diff --git a/.gitignore b/.gitignore index 90b078fc94f..40c473d13dd 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,11 @@ internal/ .idea yarn.lock .parallelperf.* +tests/cases/user/*/package-lock.json +tests/cases/user/*/node_modules/ +tests/cases/user/*/**/*.js +tests/cases/user/*/**/*.js.map +tests/cases/user/*/**/*.d.ts +!tests/cases/user/zone.js/ +!tests/cases/user/bignumber.js/ +!tests/cases/user/discord.js/ diff --git a/.travis.yml b/.travis.yml index d24e155b580..06e912c55f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,8 @@ language: node_js node_js: - 'stable' + - '8' - '6' - - '4' sudo: false diff --git a/Gulpfile.ts b/Gulpfile.ts index 5a27eb52b32..aedde5c33d9 100644 --- a/Gulpfile.ts +++ b/Gulpfile.ts @@ -46,14 +46,15 @@ const cmdLineOptions = minimist(process.argv.slice(2), { boolean: ["debug", "inspect", "light", "colors", "lint", "soft"], string: ["browser", "tests", "host", "reporter", "stackTraceLimit", "timeout"], alias: { - b: "browser", - d: "debug", "debug-brk": "debug", - i: "inspect", "inspect-brk": "inspect", - t: "tests", test: "tests", - r: "reporter", - c: "colors", color: "colors", - f: "files", file: "files", - w: "workers", + "b": "browser", + "d": "debug", "debug-brk": "debug", + "i": "inspect", "inspect-brk": "inspect", + "t": "tests", "test": "tests", + "ru": "runners", "runner": "runners", + "r": "reporter", + "c": "colors", "color": "colors", + "f": "files", "file": "files", + "w": "workers", }, default: { soft: false, @@ -64,6 +65,7 @@ const cmdLineOptions = minimist(process.argv.slice(2), { browser: process.env.browser || process.env.b || "IE", timeout: process.env.timeout || 40000, tests: process.env.test || process.env.tests || process.env.t, + runners: process.env.runners || process.env.runner || process.env.ru, light: process.env.light === undefined || process.env.light !== "false", reporter: process.env.reporter || process.env.r, lint: process.env.lint || true, @@ -72,7 +74,8 @@ const cmdLineOptions = minimist(process.argv.slice(2), { } }); -function exec(cmd: string, args: string[], complete: () => void = (() => { }), error: (e: any, status: number) => void = (() => { })) { +const noop = () => {}; // tslint:disable-line no-empty +function exec(cmd: string, args: string[], complete: () => void = noop, error: (e: any, status: number) => void = noop) { console.log(`${cmd} ${args.join(" ")}`); // TODO (weswig): Update child_process types to add windowsVerbatimArguments to the type definition const subshellFlag = isWin ? "/c" : "-c"; @@ -99,12 +102,12 @@ const lclDirectory = "src/loc/lcl"; const builtDirectory = "built/"; const builtLocalDirectory = "built/local/"; -const LKGDirectory = "lib/"; +const lkgDirectory = "lib/"; const copyright = "CopyrightNotice.txt"; const compilerFilename = "tsc.js"; -const LKGCompiler = path.join(LKGDirectory, compilerFilename); +const lkgCompiler = path.join(lkgDirectory, compilerFilename); const builtLocalCompiler = path.join(builtLocalDirectory, compilerFilename); const nodeModulesPathPrefix = path.resolve("./node_modules/.bin/"); @@ -123,34 +126,31 @@ const es2015LibrarySources = [ "es2015.symbol.wellknown.d.ts" ]; -const es2015LibrarySourceMap = es2015LibrarySources.map(function(source) { - return { target: "lib." + source, sources: ["header.d.ts", source] }; -}); +const es2015LibrarySourceMap = es2015LibrarySources.map(source => + ({ target: "lib." + source, sources: ["header.d.ts", source] })); const es2016LibrarySource = ["es2016.array.include.d.ts"]; -const es2016LibrarySourceMap = es2016LibrarySource.map(function(source) { - return { target: "lib." + source, sources: ["header.d.ts", source] }; -}); +const es2016LibrarySourceMap = es2016LibrarySource.map(source => + ({ target: "lib." + source, sources: ["header.d.ts", source] })); const es2017LibrarySource = [ "es2017.object.d.ts", "es2017.sharedmemory.d.ts", "es2017.string.d.ts", "es2017.intl.d.ts", + "es2017.typedarrays.d.ts", ]; -const es2017LibrarySourceMap = es2017LibrarySource.map(function(source) { - return { target: "lib." + source, sources: ["header.d.ts", source] }; -}); +const es2017LibrarySourceMap = es2017LibrarySource.map(source => + ({ target: "lib." + source, sources: ["header.d.ts", source] })); const esnextLibrarySource = [ "esnext.asynciterable.d.ts" ]; -const esnextLibrarySourceMap = esnextLibrarySource.map(function (source) { - return { target: "lib." + source, sources: ["header.d.ts", source] }; -}); +const esnextLibrarySourceMap = esnextLibrarySource.map(source => + ({ target: "lib." + source, sources: ["header.d.ts", source] })); const hostsLibrarySources = ["dom.generated.d.ts", "webworker.importscripts.d.ts", "scripthost.d.ts"]; @@ -171,14 +171,13 @@ const librarySourceMap = [ // JavaScript + all host library { target: "lib.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(hostsLibrarySources) }, { target: "lib.es6.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(es2015LibrarySources, hostsLibrarySources, "dom.iterable.d.ts") }, - { target: "lib.es2016.full.d.ts", sources: ["header.d.ts", "es2016.d.ts"].concat(es2015LibrarySources, hostsLibrarySources, "dom.iterable.d.ts") }, - { target: "lib.es2017.full.d.ts", sources: ["header.d.ts", "es2017.d.ts"].concat(es2015LibrarySources, hostsLibrarySources, "dom.iterable.d.ts") }, - { target: "lib.esnext.full.d.ts", sources: ["header.d.ts", "esnext.d.ts"].concat(es2015LibrarySources, hostsLibrarySources, "dom.iterable.d.ts") }, + { target: "lib.es2016.full.d.ts", sources: ["header.d.ts", "es2016.d.ts"].concat(hostsLibrarySources, "dom.iterable.d.ts") }, + { target: "lib.es2017.full.d.ts", sources: ["header.d.ts", "es2017.d.ts"].concat(hostsLibrarySources, "dom.iterable.d.ts") }, + { target: "lib.esnext.full.d.ts", sources: ["header.d.ts", "esnext.d.ts"].concat(hostsLibrarySources, "dom.iterable.d.ts") }, ].concat(es2015LibrarySourceMap, es2016LibrarySourceMap, es2017LibrarySourceMap, esnextLibrarySourceMap); -const libraryTargets = librarySourceMap.map(function(f) { - return path.join(builtLocalDirectory, f.target); -}); +const libraryTargets = librarySourceMap.map(f => + path.join(builtLocalDirectory, f.target)); /** * .lcg file is what localization team uses to know what messages to localize. @@ -193,22 +192,19 @@ const generatedLCGFile = path.join(builtLocalDirectory, "enu", "diagnosticMessag * 2. 'src\compiler\diagnosticMessages.generated.json' => 'built\local\ENU\diagnosticMessages.generated.json.lcg' * generate the lcg file (source of messages to localize) from the diagnosticMessages.generated.json */ -const localizationTargets = ["cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt-BR", "ru", "tr", "zh-CN", "zh-TW"].map(function (f) { - return path.join(builtLocalDirectory, f, "diagnosticMessages.generated.json"); -}).concat(generatedLCGFile); +const localizationTargets = ["cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt-BR", "ru", "tr", "zh-CN", "zh-TW"] + .map(f => path.join(builtLocalDirectory, f, "diagnosticMessages.generated.json")) + .concat(generatedLCGFile); for (const i in libraryTargets) { const entry = librarySourceMap[i]; const target = libraryTargets[i]; - const sources = [copyright].concat(entry.sources.map(function(s) { - return path.join(libraryDirectory, s); - })); - gulp.task(target, /*help*/ false, [], function() { - return gulp.src(sources) + const sources = [copyright].concat(entry.sources.map(s => path.join(libraryDirectory, s))); + gulp.task(target, /*help*/ false, [], () => + gulp.src(sources) .pipe(newer(target)) .pipe(concat(target, { newLine: "\n\n" })) - .pipe(gulp.dest(".")); - }); + .pipe(gulp.dest("."))); } const configureNightlyJs = path.join(scriptsDirectory, "configureNightly.js"); @@ -575,9 +571,7 @@ gulp.task(specMd, /*help*/ false, [word2mdJs], (done) => { const specMDFullPath = path.resolve(specMd); const cmd = "cscript //nologo " + word2mdJs + " \"" + specWordFullPath + "\" " + "\"" + specMDFullPath + "\""; console.log(cmd); - cp.exec(cmd, function() { - done(); - }); + cp.exec(cmd, done); }); gulp.task("generate-spec", "Generates a Markdown version of the Language Specification", [specMd]); @@ -599,7 +593,7 @@ gulp.task("VerifyLKG", /*help*/ false, [], () => { ". The following files are missing:\n" + missingFiles.join("\n")); } // Copy all the targets into the LKG directory - return gulp.src([...expectedFiles, path.join(builtLocalDirectory, "**"), `!${path.join(builtLocalDirectory, "tslint")}`, `!${path.join(builtLocalDirectory, "*.*")}`]).pipe(gulp.dest(LKGDirectory)); + return gulp.src([...expectedFiles, path.join(builtLocalDirectory, "**"), `!${path.join(builtLocalDirectory, "tslint")}`, `!${path.join(builtLocalDirectory, "*.*")}`]).pipe(gulp.dest(lkgDirectory)); }); gulp.task("LKGInternal", /*help*/ false, ["lib", "local"]); @@ -658,6 +652,7 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done: const debug = cmdLineOptions.debug; const inspect = cmdLineOptions.inspect; const tests = cmdLineOptions.tests; + const runners = cmdLineOptions.runners; const light = cmdLineOptions.light; const stackTraceLimit = cmdLineOptions.stackTraceLimit; const testConfigFile = "test.config"; @@ -678,8 +673,8 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done: workerCount = cmdLineOptions.workers; } - if (tests || light || taskConfigsFolder) { - writeTestConfigFile(tests, light, taskConfigsFolder, workerCount, stackTraceLimit); + if (tests || runners || light || taskConfigsFolder) { + writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit); } if (tests && tests.toLocaleLowerCase() === "rwc") { @@ -714,17 +709,13 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done: } args.push(run); setNodeEnvToDevelopment(); - exec(mocha, args, lintThenFinish, function(e, status) { - finish(e, status); - }); + exec(mocha, args, lintThenFinish, finish); } else { // run task to load all tests and partition them between workers setNodeEnvToDevelopment(); - exec(host, [run], lintThenFinish, function(e, status) { - finish(e, status); - }); + exec(host, [run], lintThenFinish, finish); } }); @@ -874,8 +865,8 @@ function cleanTestDirs(done: (e?: any) => void) { } // used to pass data from jake command line directly to run.js -function writeTestConfigFile(tests: string, light: boolean, taskConfigsFolder?: string, workerCount?: number, stackTraceLimit?: string) { - const testConfigContents = JSON.stringify({ test: tests ? [tests] : undefined, light, workerCount, stackTraceLimit, taskConfigsFolder, noColor: !cmdLineOptions.colors }); +function writeTestConfigFile(tests: string, runners: string, light: boolean, taskConfigsFolder?: string, workerCount?: number, stackTraceLimit?: string) { + const testConfigContents = JSON.stringify({ test: tests ? [tests] : undefined, runner: runners ? runners.split(",") : undefined, light, workerCount, stackTraceLimit, taskConfigsFolder, noColor: !cmdLineOptions.colors }); console.log("Running tests with config: " + testConfigContents); fs.writeFileSync("test.config", testConfigContents); } @@ -886,13 +877,14 @@ gulp.task("runtests-browser", "Runs the tests using the built run.js file like ' if (err) { console.error(err); done(err); process.exit(1); } host = "node"; const tests = cmdLineOptions.tests; + const runners = cmdLineOptions.runners; const light = cmdLineOptions.light; const testConfigFile = "test.config"; if (fs.existsSync(testConfigFile)) { fs.unlinkSync(testConfigFile); } - if (tests || light) { - writeTestConfigFile(tests, light); + if (tests || runners || light) { + writeTestConfigFile(tests, runners, light); } const args = [nodeServerOutFile]; @@ -1006,7 +998,7 @@ gulp.task(loggedIOJsPath, /*help*/ false, [], (done) => { const temp = path.join(builtLocalDirectory, "temp"); mkdirP(temp, (err) => { if (err) { console.error(err); done(err); process.exit(1); } - exec(host, [LKGCompiler, "--types", "--target es5", "--lib es5", "--outdir", temp, loggedIOpath], () => { + exec(host, [lkgCompiler, "--types", "--target es5", "--lib es5", "--outdir", temp, loggedIOpath], () => { fs.renameSync(path.join(temp, "/harness/loggedIO.js"), loggedIOJsPath); del(temp).then(() => done(), done); }, done); @@ -1043,7 +1035,7 @@ gulp.task("update-sublime", "Updates the sublime plugin's tsserver", ["local", s }); gulp.task("build-rules", "Compiles tslint rules to js", () => { - const settings: tsc.Settings = getCompilerSettings({ module: "commonjs", "lib": ["es6"] }, /*useBuiltCompiler*/ false); + const settings: tsc.Settings = getCompilerSettings({ module: "commonjs", lib: ["es6"] }, /*useBuiltCompiler*/ false); const dest = path.join(builtLocalDirectory, "tslint"); return gulp.src("scripts/tslint/**/*.ts") .pipe(newer({ @@ -1082,7 +1074,7 @@ function sendNextFile(files: {path: string}[], child: cp.ChildProcess, callback: function spawnLintWorker(files: {path: string}[], callback: (failures: number) => void) { const child = cp.fork("./scripts/parallel-lint"); let failures = 0; - child.on("message", function(data) { + child.on("message", data => { switch (data.kind) { case "result": if (data.failures > 0) { @@ -1106,7 +1098,7 @@ gulp.task("lint", "Runs tslint on the compiler sources. Optional arguments are: const fileMatcher = cmdLineOptions.files; const files = fileMatcher ? `src/**/${fileMatcher}` - : "Gulpfile.ts 'scripts/generateLocalizedDiagnosticMessages.ts' 'scripts/tslint/**/*.ts' 'src/**/*.ts' --exclude src/lib/es5.d.ts --exclude 'src/lib/*.generated.d.ts'"; + : "Gulpfile.ts 'scripts/generateLocalizedDiagnosticMessages.ts' 'scripts/tslint/**/*.ts' 'src/**/*.ts' --exclude 'src/lib/*.d.ts'"; const cmd = `node node_modules/tslint/bin/tslint ${files} --formatters-dir ./built/local/tslint/formatters --format autolinkableStylish`; console.log("Linting: " + cmd); child_process.execSync(cmd, { stdio: [0, 1, 2] }); diff --git a/Jakefile.js b/Jakefile.js index da7d96f0699..c2d0717641f 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -105,6 +105,7 @@ var harnessCoreSources = [ "projectsRunner.ts", "loggedIO.ts", "rwcRunner.ts", + "externalCompileRunner.ts", "test262Runner.ts", "./parallel/shared.ts", "./parallel/host.ts", @@ -196,7 +197,8 @@ var es2017LibrarySource = [ "es2017.object.d.ts", "es2017.sharedmemory.d.ts", "es2017.string.d.ts", - "es2017.intl.d.ts" + "es2017.intl.d.ts", + "es2017.typedarrays.d.ts", ]; var es2017LibrarySourceMap = es2017LibrarySource.map(function (source) { @@ -843,8 +845,9 @@ function cleanTestDirs() { } // used to pass data from jake command line directly to run.js -function writeTestConfigFile(tests, light, taskConfigsFolder, workerCount, stackTraceLimit, colors) { +function writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, colors) { var testConfigContents = JSON.stringify({ + runners: runners ? runners.split(",") : undefined, test: tests ? [tests] : undefined, light: light, workerCount: workerCount, @@ -870,6 +873,7 @@ function runConsoleTests(defaultReporter, runInParallel) { var debug = process.env.debug || process.env["debug-brk"] || process.env.d; var inspect = process.env.inspect || process.env["inspect-brk"] || process.env.i; var testTimeout = process.env.timeout || defaultTestTimeout; + var runners = process.env.runners || process.env.runner || process.env.ru; var tests = process.env.test || process.env.tests || process.env.t; var light = process.env.light === undefined || process.env.light !== "false"; var stackTraceLimit = process.env.stackTraceLimit; @@ -891,8 +895,8 @@ function runConsoleTests(defaultReporter, runInParallel) { workerCount = process.env.workerCount || process.env.p || os.cpus().length; } - if (tests || light || taskConfigsFolder) { - writeTestConfigFile(tests, light, taskConfigsFolder, workerCount, stackTraceLimit, colors); + if (tests || runners || light || taskConfigsFolder) { + writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, colors); } if (tests && tests.toLocaleLowerCase() === "rwc") { @@ -1027,14 +1031,15 @@ task("runtests-browser", ["browserify", nodeServerOutFile], function () { cleanTestDirs(); host = "node"; var browser = process.env.browser || process.env.b || (os.platform() === "linux" ? "chrome" : "IE"); + var runners = process.env.runners || process.env.runner || process.env.ru; var tests = process.env.test || process.env.tests || process.env.t; var light = process.env.light || false; var testConfigFile = 'test.config'; if (fs.existsSync(testConfigFile)) { fs.unlinkSync(testConfigFile); } - if (tests || light) { - writeTestConfigFile(tests, light); + if (tests || runners || light) { + writeTestConfigFile(tests, runners, light); } tests = tests ? tests : ''; @@ -1282,7 +1287,7 @@ task("lint", ["build-rules"], () => { const fileMatcher = process.env.f || process.env.file || process.env.files; const files = fileMatcher ? `src/**/${fileMatcher}` - : "Gulpfile.ts 'scripts/generateLocalizedDiagnosticMessages.ts' 'scripts/tslint/**/*.ts' 'src/**/*.ts' --exclude src/lib/es5.d.ts --exclude 'src/lib/*.generated.d.ts'"; + : "Gulpfile.ts 'scripts/generateLocalizedDiagnosticMessages.ts' 'scripts/tslint/**/*.ts' 'src/**/*.ts' --exclude 'src/lib/*.d.ts'"; const cmd = `node node_modules/tslint/bin/tslint ${files} --formatters-dir ./built/local/tslint/formatters --format autolinkableStylish`; console.log("Linting: " + cmd); jake.exec([cmd], { interactive: true }, () => { diff --git a/netci.groovy b/netci.groovy index fc6d00e4e7f..5fa8b02baf2 100644 --- a/netci.groovy +++ b/netci.groovy @@ -5,7 +5,7 @@ import jobs.generation.Utilities; def project = GithubProject def branch = GithubBranchName -def nodeVersions = ['stable', '6', '4'] +def nodeVersions = ['stable', '8', '6'] nodeVersions.each { nodeVer -> diff --git a/package.json b/package.json index e76d480937c..e329db05d85 100644 --- a/package.json +++ b/package.json @@ -74,10 +74,12 @@ "q": "latest", "run-sequence": "latest", "sorcery": "latest", + "source-map-support": "latest", "through2": "latest", "travis-fold": "latest", "ts-node": "latest", "tslint": "latest", + "vinyl": "latest", "colors": "latest", "typescript": "next" }, diff --git a/scripts/generateLocalizedDiagnosticMessages.ts b/scripts/generateLocalizedDiagnosticMessages.ts index 36df92590c7..566eb557fd5 100644 --- a/scripts/generateLocalizedDiagnosticMessages.ts +++ b/scripts/generateLocalizedDiagnosticMessages.ts @@ -65,10 +65,11 @@ function main(): void { * There are three exceptions, zh-CN, zh-TW and pt-BR. */ function getPreferedLocaleName(localeName: string) { + localeName = localeName.toLowerCase(); switch (localeName) { - case "zh-CN": - case "zh-TW": - case "pt-BR": + case "zh-cn": + case "zh-tw": + case "pt-br": return localeName; default: return localeName.split("-")[0]; @@ -86,9 +87,9 @@ function main(): void { const out: any = {}; for (const item of o.LCX.Item[0].Item[0].Item) { let ItemId = item.$.ItemId; - let Val = item.Str[0].Tgt ? item.Str[0].Tgt[0].Val[0] : item.Str[0].Val[0]; + let val = item.Str[0].Tgt ? item.Str[0].Tgt[0].Val[0] : item.Str[0].Val[0]; - if (typeof ItemId !== "string" || typeof Val !== "string") { + if (typeof ItemId !== "string" || typeof val !== "string") { console.error("Unexpected XML file structure"); process.exit(1); } @@ -97,8 +98,8 @@ function main(): void { ItemId = ItemId.slice(1); // remove leading semicolon } - Val = Val.replace(/]5D;/, "]"); // unescape `]` - out[ItemId] = Val; + val = val.replace(/]5D;/, "]"); // unescape `]` + out[ItemId] = val; } return JSON.stringify(out, undefined, 2); } diff --git a/scripts/ior.ts b/scripts/ior.ts index 91580203350..374747d8439 100644 --- a/scripts/ior.ts +++ b/scripts/ior.ts @@ -64,7 +64,6 @@ module Commands { } if (path.charAt(1) === ":") { if (path.charAt(2) === directorySeparator) return 3; - return 2; } return 0; } diff --git a/scripts/processDiagnosticMessages.ts b/scripts/processDiagnosticMessages.ts index ff4047d310d..dd66564b134 100644 --- a/scripts/processDiagnosticMessages.ts +++ b/scripts/processDiagnosticMessages.ts @@ -1,4 +1,5 @@ /// +/// interface DiagnosticDetails { category: string; @@ -9,80 +10,79 @@ interface DiagnosticDetails { type InputDiagnosticMessageTable = ts.Map; function main(): void { - var sys = ts.sys; + const sys = ts.sys; if (sys.args.length < 1) { - sys.write("Usage:" + sys.newLine) + sys.write("Usage:" + sys.newLine); sys.write("\tnode processDiagnosticMessages.js " + sys.newLine); return; } function writeFile(fileName: string, contents: string) { - // TODO: Fix path joining - var inputDirectory = inputFilePath.substr(0,inputFilePath.lastIndexOf("/")); - var fileOutputPath = inputDirectory + "/" + fileName; + const inputDirectory = ts.getDirectoryPath(inputFilePath); + const fileOutputPath = ts.combinePaths(inputDirectory, fileName); sys.writeFile(fileOutputPath, contents); } - var inputFilePath = sys.args[0].replace(/\\/g, "/"); - var inputStr = sys.readFile(inputFilePath); + const inputFilePath = sys.args[0].replace(/\\/g, "/"); + const inputStr = sys.readFile(inputFilePath); - var diagnosticMessagesJson: { [key: string]: DiagnosticDetails } = JSON.parse(inputStr); - // Check that there are no duplicates. - const seenNames = ts.createMap(); - for (const name of Object.keys(diagnosticMessagesJson)) { - if (seenNames.has(name)) - throw new Error(`Name ${name} appears twice`); - seenNames.set(name, true); - } + const diagnosticMessagesJson: { [key: string]: DiagnosticDetails } = JSON.parse(inputStr); const diagnosticMessages: InputDiagnosticMessageTable = ts.createMapFromTemplate(diagnosticMessagesJson); - var infoFileOutput = buildInfoFileOutput(diagnosticMessages); + const outputFilesDir = ts.getDirectoryPath(inputFilePath); + const thisFilePathRel = ts.getRelativePathToDirectoryOrUrl(outputFilesDir, sys.getExecutingFilePath(), + sys.getCurrentDirectory(), ts.createGetCanonicalFileName(sys.useCaseSensitiveFileNames), /* isAbsolutePathAnUrl */ false); + + const infoFileOutput = buildInfoFileOutput(diagnosticMessages, "./diagnosticInformationMap.generated.ts", thisFilePathRel); checkForUniqueCodes(diagnosticMessages); writeFile("diagnosticInformationMap.generated.ts", infoFileOutput); - var messageOutput = buildDiagnosticMessageOutput(diagnosticMessages); + const messageOutput = buildDiagnosticMessageOutput(diagnosticMessages); writeFile("diagnosticMessages.generated.json", messageOutput); } function checkForUniqueCodes(diagnosticTable: InputDiagnosticMessageTable) { const allCodes: { [key: number]: true | undefined } = []; diagnosticTable.forEach(({ code }) => { - if (allCodes[code]) + if (allCodes[code]) { throw new Error(`Diagnostic code ${code} appears more than once.`); + } allCodes[code] = true; }); } -function buildInfoFileOutput(messageTable: InputDiagnosticMessageTable): string { - var result = - '// \r\n' + - '/// \r\n' + - '/* @internal */\r\n' + - 'namespace ts {\r\n' + +function buildInfoFileOutput(messageTable: InputDiagnosticMessageTable, inputFilePathRel: string, thisFilePathRel: string): string { + let result = + "// \r\n" + + "// generated from '" + inputFilePathRel + "' by '" + thisFilePathRel + "'\r\n" + + "/// \r\n" + + "/* @internal */\r\n" + + "namespace ts {\r\n" + " function diag(code: number, category: DiagnosticCategory, key: string, message: string): DiagnosticMessage {\r\n" + " return { code, category, key, message };\r\n" + " }\r\n" + - ' export const Diagnostics = {\r\n'; + " // tslint:disable-next-line variable-name\r\n" + + " export const Diagnostics = {\r\n"; messageTable.forEach(({ code, category }, name) => { const propName = convertPropertyName(name); result += ` ${propName}: diag(${code}, DiagnosticCategory.${category}, "${createKey(propName, code)}", ${JSON.stringify(name)}),\r\n`; }); - result += ' };\r\n}'; + result += " };\r\n}"; return result; } function buildDiagnosticMessageOutput(messageTable: InputDiagnosticMessageTable): string { - let result = '{'; + let result = "{"; messageTable.forEach(({ code }, name) => { const propName = convertPropertyName(name); result += `\r\n "${createKey(propName, code)}" : "${name.replace(/[\"]/g, '\\"')}",`; }); // Shave trailing comma, then add newline and ending brace - result = result.slice(0, result.length - 1) + '\r\n}'; + result = result.slice(0, result.length - 1) + "\r\n}"; // Assert that we generated valid JSON JSON.parse(result); @@ -90,15 +90,15 @@ function buildDiagnosticMessageOutput(messageTable: InputDiagnosticMessageTable) return result; } -function createKey(name: string, code: number) : string { - return name.slice(0, 100) + '_' + code; +function createKey(name: string, code: number): string { + return name.slice(0, 100) + "_" + code; } function convertPropertyName(origName: string): string { - var result = origName.split("").map(char => { - if (char === '*') { return "_Asterisk"; } - if (char === '/') { return "_Slash"; } - if (char === ':') { return "_Colon"; } + let result = origName.split("").map(char => { + if (char === "*") { return "_Asterisk"; } + if (char === "/") { return "_Slash"; } + if (char === ":") { return "_Colon"; } return /\w/.test(char) ? char : "_"; }).join(""); @@ -106,7 +106,7 @@ function convertPropertyName(origName: string): string { result = result.replace(/_+/g, "_"); // remove any leading underscore, unless it is followed by a number. - result = result.replace(/^_([^\d])/, "$1") + result = result.replace(/^_([^\d])/, "$1"); // get rid of all trailing underscores. result = result.replace(/_$/, ""); diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 35a62a644d8..4e89abde780 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -133,7 +133,7 @@ namespace ts { let symbolCount = 0; - let Symbol: { new (flags: SymbolFlags, name: __String): Symbol }; + let Symbol: { new (flags: SymbolFlags, name: __String): Symbol }; // tslint:disable-line variable-name let classifiableNames: UnderscoreEscapedMap; const unreachableFlow: FlowNode = { flags: FlowFlags.Unreachable }; @@ -192,7 +192,7 @@ namespace ts { return bindSourceFile; function bindInStrictMode(file: SourceFile, opts: CompilerOptions): boolean { - if ((opts.alwaysStrict === undefined ? opts.strict : opts.alwaysStrict) && !file.isDeclarationFile) { + if (getStrictOptionValue(opts, "alwaysStrict") && !file.isDeclarationFile) { // bind in strict mode source files with alwaysStrict option return true; } @@ -1550,7 +1550,7 @@ namespace ts { function setExportContextFlag(node: ModuleDeclaration | SourceFile) { // A declaration source file or ambient module declaration that contains no export declarations (but possibly regular // declarations with export modifiers) is an export context in which declarations are implicitly exported. - if (isInAmbientContext(node) && !hasExportDeclarations(node)) { + if (node.flags & NodeFlags.Ambient && !hasExportDeclarations(node)) { node.flags |= NodeFlags.ExportContext; } else { @@ -1726,7 +1726,7 @@ namespace ts { node.originalKeywordKind >= SyntaxKind.FirstFutureReservedWord && node.originalKeywordKind <= SyntaxKind.LastFutureReservedWord && !isIdentifierName(node) && - !isInAmbientContext(node)) { + !(node.flags & NodeFlags.Ambient)) { // Report error only if there are no parse errors in file if (!file.parseDiagnostics.length) { @@ -2205,15 +2205,14 @@ namespace ts { bindAnonymousDeclaration(node, SymbolFlags.Alias, getDeclarationName(node)); } else { - // An export default clause with an expression exports a value - // We want to exclude both class and function here, this is necessary to issue an error when there are both - // default export-assignment and default export function and class declaration. - const flags = node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(node) + const flags = node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(node) // An export default clause with an EntityNameExpression exports all meanings of that identifier ? SymbolFlags.Alias // An export default clause with any other expression exports a value : SymbolFlags.Property; - declareSymbol(container.symbol.exports, container.symbol, node, flags, SymbolFlags.Property | SymbolFlags.AliasExcludes | SymbolFlags.Class | SymbolFlags.Function); + // If there is an `export default x;` alias declaration, can't `export default` anything else. + // (In contrast, you can still have `export default function f() {}` and `export default interface I {}`.) + declareSymbol(container.symbol.exports, container.symbol, node, flags, SymbolFlags.All); } } @@ -2481,7 +2480,7 @@ namespace ts { } function bindParameter(node: ParameterDeclaration) { - if (inStrictMode && !isInAmbientContext(node)) { + if (inStrictMode && !(node.flags & NodeFlags.Ambient)) { // It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a // strict mode FunctionLikeDeclaration or FunctionExpression(13.1) checkStrictModeEvalOrArguments(node, node.name); @@ -2503,7 +2502,7 @@ namespace ts { } function bindFunctionDeclaration(node: FunctionDeclaration) { - if (!file.isDeclarationFile && !isInAmbientContext(node)) { + if (!file.isDeclarationFile && !(node.flags & NodeFlags.Ambient)) { if (isAsyncFunction(node)) { emitFlags |= NodeFlags.HasAsyncFunctions; } @@ -2520,7 +2519,7 @@ namespace ts { } function bindFunctionExpression(node: FunctionExpression) { - if (!file.isDeclarationFile && !isInAmbientContext(node)) { + if (!file.isDeclarationFile && !(node.flags & NodeFlags.Ambient)) { if (isAsyncFunction(node)) { emitFlags |= NodeFlags.HasAsyncFunctions; } @@ -2534,7 +2533,7 @@ namespace ts { } function bindPropertyOrMethodOrAccessor(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) { - if (!file.isDeclarationFile && !isInAmbientContext(node) && isAsyncFunction(node)) { + if (!file.isDeclarationFile && !(node.flags & NodeFlags.Ambient) && isAsyncFunction(node)) { emitFlags |= NodeFlags.HasAsyncFunctions; } @@ -2583,7 +2582,7 @@ namespace ts { // On the other side we do want to report errors on non-initialized 'lets' because of TDZ const reportUnreachableCode = !options.allowUnreachableCode && - !isInAmbientContext(node) && + !(node.flags & NodeFlags.Ambient) && ( node.kind !== SyntaxKind.VariableStatement || getCombinedNodeFlags((node).declarationList) & NodeFlags.BlockScoped || @@ -2963,6 +2962,7 @@ namespace ts { || hasModifier(node, ModifierFlags.TypeScriptModifier) || node.typeParameters || node.type + || (node.name && isComputedPropertyName(node.name)) // While computed method names aren't typescript, the TS transform must visit them to emit property declarations correctly || !node.body) { transformFlags |= TransformFlags.AssertTypeScript; } @@ -2993,6 +2993,7 @@ namespace ts { if (node.decorators || hasModifier(node, ModifierFlags.TypeScriptModifier) || node.type + || (node.name && isComputedPropertyName(node.name)) // While computed accessor names aren't typescript, the TS transform must visit them to emit property declarations correctly || !node.body) { transformFlags |= TransformFlags.AssertTypeScript; } @@ -3296,6 +3297,9 @@ namespace ts { case SyntaxKind.JsxOpeningElement: case SyntaxKind.JsxText: case SyntaxKind.JsxClosingElement: + case SyntaxKind.JsxFragment: + case SyntaxKind.JsxOpeningFragment: + case SyntaxKind.JsxClosingFragment: case SyntaxKind.JsxAttribute: case SyntaxKind.JsxAttributes: case SyntaxKind.JsxSpreadAttribute: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index aaaa0ed50b8..a9aaa77fa74 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -48,9 +48,11 @@ namespace ts { let requestedExternalEmitHelpers: ExternalEmitHelpers; let externalHelpersModule: Symbol; + // tslint:disable variable-name const Symbol = objectAllocator.getSymbolConstructor(); const Type = objectAllocator.getTypeConstructor(); const Signature = objectAllocator.getSignatureConstructor(); + // tslint:enable variable-name let typeCount = 0; let symbolCount = 0; @@ -64,11 +66,11 @@ namespace ts { const languageVersion = getEmitScriptTarget(compilerOptions); const modulekind = getEmitModuleKind(compilerOptions); const noUnusedIdentifiers = !!compilerOptions.noUnusedLocals || !!compilerOptions.noUnusedParameters; - const allowSyntheticDefaultImports = typeof compilerOptions.allowSyntheticDefaultImports !== "undefined" ? compilerOptions.allowSyntheticDefaultImports : modulekind === ModuleKind.System; - const strictNullChecks = compilerOptions.strictNullChecks === undefined ? compilerOptions.strict : compilerOptions.strictNullChecks; - const strictFunctionTypes = compilerOptions.strictFunctionTypes === undefined ? compilerOptions.strict : compilerOptions.strictFunctionTypes; - const noImplicitAny = compilerOptions.noImplicitAny === undefined ? compilerOptions.strict : compilerOptions.noImplicitAny; - const noImplicitThis = compilerOptions.noImplicitThis === undefined ? compilerOptions.strict : compilerOptions.noImplicitThis; + const allowSyntheticDefaultImports = getAllowSyntheticDefaultImports(compilerOptions); + const strictNullChecks = getStrictOptionValue(compilerOptions, "strictNullChecks"); + const strictFunctionTypes = getStrictOptionValue(compilerOptions, "strictFunctionTypes"); + const noImplicitAny = getStrictOptionValue(compilerOptions, "noImplicitAny"); + const noImplicitThis = getStrictOptionValue(compilerOptions, "noImplicitThis"); const emitResolver = createResolver(); const nodeBuilder = createNodeBuilder(); @@ -260,6 +262,7 @@ namespace ts { const literalTypes = createMap(); const indexedAccessTypes = createMap(); const evolvingArrayTypes: EvolvingArrayType[] = []; + const undefinedProperties = createMap() as UnderscoreEscapedMap; const unknownSymbol = createSymbol(SymbolFlags.Property, "unknown" as __String); const resolvingSymbol = createSymbol(0, InternalSymbolName.Resolving); @@ -280,6 +283,7 @@ namespace ts { const voidType = createIntrinsicType(TypeFlags.Void, "void"); const neverType = createIntrinsicType(TypeFlags.Never, "never"); const silentNeverType = createIntrinsicType(TypeFlags.Never, "never"); + const implicitNeverType = createIntrinsicType(TypeFlags.Never, "never"); const nonPrimitiveType = createIntrinsicType(TypeFlags.NonPrimitive, "object"); const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); @@ -451,29 +455,29 @@ namespace ts { } const typeofEQFacts = createMapFromTemplate({ - "string": TypeFacts.TypeofEQString, - "number": TypeFacts.TypeofEQNumber, - "boolean": TypeFacts.TypeofEQBoolean, - "symbol": TypeFacts.TypeofEQSymbol, - "undefined": TypeFacts.EQUndefined, - "object": TypeFacts.TypeofEQObject, - "function": TypeFacts.TypeofEQFunction + string: TypeFacts.TypeofEQString, + number: TypeFacts.TypeofEQNumber, + boolean: TypeFacts.TypeofEQBoolean, + symbol: TypeFacts.TypeofEQSymbol, + undefined: TypeFacts.EQUndefined, + object: TypeFacts.TypeofEQObject, + function: TypeFacts.TypeofEQFunction }); const typeofNEFacts = createMapFromTemplate({ - "string": TypeFacts.TypeofNEString, - "number": TypeFacts.TypeofNENumber, - "boolean": TypeFacts.TypeofNEBoolean, - "symbol": TypeFacts.TypeofNESymbol, - "undefined": TypeFacts.NEUndefined, - "object": TypeFacts.TypeofNEObject, - "function": TypeFacts.TypeofNEFunction + string: TypeFacts.TypeofNEString, + number: TypeFacts.TypeofNENumber, + boolean: TypeFacts.TypeofNEBoolean, + symbol: TypeFacts.TypeofNESymbol, + undefined: TypeFacts.NEUndefined, + object: TypeFacts.TypeofNEObject, + function: TypeFacts.TypeofNEFunction }); const typeofTypesByName = createMapFromTemplate({ - "string": stringType, - "number": numberType, - "boolean": booleanType, - "symbol": esSymbolType, - "undefined": undefinedType + string: stringType, + number: numberType, + boolean: booleanType, + symbol: esSymbolType, + undefined: undefinedType }); const typeofType = createTypeofType(); @@ -487,17 +491,6 @@ namespace ts { /** Things we lazy load from the JSX namespace */ const jsxTypes = createUnderscoreEscapedMap(); - const JsxNames = { - JSX: "JSX" as __String, - IntrinsicElements: "IntrinsicElements" as __String, - ElementClass: "ElementClass" as __String, - ElementAttributesPropertyNameContainer: "ElementAttributesProperty" as __String, - ElementChildrenAttributeNameContainer: "ElementChildrenAttribute" as __String, - Element: "Element" as __String, - IntrinsicAttributes: "IntrinsicAttributes" as __String, - IntrinsicClassAttributes: "IntrinsicClassAttributes" as __String - }; - const subtypeRelation = createMap(); const assignableRelation = createMap(); const comparableRelation = createMap(); @@ -528,6 +521,11 @@ namespace ts { Strict, } + const enum MappedTypeModifiers { + Readonly = 1 << 0, + Optional = 1 << 1, + } + const builtinGlobals = createSymbolTable(); builtinGlobals.set(undefinedSymbol.escapedName, undefinedSymbol); @@ -690,7 +688,7 @@ namespace ts { else { // find a module that about to be augmented // do not validate names of augmentations that are defined in ambient context - const moduleNotFoundError = !isInAmbientContext(moduleName.parent.parent) + 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); @@ -795,7 +793,7 @@ namespace ts { if ((modulekind && (declarationFile.externalModuleIndicator || useFile.externalModuleIndicator)) || (!compilerOptions.outFile && !compilerOptions.out) || isInTypeQuery(usage) || - isInAmbientContext(declaration)) { + declaration.flags & NodeFlags.Ambient) { // nodes are in different files and order cannot be determined return true; } @@ -1367,7 +1365,7 @@ namespace ts { } } else if (meaning & (SymbolFlags.Type & ~SymbolFlags.NamespaceModule & ~SymbolFlags.Value)) { - const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.NamespaceModule & ~SymbolFlags.Type, /*nameNotFoundMessage*/undefined, /*nameArg*/ undefined, /*isUse*/ false)); + const symbol = resolveSymbol(resolveName(errorLocation, name, (SymbolFlags.ValueModule | SymbolFlags.NamespaceModule) & ~SymbolFlags.Type, /*nameNotFoundMessage*/undefined, /*nameArg*/ undefined, /*isUse*/ false)); if (symbol) { error(errorLocation, Diagnostics.Cannot_use_namespace_0_as_a_type, unescapeLeadingUnderscores(name)); return true; @@ -1383,7 +1381,7 @@ namespace ts { Debug.assert(declaration !== undefined, "Declaration to checkResolvedBlockScopedVariable is undefined"); - if (!isInAmbientContext(declaration) && !isBlockScopedNameDeclaredBeforeUse(declaration, errorLocation)) { + if (!(declaration.flags & NodeFlags.Ambient) && !isBlockScopedNameDeclaredBeforeUse(declaration, errorLocation)) { if (result.flags & SymbolFlags.BlockScopedVariable) { error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, declarationNameToString(getNameOfDeclaration(declaration))); } @@ -1906,8 +1904,9 @@ 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, lookupTable?: ExportCollisionTrackerTable, exportNode?: ExportDeclaration) { - source && source.forEach((sourceSymbol, id) => { + function extendExportSymbols(target: SymbolTable, source: SymbolTable | undefined, lookupTable?: ExportCollisionTrackerTable, exportNode?: ExportDeclaration) { + if (!source) return; + source.forEach((sourceSymbol, id) => { if (id === "default") return; const targetSymbol = target.get(id); @@ -2162,7 +2161,6 @@ namespace ts { return forEachEntry(symbols, symbolFromSymbolTable => { if (symbolFromSymbolTable.flags & SymbolFlags.Alias && symbolFromSymbolTable.escapedName !== "export=" - && !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier) && !(isUMDExportSymbol(symbolFromSymbolTable) && enclosingDeclaration && isExternalModule(getSourceFileOfNode(enclosingDeclaration))) // If `!useOnlyExternalAliasing`, we can use any type of alias to get the name && (!useOnlyExternalAliasing || some(symbolFromSymbolTable.declarations, isExternalModuleImportEqualsDeclaration))) { @@ -2443,18 +2441,21 @@ namespace ts { function createNodeBuilder() { return { typeToTypeNode: (type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => { + Debug.assert(enclosingDeclaration === undefined || (enclosingDeclaration.flags & NodeFlags.Synthesized) === 0); const context = createNodeBuilderContext(enclosingDeclaration, flags); const resultingNode = typeToTypeNodeHelper(type, context); const result = context.encounteredError ? undefined : resultingNode; return result; }, indexInfoToIndexSignatureDeclaration: (indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => { + Debug.assert(enclosingDeclaration === undefined || (enclosingDeclaration.flags & NodeFlags.Synthesized) === 0); const context = createNodeBuilderContext(enclosingDeclaration, flags); const resultingNode = indexInfoToIndexSignatureDeclarationHelper(indexInfo, kind, context); const result = context.encounteredError ? undefined : resultingNode; return result; }, signatureToSignatureDeclaration: (signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => { + Debug.assert(enclosingDeclaration === undefined || (enclosingDeclaration.flags & NodeFlags.Synthesized) === 0); const context = createNodeBuilderContext(enclosingDeclaration, flags); const resultingNode = signatureToSignatureDeclarationHelper(signature, kind, context); const result = context.encounteredError ? undefined : resultingNode; @@ -2495,7 +2496,7 @@ namespace ts { if (type.flags & TypeFlags.EnumLiteral && !(type.flags & TypeFlags.Union)) { const parentSymbol = getParentOfSymbol(type.symbol); const parentName = symbolToName(parentSymbol, context, SymbolFlags.Type, /*expectsIdentifier*/ false); - const enumLiteralName = getDeclaredTypeOfSymbol(parentSymbol) === type ? parentName : createQualifiedName(parentName, getNameOfSymbol(type.symbol, context)); + const enumLiteralName = getDeclaredTypeOfSymbol(parentSymbol) === type ? parentName : createQualifiedName(parentName, symbolName(type.symbol)); return createTypeReferenceNode(enumLiteralName, /*typeArguments*/ undefined); } if (type.flags & TypeFlags.EnumLike) { @@ -2850,8 +2851,7 @@ namespace ts { function mapToTypeNodes(types: Type[], context: NodeBuilderContext): TypeNode[] { if (some(types)) { const result = []; - for (let i = 0; i < types.length; ++i) { - const type = types[i]; + for (const type of types) { const typeNode = typeToTypeNodeHelper(type, context); if (typeNode) { result.push(typeNode); @@ -3015,8 +3015,7 @@ namespace ts { typeParameterNodes = mapToTypeNodes(typeParameters, context); } - const symbolName = getNameOfSymbol(symbol, context); - const identifier = setEmitFlags(createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping); + const identifier = setEmitFlags(createIdentifier(getNameOfSymbolAsWritten(symbol, context), typeParameterNodes), EmitFlags.NoAsciiEscaping); return index > 0 ? createQualifiedName(createEntityNameFromSymbolChain(chain, index - 1), identifier) : identifier; } @@ -3128,7 +3127,14 @@ namespace ts { symbolStack: Symbol[] | undefined; } - function getNameOfSymbol(symbol: Symbol, context?: NodeBuilderContext): string { + /** + * Gets a human-readable name for a symbol. + * Should *not* be used for the right-hand side of a `.` -- use `symbolName(symbol)` for that instead. + * + * Unlike `symbolName(symbol)`, this will include quotes if the name is from a string literal. + * It will also use a representation of a number as written instead of a decimal form, e.g. `0o11` instead of `9`. + */ + function getNameOfSymbolAsWritten(symbol: Symbol, context?: NodeBuilderContext): string { if (symbol.declarations && symbol.declarations.length) { const declaration = symbol.declarations[0]; const name = getNameOfDeclaration(declaration); @@ -3165,7 +3171,7 @@ namespace ts { * for the name of the symbol if it is available to match how the user wrote the name. */ function appendSymbolNameOnly(symbol: Symbol, writer: SymbolWriter): void { - writer.writeSymbol(getNameOfSymbol(symbol), symbol); + writer.writeSymbol(getNameOfSymbolAsWritten(symbol), symbol); } /** @@ -3174,7 +3180,7 @@ namespace ts { * ensuring that any names written with literals use element accesses. */ function appendPropertyOrElementAccessForSymbol(symbol: Symbol, writer: SymbolWriter): void { - const symbolName = getNameOfSymbol(symbol); + const symbolName = symbol.escapedName === "default" ? "default" : getNameOfSymbolAsWritten(symbol); const firstChar = symbolName.charCodeAt(0); const needsElementAccess = !isIdentifierStart(firstChar, languageVersion); @@ -3939,7 +3945,7 @@ 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) & ModifierFlags.Export) && - !(node.kind !== SyntaxKind.ImportEqualsDeclaration && parent.kind !== SyntaxKind.SourceFile && isInAmbientContext(parent))) { + !(node.kind !== SyntaxKind.ImportEqualsDeclaration && parent.kind !== SyntaxKind.SourceFile && parent.flags & NodeFlags.Ambient)) { return isGlobalSourceFile(parent); } // Exported members/ambient module elements (exception import declaration) are visible if parent is visible @@ -4317,7 +4323,7 @@ namespace ts { if ((noImplicitAny || isInJavaScriptFile(declaration)) && declaration.kind === SyntaxKind.VariableDeclaration && !isBindingPattern(declaration.name) && - !(getCombinedModifierFlags(declaration) & ModifierFlags.Export) && !isInAmbientContext(declaration)) { + !(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. @@ -5190,7 +5196,7 @@ namespace ts { function isLiteralEnumMember(member: EnumMember) { const expr = member.initializer; if (!expr) { - return !isInAmbientContext(member); + return !(member.flags & NodeFlags.Ambient); } switch (expr.kind) { case SyntaxKind.StringLiteral: @@ -5866,6 +5872,17 @@ namespace ts { return type.modifiersType; } + function getMappedTypeModifiers(type: MappedType): MappedTypeModifiers { + return (type.declaration.readonlyToken ? MappedTypeModifiers.Readonly : 0) | + (type.declaration.questionToken ? MappedTypeModifiers.Optional : 0); + } + + function getCombinedMappedTypeModifiers(type: MappedType): MappedTypeModifiers { + const modifiersType = getModifiersTypeFromMappedType(type); + return getMappedTypeModifiers(type) | + (isGenericMappedType(modifiersType) ? getMappedTypeModifiers(modifiersType) : 0); + } + function isPartialMappedType(type: Type) { return getObjectFlags(type) & ObjectFlags.Mapped && !!(type).declaration.questionToken; } @@ -6566,7 +6583,7 @@ namespace ts { if (!node) return false; switch (node.kind) { case SyntaxKind.Identifier: - return (node).escapedText === "arguments" && isPartOfExpression(node); + return (node).escapedText === "arguments" && isExpressionNode(node); case SyntaxKind.PropertyDeclaration: case SyntaxKind.MethodDeclaration: @@ -6885,7 +6902,7 @@ namespace ts { const numTypeArguments = length(node.typeArguments); const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters); const isJs = isInJavaScriptFile(node); - const isJsImplicitAny = !compilerOptions.noImplicitAny && isJs; + const isJsImplicitAny = !noImplicitAny && isJs; if (!isJsImplicitAny && (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length)) { const missingAugmentsTag = isJs && node.parent.kind !== SyntaxKind.JSDocAugmentsTag; const diag = minTypeArgumentCount === typeParameters.length @@ -7292,6 +7309,9 @@ namespace ts { property.type = typeParameter; properties.push(property); } + const lengthSymbol = createSymbol(SymbolFlags.Property, "length" as __String); + lengthSymbol.type = getLiteralType(arity); + properties.push(lengthSymbol); const type = createObjectType(ObjectFlags.Tuple | ObjectFlags.Reference); type.typeParameters = typeParameters; type.outerTypeParameters = undefined; @@ -7341,28 +7361,12 @@ namespace ts { unionIndex?: number; } - function binarySearchTypes(types: Type[], type: Type): number { - let low = 0; - let high = types.length - 1; - const typeId = type.id; - while (low <= high) { - const middle = low + ((high - low) >> 1); - const id = types[middle].id; - if (id === typeId) { - return middle; - } - else if (id > typeId) { - high = middle - 1; - } - else { - low = middle + 1; - } - } - return ~low; + function getTypeId(type: Type) { + return type.id; } function containsType(types: Type[], type: Type): boolean { - return binarySearchTypes(types, type) >= 0; + return binarySearch(types, type, getTypeId, compareValues) >= 0; } // Return true if the given intersection type contains (a) more than one unit type or (b) an object @@ -7403,7 +7407,7 @@ namespace ts { if (flags & TypeFlags.Number) typeSet.containsNumber = true; if (flags & TypeFlags.StringOrNumberLiteral) typeSet.containsStringOrNumberLiteral = true; const len = typeSet.length; - const index = len && type.id > typeSet[len - 1].id ? ~len : binarySearchTypes(typeSet, type); + const index = len && type.id > typeSet[len - 1].id ? ~len : binarySearch(typeSet, type, getTypeId, compareValues); if (index < 0) { if (!(flags & TypeFlags.Object && (type).objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && containsIdenticalType(typeSet, type))) { @@ -7430,9 +7434,12 @@ namespace ts { return false; } - function isSubtypeOfAny(candidate: Type, types: Type[]): boolean { - for (const type of types) { - if (candidate !== type && isTypeSubtypeOf(candidate, type)) { + function isSubtypeOfAny(source: Type, targets: Type[]): boolean { + for (const target of targets) { + if (source !== target && isTypeSubtypeOf(source, target) && ( + !(getObjectFlags(getTargetType(source)) & ObjectFlags.Class) || + !(getObjectFlags(getTargetType(target)) & ObjectFlags.Class) || + isTypeDerivedFrom(source, target))) { return true; } } @@ -7579,11 +7586,11 @@ namespace ts { } } - // Add the given types to the given type set. Order is preserved, duplicates are removed, - // and nested types of the given kind are flattened into the set. + // Add the given types to the given type set. Order is preserved, freshness is removed from literal + // types, duplicates are removed, and nested types of the given kind are flattened into the set. function addTypesToIntersection(typeSet: TypeSet, types: Type[]) { for (const type of types) { - addTypeToIntersection(typeSet, type); + addTypeToIntersection(typeSet, getRegularTypeOfLiteralType(type)); } } @@ -7672,7 +7679,7 @@ namespace ts { function getIndexTypeOrString(type: Type): Type { const indexType = getIndexType(type); - return indexType !== neverType ? indexType : stringType; + return indexType.flags & TypeFlags.Never ? stringType : indexType; } function getTypeFromTypeOperatorNode(node: TypeOperatorNode) { @@ -7981,11 +7988,16 @@ namespace ts { } } - const spread = createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); + const spread = createAnonymousType( + symbol, + members, + emptyArray, + emptyArray, + getNonReadonlyIndexSignature(stringIndexInfo), + getNonReadonlyIndexSignature(numberIndexInfo)); spread.flags |= propagatedFlags; spread.flags |= TypeFlags.FreshLiteral | TypeFlags.ContainsObjectLiteral; - (spread as ObjectType).objectFlags |= ObjectFlags.ObjectLiteral; - spread.symbol = symbol; + (spread as ObjectType).objectFlags |= (ObjectFlags.ObjectLiteral | ObjectFlags.ContainsSpread); return spread; } @@ -8001,6 +8013,13 @@ namespace ts { return result; } + function getNonReadonlyIndexSignature(index: IndexInfo) { + if (index && index.isReadonly) { + return createIndexInfo(index.type, /*isReadonly*/ false, index.declaration); + } + return index; + } + function isClassMethod(prop: Symbol) { return prop.flags & SymbolFlags.Method && find(prop.declarations, decl => isClassLike(decl.parent)); } @@ -8555,12 +8574,19 @@ namespace ts { return isTypeRelatedTo(source, target, assignableRelation); } - // A type S is considered to be an instance of a type T if S and T are the same type or if S is a - // subtype of T but not structurally identical to T. This specifically means that two distinct but - // structurally identical types (such as two classes) are not considered instances of each other. - function isTypeInstanceOf(source: Type, target: Type): boolean { - return getTargetType(source) === getTargetType(target) || isTypeSubtypeOf(source, target) && !isTypeIdenticalTo(source, target); - } + // An object type S is considered to be derived from an object type T if + // S is a union type and every constituent of S is derived from T, + // T is a union type and S is derived from at least one constituent of T, or + // T is one of the global types Object and Function and S is a subtype of T, or + // T occurs directly or indirectly in an 'extends' clause of S. + // 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).types, t => isTypeDerivedFrom(t, target)) : + target.flags & TypeFlags.Union ? some((target).types, t => isTypeDerivedFrom(source, t)) : + target === globalObjectType || target === globalFunctionType ? isTypeSubtypeOf(source, target) : + hasBaseType(source, getTargetType(target)); + } /** * This is *not* a bi-directional relationship. @@ -8842,8 +8868,8 @@ namespace ts { function isSimpleTypeRelatedTo(source: Type, target: Type, relation: Map, errorReporter?: ErrorReporter) { const s = source.flags; const t = target.flags; - if (t & TypeFlags.Never) return false; if (t & TypeFlags.Any || s & TypeFlags.Never) 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) && @@ -9026,7 +9052,7 @@ namespace ts { if (isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True; - if (getObjectFlags(source) & ObjectFlags.ObjectLiteral && source.flags & TypeFlags.FreshLiteral) { + if (isObjectLiteralType(source) && source.flags & TypeFlags.FreshLiteral) { if (hasExcessProperties(source, target, reportErrors)) { if (reportErrors) { reportRelationError(headMessage, source, target); @@ -9229,20 +9255,24 @@ namespace ts { return Ternary.False; } + // Keep this up-to-date with the same logic within `getApparentTypeOfContextualType`, since they should behave similarly function findMatchingDiscriminantType(source: Type, target: UnionOrIntersectionType) { let match: Type; const sourceProperties = getPropertiesOfObjectType(source); if (sourceProperties) { - const sourceProperty = findSingleDiscriminantProperty(sourceProperties, target); - if (sourceProperty) { - const sourceType = getTypeOfSymbol(sourceProperty); - for (const type of target.types) { - const targetType = getTypeOfPropertyOfType(type, sourceProperty.escapedName); - if (targetType && isRelatedTo(sourceType, targetType)) { - if (match) { - return undefined; + const sourcePropertiesFiltered = findDiscriminantProperties(sourceProperties, target); + if (sourcePropertiesFiltered) { + for (const sourceProperty of sourcePropertiesFiltered) { + const sourceType = getTypeOfSymbol(sourceProperty); + for (const type of target.types) { + const targetType = getTypeOfPropertyOfType(type, sourceProperty.escapedName); + if (targetType && isRelatedTo(sourceType, targetType)) { + if (type === match) continue; // Finding multiple fields which discriminate to the same type is fine + if (match) { + return undefined; + } + match = type; } - match = type; } } } @@ -9413,6 +9443,7 @@ namespace ts { function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary { let result: Ternary; + let originalErrorInfo: DiagnosticMessageChain; const saveErrorInfo = errorInfo; if (target.flags & TypeFlags.TypeParameter) { // A source type { [P in keyof T]: X } is related to a target type T if X is related to T[P]. @@ -9453,32 +9484,30 @@ namespace ts { } } } + else if (isGenericMappedType(target) && !isGenericMappedType(source) && getConstraintTypeFromMappedType(target) === getIndexType(source)) { + // A source type T is related to a target type { [P in keyof T]: X } if T[P] is related to X. + const indexedAccessType = getIndexedAccessType(source, getTypeParameterFromMappedType(target)); + const templateType = getTemplateTypeFromMappedType(target); + if (result = isRelatedTo(indexedAccessType, templateType, reportErrors)) { + errorInfo = saveErrorInfo; + return result; + } + } if (source.flags & TypeFlags.TypeParameter) { - // A source type T is related to a target type { [P in keyof T]: X } if T[P] is related to X. - if (getObjectFlags(target) & ObjectFlags.Mapped && getConstraintTypeFromMappedType(target) === getIndexType(source)) { - const indexedAccessType = getIndexedAccessType(source, getTypeParameterFromMappedType(target)); - const templateType = getTemplateTypeFromMappedType(target); - if (result = isRelatedTo(indexedAccessType, templateType, reportErrors)) { + let constraint = getConstraintOfTypeParameter(source); + // A type parameter with no constraint is not related to the non-primitive object type. + if (constraint || !(target.flags & TypeFlags.NonPrimitive)) { + if (!constraint || constraint.flags & TypeFlags.Any) { + constraint = emptyObjectType; + } + // Report constraint errors only if the constraint is not the empty object type + const reportConstraintErrors = reportErrors && constraint !== emptyObjectType; + if (result = isRelatedTo(constraint, target, reportConstraintErrors)) { errorInfo = saveErrorInfo; return result; } } - else { - let constraint = getConstraintOfTypeParameter(source); - // A type parameter with no constraint is not related to the non-primitive object type. - if (constraint || !(target.flags & TypeFlags.NonPrimitive)) { - if (!constraint || constraint.flags & TypeFlags.Any) { - constraint = emptyObjectType; - } - // Report constraint errors only if the constraint is not the empty object type - const reportConstraintErrors = reportErrors && constraint !== emptyObjectType; - if (result = isRelatedTo(constraint, target, reportConstraintErrors)) { - errorInfo = saveErrorInfo; - return result; - } - } - } } else if (source.flags & TypeFlags.IndexedAccess) { // A type S[K] is related to a type T if A[K] is related to T, where K is string-like and @@ -9494,6 +9523,7 @@ namespace ts { // if we have indexed access types with identical index types, see if relationship holds for // the two object types. if (result = isRelatedTo((source).objectType, (target).objectType, reportErrors)) { + errorInfo = saveErrorInfo; return result; } } @@ -9525,6 +9555,10 @@ namespace ts { if (!(reportErrors && some(variances, v => v === Variance.Invariant))) { return Ternary.False; } + // We remember the original error information so we can restore it in case the structural + // comparison unexpectedly succeeds. This can happen when the structural comparison result + // is a Ternary.Maybe for example caused by the recursion depth limiter. + originalErrorInfo = errorInfo; errorInfo = saveErrorInfo; } } @@ -9563,8 +9597,11 @@ namespace ts { } } if (result) { - errorInfo = saveErrorInfo; - return result; + if (!originalErrorInfo) { + errorInfo = saveErrorInfo; + return result; + } + errorInfo = originalErrorInfo; } } } @@ -9575,13 +9612,10 @@ 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 sourceReadonly = !!source.declaration.readonlyToken; - const sourceOptional = !!source.declaration.questionToken; - const targetReadonly = !!target.declaration.readonlyToken; - const targetOptional = !!target.declaration.questionToken; - const modifiersRelated = relation === identityRelation ? - sourceReadonly === targetReadonly && sourceOptional === targetOptional : - relation === comparableRelation || !sourceOptional || targetOptional; + const modifiersRelated = relation === comparableRelation || ( + relation === identityRelation ? getMappedTypeModifiers(source) === getMappedTypeModifiers(target) : + !(getCombinedMappedTypeModifiers(source) & MappedTypeModifiers.Optional) || + getCombinedMappedTypeModifiers(target) & MappedTypeModifiers.Optional); if (modifiersRelated) { let result: Ternary; if (result = isRelatedTo(getConstraintTypeFromMappedType(target), getConstraintTypeFromMappedType(source), reportErrors)) { @@ -9596,7 +9630,7 @@ namespace ts { if (relation === identityRelation) { return propertiesIdenticalTo(source, target); } - const requireOptionalProperties = relation === subtypeRelation && !(getObjectFlags(source) & ObjectFlags.ObjectLiteral); + const requireOptionalProperties = relation === subtypeRelation && !isObjectLiteralType(source) && !isEmptyArrayLiteralType(source); const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties); if (unmatchedProperty) { if (reportErrors) { @@ -9604,6 +9638,19 @@ namespace ts { } return Ternary.False; } + if (isObjectLiteralType(target)) { + for (const sourceProp of getPropertiesOfType(source)) { + if (!getPropertyOfObjectType(target, sourceProp.escapedName)) { + const sourceType = getTypeOfSymbol(sourceProp); + if (!(sourceType === undefinedType || sourceType === undefinedWideningType)) { + if (reportErrors) { + reportError(Diagnostics.Property_0_does_not_exist_on_type_1, symbolToString(sourceProp), typeToString(target)); + } + return Ternary.False; + } + } + } + } let result = Ternary.True; const properties = getPropertiesOfObjectType(target); for (const targetProp of properties) { @@ -10291,6 +10338,11 @@ namespace ts { !(type.flags & TypeFlags.Nullable) && isTypeAssignableTo(type, anyReadonlyArrayType); } + function isEmptyArrayLiteralType(type: Type): boolean { + const elementType = isArrayType(type) ? (type).typeArguments[0] : undefined; + return elementType === undefinedWideningType || elementType === implicitNeverType; + } + function isTupleLikeType(type: Type): boolean { return !!getPropertyOfType(type, "0" as __String); } @@ -10425,7 +10477,7 @@ namespace ts { * Leave signatures alone since they are not subject to the check. */ function getRegularTypeOfObjectLiteral(type: Type): Type { - if (!(getObjectFlags(type) & ObjectFlags.ObjectLiteral && type.flags & TypeFlags.FreshLiteral)) { + if (!(isObjectLiteralType(type) && type.flags & TypeFlags.FreshLiteral)) { return type; } const regularType = (type).regularType; @@ -10447,18 +10499,74 @@ namespace ts { return regularNew; } - function getWidenedProperty(prop: Symbol): Symbol { + function createWideningContext(parent: WideningContext, propertyName: __String, siblings: Type[]): WideningContext { + return { parent, propertyName, siblings, resolvedPropertyNames: undefined }; + } + + function getSiblingsOfContext(context: WideningContext): Type[] { + if (!context.siblings) { + const siblings: Type[] = []; + for (const type of getSiblingsOfContext(context.parent)) { + if (isObjectLiteralType(type)) { + const prop = getPropertyOfObjectType(type, context.propertyName); + if (prop) { + forEachType(getTypeOfSymbol(prop), t => { + siblings.push(t); + }); + } + } + } + context.siblings = siblings; + } + return context.siblings; + } + + function getPropertyNamesOfContext(context: WideningContext): __String[] { + if (!context.resolvedPropertyNames) { + const names = createMap() as UnderscoreEscapedMap; + for (const t of getSiblingsOfContext(context)) { + if (isObjectLiteralType(t) && !(getObjectFlags(t) & ObjectFlags.ContainsSpread)) { + for (const prop of getPropertiesOfType(t)) { + names.set(prop.escapedName, true); + } + } + } + context.resolvedPropertyNames = arrayFrom(names.keys()); + } + return context.resolvedPropertyNames; + } + + function getWidenedProperty(prop: Symbol, context: WideningContext): Symbol { const original = getTypeOfSymbol(prop); - const widened = getWidenedType(original); + const propContext = context && createWideningContext(context, prop.escapedName, /*siblings*/ undefined); + const widened = getWidenedTypeWithContext(original, propContext); return widened === original ? prop : createSymbolWithType(prop, widened); } - function getWidenedTypeOfObjectLiteral(type: Type): Type { + function getUndefinedProperty(name: __String) { + const cached = undefinedProperties.get(name); + if (cached) { + return cached; + } + const result = createSymbol(SymbolFlags.Property | SymbolFlags.Optional, name); + result.type = undefinedType; + undefinedProperties.set(name, result); + return result; + } + + function getWidenedTypeOfObjectLiteral(type: Type, context: WideningContext): Type { const members = createSymbolTable(); for (const prop of getPropertiesOfObjectType(type)) { // Since get accessors already widen their return value there is no need to // widen accessor based properties here. - members.set(prop.escapedName, prop.flags & SymbolFlags.Property ? getWidenedProperty(prop) : prop); + members.set(prop.escapedName, prop.flags & SymbolFlags.Property ? getWidenedProperty(prop, context) : prop); + } + if (context) { + for (const name of getPropertyNamesOfContext(context)) { + if (!members.has(name)) { + members.set(name, getUndefinedProperty(name)); + } + } } const stringIndexInfo = getIndexInfoOfType(type, IndexKind.String); const numberIndexInfo = getIndexInfoOfType(type, IndexKind.Number); @@ -10467,20 +10575,25 @@ namespace ts { numberIndexInfo && createIndexInfo(getWidenedType(numberIndexInfo.type), numberIndexInfo.isReadonly)); } - function getWidenedConstituentType(type: Type): Type { - return type.flags & TypeFlags.Nullable ? type : getWidenedType(type); + function getWidenedType(type: Type) { + return getWidenedTypeWithContext(type, /*context*/ undefined); } - function getWidenedType(type: Type): Type { + function getWidenedTypeWithContext(type: Type, context: WideningContext): Type { if (type.flags & TypeFlags.RequiresWidening) { if (type.flags & TypeFlags.Nullable) { return anyType; } - if (getObjectFlags(type) & ObjectFlags.ObjectLiteral) { - return getWidenedTypeOfObjectLiteral(type); + if (isObjectLiteralType(type)) { + return getWidenedTypeOfObjectLiteral(type, context); } if (type.flags & TypeFlags.Union) { - return getUnionType(sameMap((type).types, getWidenedConstituentType)); + const unionContext = context || createWideningContext(/*parent*/ undefined, /*propertyName*/ undefined, (type).types); + const widenedTypes = sameMap((type).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 {}). + return getUnionType(widenedTypes, some(widenedTypes, isEmptyObjectType)); } if (isArrayType(type) || isTupleType(type)) { return createTypeReference((type).target, sameMap((type).typeArguments, getWidenedType)); @@ -10502,28 +10615,35 @@ namespace ts { */ function reportWideningErrorsInType(type: Type): boolean { let errorReported = false; - if (type.flags & TypeFlags.Union) { - for (const t of (type).types) { - if (reportWideningErrorsInType(t)) { + if (type.flags & TypeFlags.ContainsWideningType) { + if (type.flags & TypeFlags.Union) { + if (some((type).types, isEmptyObjectType)) { errorReported = true; } + else { + for (const t of (type).types) { + if (reportWideningErrorsInType(t)) { + errorReported = true; + } + } + } } - } - if (isArrayType(type) || isTupleType(type)) { - for (const t of (type).typeArguments) { - if (reportWideningErrorsInType(t)) { - errorReported = true; + if (isArrayType(type) || isTupleType(type)) { + for (const t of (type).typeArguments) { + if (reportWideningErrorsInType(t)) { + errorReported = true; + } } } - } - if (getObjectFlags(type) & ObjectFlags.ObjectLiteral) { - for (const p of getPropertiesOfObjectType(type)) { - const t = getTypeOfSymbol(p); - if (t.flags & TypeFlags.ContainsWideningType) { - if (!reportWideningErrorsInType(t)) { - error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, symbolName(p), typeToString(getWidenedType(t))); + if (isObjectLiteralType(type)) { + for (const p of getPropertiesOfObjectType(type)) { + const t = getTypeOfSymbol(p); + if (t.flags & TypeFlags.ContainsWideningType) { + if (!reportWideningErrorsInType(t)) { + error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, symbolName(p), typeToString(getWidenedType(t))); + } + errorReported = true; } - errorReported = true; } } } @@ -10703,7 +10823,7 @@ namespace ts { } function getUnmatchedProperty(source: Type, target: Type, requireOptionalProperties: boolean) { - const properties = getPropertiesOfObjectType(target); + const properties = target.flags & TypeFlags.Intersection ? getPropertiesOfUnionOrIntersectionType(target) : getPropertiesOfObjectType(target); for (const targetProp of properties) { if (requireOptionalProperties || !(targetProp.flags & SymbolFlags.Optional)) { const sourceProp = getPropertyOfType(source, targetProp.escapedName); @@ -10777,9 +10897,10 @@ namespace ts { // Because the anyFunctionType is internal, it should not be exposed to the user by adding // it as an inference candidate. Hopefully, a better candidate will come along that does // not contain anyFunctionType when we come back to this argument for its second round - // of inference. Also, we exclude inferences for silentNeverType which is used as a wildcard - // when constructing types from type parameters that had no inference candidates. - if (source.flags & TypeFlags.ContainsAnyFunctionType || source === silentNeverType) { + // of inference. Also, we exclude inferences for silentNeverType (which is used as a wildcard + // when constructing types from type parameters that had no inference candidates) and + // implicitNeverType (which is used as the element type for empty array literals). + if (source.flags & TypeFlags.ContainsAnyFunctionType || source === silentNeverType || source === implicitNeverType) { return; } const inference = getInferenceInfoForType(target); @@ -11029,11 +11150,28 @@ namespace ts { return constraint && maybeTypeOfKind(constraint, TypeFlags.Primitive | TypeFlags.Index); } + function isObjectLiteralType(type: Type) { + return !!(getObjectFlags(type) & ObjectFlags.ObjectLiteral); + } + + function widenObjectLiteralCandidates(candidates: Type[]): Type[] { + if (candidates.length > 1) { + const objectLiterals = filter(candidates, isObjectLiteralType); + if (objectLiterals.length) { + const objectLiteralsType = getWidenedType(getUnionType(objectLiterals, /*subtypeReduction*/ true)); + return concatenate(filter(candidates, t => !isObjectLiteralType(t)), [objectLiteralsType]); + } + } + return candidates; + } + function getInferredType(context: InferenceContext, index: number): Type { const inference = context.inferences[index]; let inferredType = inference.inferredType; if (!inferredType) { if (inference.candidates) { + // Extract all object literal types and replace them with a single widened and normalized type. + const candidates = widenObjectLiteralCandidates(inference.candidates); // We widen inferred literal types if // all inferences were made to top-level ocurrences of the type parameter, and // the type parameter has no constraint or its constraint includes no primitive or literal types, and @@ -11042,7 +11180,7 @@ namespace ts { const widenLiteralTypes = inference.topLevel && !hasPrimitiveConstraint(inference.typeParameter) && (inference.isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter)); - const baseCandidates = widenLiteralTypes ? sameMap(inference.candidates, getWidenedLiteralType) : inference.candidates; + const baseCandidates = widenLiteralTypes ? sameMap(candidates, getWidenedLiteralType) : candidates; // If all inferences were made from contravariant positions, infer a common subtype. Otherwise, if // union types were requested or if all inferences were made from the return type position, infer a // union type. Otherwise, infer a common supertype. @@ -11248,14 +11386,15 @@ namespace ts { return false; } - function findSingleDiscriminantProperty(sourceProperties: Symbol[], target: Type): Symbol | undefined { - let result: Symbol; + function findDiscriminantProperties(sourceProperties: Symbol[], target: Type): Symbol[] | undefined { + let result: Symbol[]; for (const sourceProperty of sourceProperties) { if (isDiscriminantProperty(target, sourceProperty.escapedName)) { if (result) { - return undefined; + result.push(sourceProperty); + continue; } - result = sourceProperty; + result = [sourceProperty]; } } return result; @@ -12309,7 +12448,7 @@ namespace ts { } if (targetType) { - return getNarrowedType(type, targetType, assumeTrue, isTypeInstanceOf); + return getNarrowedType(type, targetType, assumeTrue, isTypeDerivedFrom); } return type; @@ -12416,7 +12555,7 @@ namespace ts { if (isRightSideOfQualifiedNameOrPropertyAccess(location)) { location = location.parent; } - if (isPartOfExpression(location) && !isAssignmentTarget(location)) { + if (isExpressionNode(location) && !isAssignmentTarget(location)) { const type = getTypeOfExpression(location); if (getExportSymbolOfValueSymbolIfExported(getNodeLinks(location).resolvedSymbol) === symbol) { return type; @@ -12639,7 +12778,7 @@ namespace ts { const assumeInitialized = isParameter || isAlias || isOuterVariable || type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || isInTypeQuery(node) || node.parent.kind === SyntaxKind.ExportSpecifier) || node.parent.kind === SyntaxKind.NonNullExpression || - isInAmbientContext(declaration); + declaration.flags & NodeFlags.Ambient; const initialType = assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, getRootDeclaration(declaration) as VariableLikeDeclaration) : type) : type === autoType || type === autoArrayType ? undefinedType : getNullableType(type, TypeFlags.Undefined); @@ -13491,7 +13630,13 @@ namespace ts { // JSX expression can appear in two position : JSX Element's children or JSX attribute const jsxAttributes = isJsxAttributeLike(node.parent) ? node.parent.parent : - node.parent.openingElement.attributes; // node.parent is JsxElement + isJsxElement(node.parent) ? + node.parent.openingElement.attributes : + undefined; // node.parent is JsxFragment with no attributes + + if (!jsxAttributes) { + return undefined; // don't check children of a fragment + } // 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. @@ -13537,8 +13682,32 @@ 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): Type { - const type = getContextualType(node); - return type && getApparentType(type); + let contextualType = getContextualType(node); + contextualType = contextualType && mapType(contextualType, getApparentType); + if (!(contextualType && contextualType.flags & TypeFlags.Union && isObjectLiteralExpression(node))) { + return contextualType; + } + // Keep the below up-to-date with the work done within `isRelatedTo` by `findMatchingDiscriminantType` + let match: Type | undefined; + propLoop: for (const prop of node.properties) { + if (!prop.symbol) continue; + if (prop.kind !== SyntaxKind.PropertyAssignment) continue; + if (isDiscriminantProperty(contextualType, prop.symbol.escapedName)) { + const discriminatingType = getTypeOfNode(prop.initializer); + for (const type of (contextualType as UnionType).types) { + const targetType = getTypeOfPropertyOfType(type, prop.symbol.escapedName); + if (targetType && checkTypeAssignableTo(discriminatingType, targetType, /*errorNode*/ undefined)) { + if (match) { + if (type === match) continue; // Finding multiple fields which discriminate to the same type is fine + match = undefined; + break propLoop; + } + match = type; + } + } + } + } + return match || contextualType; } /** @@ -13771,7 +13940,6 @@ namespace ts { type.pattern = node; return type; } - const contextualType = getApparentTypeOfContextualType(node); if (contextualType && contextualTypeIsTupleLikeType(contextualType)) { const pattern = contextualType.pattern; // If array literal is contextually typed by a binding pattern or an assignment pattern, pad the resulting @@ -13798,7 +13966,7 @@ namespace ts { } return createArrayType(elementTypes.length ? getUnionType(elementTypes, /*subtypeReduction*/ true) : - strictNullChecks ? neverType : undefinedWideningType); + strictNullChecks ? implicitNeverType : undefinedWideningType); } function isNumericName(name: DeclarationName): boolean { @@ -14071,13 +14239,13 @@ namespace ts { } function checkJsxSelfClosingElement(node: JsxSelfClosingElement): Type { - checkJsxOpeningLikeElement(node); + checkJsxOpeningLikeElementOrOpeningFragment(node); return getJsxGlobalElementType() || anyType; } function checkJsxElement(node: JsxElement): Type { // Check attributes - checkJsxOpeningLikeElement(node.openingElement); + checkJsxOpeningLikeElementOrOpeningFragment(node.openingElement); // Perform resolution on the closing tag so that rename/go to definition/etc work if (isJsxIntrinsicIdentifier(node.closingElement.tagName)) { @@ -14090,6 +14258,16 @@ namespace ts { return getJsxGlobalElementType() || anyType; } + function checkJsxFragment(node: JsxFragment): Type { + checkJsxOpeningLikeElementOrOpeningFragment(node.openingFragment); + + if (compilerOptions.jsx === JsxEmit.React && compilerOptions.jsxFactory) { + error(node, Diagnostics.JSX_fragment_is_not_supported_when_using_jsxFactory); + } + + return getJsxGlobalElementType() || anyType; + } + /** * Returns true iff the JSX element name would be a valid JS identifier, ignoring restrictions about keywords not being identifiers */ @@ -14753,14 +14931,19 @@ namespace ts { } } - function checkJsxOpeningLikeElement(node: JsxOpeningLikeElement) { - checkGrammarJsxElement(node); + function checkJsxOpeningLikeElementOrOpeningFragment(node: JsxOpeningLikeElement | JsxOpeningFragment) { + const isNodeOpeningLikeElement = isJsxOpeningLikeElement(node); + + if (isNodeOpeningLikeElement) { + checkGrammarJsxElement(node); + } checkJsxPreconditions(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 reactRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined; const reactNamespace = getJsxNamespace(); - const reactSym = resolveName(node.tagName, reactNamespace, SymbolFlags.Value, reactRefErr, reactNamespace, /*isUse*/ true); + const reactLocation = isNodeOpeningLikeElement ? (node).tagName : node; + const reactSym = resolveName(reactLocation, reactNamespace, SymbolFlags.Value, reactRefErr, reactNamespace, /*isUse*/ true); if (reactSym) { // Mark local symbol as referenced here because it might not have been marked // if jsx emit was not react as there wont be error being emitted @@ -14772,7 +14955,9 @@ namespace ts { } } - checkJsxAttributesAssignableToTagNameAttributes(node); + if (isNodeOpeningLikeElement) { + checkJsxAttributesAssignableToTagNameAttributes(node); + } } /** @@ -14928,12 +15113,11 @@ namespace ts { } } - // Referencing Abstract Properties within Constructors is not allowed - if ((flags & ModifierFlags.Abstract) && symbolHasNonMethodDeclaration(prop)) { + // Referencing abstract properties within their own constructors is not allowed + if ((flags & ModifierFlags.Abstract) && isThisProperty(node) && symbolHasNonMethodDeclaration(prop)) { const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)); - - if (declaringClassDeclaration && isNodeWithinConstructor(node, declaringClassDeclaration)) { - error(errorNode, Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, symbolToString(prop), typeToString(getDeclaringClass(prop))); + if (declaringClassDeclaration && isNodeWithinConstructorOfClass(node, declaringClassDeclaration)) { + error(errorNode, Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, symbolToString(prop), getTextOfIdentifierOrLiteral(declaringClassDeclaration.name)); return false; } } @@ -14977,12 +15161,11 @@ namespace ts { if (flags & ModifierFlags.Static) { return true; } - // An instance property must be accessed through an instance of the enclosing class - if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) { + if (type.flags & TypeFlags.TypeParameter) { // get the original type -- represented as the type constraint of the 'this' type - type = getConstraintOfTypeParameter(type); + type = (type as TypeParameter).isThisType ? getConstraintOfTypeParameter(type) : getBaseConstraintOfType(type); } - if (!(getObjectFlags(getTargetType(type)) & ObjectFlags.ClassOrInterface && hasBaseType(type, enclosingClass))) { + if (!type || !hasBaseType(type, enclosingClass)) { error(errorNode, Diagnostics.Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1, symbolToString(prop), typeToString(enclosingClass)); return false; } @@ -15039,7 +15222,7 @@ namespace ts { if (indexInfo.isReadonly && (isAssignmentTarget(node) || isDeleteTarget(node))) { error(node, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(apparentType)); } - return indexInfo.type; + return getFlowTypeOfPropertyAccess(node, /*prop*/ undefined, indexInfo.type, getAssignmentTargetKind(node)); } if (right.escapedText && !checkAndReportErrorForExtendingInterface(node)) { reportNonexistentProperty(right, type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType ? apparentType : type); @@ -15064,16 +15247,21 @@ namespace ts { return unknownType; } } + return getFlowTypeOfPropertyAccess(node, prop, propType, assignmentKind); + } - // 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. - if (node.kind !== SyntaxKind.PropertyAccessExpression || assignmentKind === AssignmentKind.Definite || - !(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Accessor)) && - !(prop.flags & SymbolFlags.Method && propType.flags & TypeFlags.Union)) { - return propType; + /** + * 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. + */ + function getFlowTypeOfPropertyAccess(node: PropertyAccessExpression | QualifiedName, prop: Symbol | undefined, type: Type, assignmentKind: AssignmentKind) { + if (node.kind !== SyntaxKind.PropertyAccessExpression || + assignmentKind === AssignmentKind.Definite || + prop && !(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Accessor)) && !(prop.flags & SymbolFlags.Method && type.flags & TypeFlags.Union)) { + return type; } - const flowType = getFlowTypeOfReference(node, propType); + const flowType = getFlowTypeOfReference(node, type); return assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType; } @@ -15090,7 +15278,7 @@ namespace ts { } else if (valueDeclaration.kind === SyntaxKind.ClassDeclaration && node.parent.kind !== SyntaxKind.TypeReference && - !isInAmbientContext(valueDeclaration) && + !(valueDeclaration.flags & NodeFlags.Ambient) && !isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right)) { error(right, Diagnostics.Class_0_used_before_its_declaration, idText(right)); } @@ -15105,7 +15293,7 @@ namespace ts { // We might be in `a = { b: this.b }`, so keep looking. See `tests/cases/compiler/useBeforeDeclaration_propertyAssignment.ts`. return false; default: - return isPartOfExpression(node) ? false : "quit"; + return isExpressionNode(node) ? false : "quit"; } }); } @@ -15162,9 +15350,10 @@ namespace ts { return suggestion && symbolName(suggestion); } - function getSuggestionForNonexistentSymbol(location: Node, name: __String, meaning: SymbolFlags): string { - const result = resolveNameHelper(location, name, meaning, /*nameNotFoundMessage*/ undefined, name, /*isUse*/ false, (symbols, name, meaning) => { - // `name` from the callback === the outer `name` + function getSuggestionForNonexistentSymbol(location: Node, outerName: __String, meaning: SymbolFlags): string { + Debug.assert(outerName !== undefined, "outername should always be defined"); + const result = resolveNameHelper(location, outerName, meaning, /*nameNotFoundMessage*/ undefined, outerName, /*isUse*/ false, (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. @@ -16489,21 +16678,9 @@ namespace ts { * 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) { - if (isTypeAny(funcType)) { - return true; - } - if (isTypeAny(apparentFuncType) && funcType.flags & TypeFlags.TypeParameter) { - return true; - } - if (!numCallSignatures && !numConstructSignatures) { - // We exclude union types because we may have a union of function types that happen to have - // no common signatures. - if (funcType.flags & TypeFlags.Union) { - return false; - } - return isTypeAssignableTo(funcType, globalFunctionType); - } - return false; + // 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 && !(funcType.flags & (TypeFlags.Union | TypeFlags.Never)) && isTypeAssignableTo(funcType, globalFunctionType); } function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[]): Signature { @@ -16555,7 +16732,7 @@ namespace ts { // only the class declaration node will have the Abstract flag set. const valueDecl = expressionType.symbol && getClassLikeDeclarationOfSymbol(expressionType.symbol); if (valueDecl && hasModifier(valueDecl, ModifierFlags.Abstract)) { - error(node, Diagnostics.Cannot_create_an_instance_of_the_abstract_class_0, declarationNameToString(getNameOfDeclaration(valueDecl))); + error(node, Diagnostics.Cannot_create_an_instance_of_an_abstract_class); return resolveErrorCall(node); } @@ -16860,8 +17037,7 @@ namespace ts { * @returns On success, the expression's signature's return type. On failure, anyType. */ function checkCallExpression(node: CallExpression | NewExpression): Type { - // Grammar checking; stop grammar-checking if checkGrammarTypeArguments return true - checkGrammarTypeArguments(node, node.typeArguments) || checkGrammarArguments(node.arguments); + if (!checkGrammarTypeArguments(node, node.typeArguments)) checkGrammarArguments(node.arguments); const signature = getResolvedSignature(node); @@ -16908,7 +17084,7 @@ namespace ts { function checkImportCallExpression(node: ImportCall): Type { // Check grammar of dynamic import - checkGrammarArguments(node.arguments) || checkGrammarImportCallExpression(node); + if (!checkGrammarArguments(node.arguments)) checkGrammarImportCallExpression(node); if (node.arguments.length === 0) { return createPromiseReturnType(node, anyType); @@ -16958,7 +17134,7 @@ namespace ts { return type; } - function isCommonJsRequire(node: Node) { + function isCommonJsRequire(node: Node): boolean { if (!isRequireCall(node, /*checkArgumentIsStringLiteral*/ true)) { return false; } @@ -16982,7 +17158,7 @@ namespace ts { if (targetDeclarationKind !== SyntaxKind.Unknown) { const decl = getDeclarationOfKind(resolvedRequire, targetDeclarationKind); // function/variable declaration should be ambient - return isInAmbientContext(decl); + return !!(decl.flags & NodeFlags.Ambient); } return false; } @@ -17959,14 +18135,6 @@ namespace ts { return (target.flags & TypeFlags.Nullable) !== 0 || isTypeComparableTo(source, target); } - function getBestChoiceType(type1: Type, type2: Type): Type { - const firstAssignableToSecond = isTypeAssignableTo(type1, type2); - const secondAssignableToFirst = isTypeAssignableTo(type2, type1); - return secondAssignableToFirst && !firstAssignableToSecond ? type1 : - firstAssignableToSecond && !secondAssignableToFirst ? type2 : - getUnionType([type1, type2], /*subtypeReduction*/ true); - } - function checkBinaryExpression(node: BinaryExpression, checkMode?: CheckMode) { return checkBinaryLikeExpression(node.left, node.operatorToken, node.right, checkMode, node); } @@ -18103,7 +18271,7 @@ namespace ts { leftType; case SyntaxKind.BarBarToken: return getTypeFacts(leftType) & TypeFacts.Falsy ? - getBestChoiceType(removeDefinitelyFalsyTypes(leftType), rightType) : + getUnionType([removeDefinitelyFalsyTypes(leftType), rightType], /*subtypeReduction*/ true) : leftType; case SyntaxKind.EqualsToken: checkAssignmentOperator(rightType); @@ -18263,7 +18431,7 @@ namespace ts { checkExpression(node.condition); const type1 = checkExpression(node.whenTrue, checkMode); const type2 = checkExpression(node.whenFalse, checkMode); - return getBestChoiceType(type1, type2); + return getUnionType([type1, type2], /*subtypeReduction*/ true); } function checkTemplateExpression(node: TemplateExpression): Type { @@ -18549,6 +18717,8 @@ namespace ts { return checkJsxElement(node); case SyntaxKind.JsxSelfClosingElement: return checkJsxSelfClosingElement(node); + case SyntaxKind.JsxFragment: + return checkJsxFragment(node); case SyntaxKind.JsxAttributes: return checkJsxAttributes(node, checkMode); case SyntaxKind.JsxOpeningElement: @@ -18589,9 +18759,7 @@ namespace ts { // It is a SyntaxError if the Identifier "eval" or the Identifier "arguments" occurs as the // Identifier in a PropertySetParameterList of a PropertyAssignment that is contained in strict code // or if its FunctionBody is strict code(11.1.5). - - // Grammar checking - checkGrammarDecorators(node) || checkGrammarModifiers(node); + checkGrammarDecoratorsAndModifiers(node); checkVariableLikeDeclaration(node); const func = getContainingFunction(node); @@ -18900,7 +19068,7 @@ namespace ts { case "arguments": case "prototype": const message = Diagnostics.Static_property_0_conflicts_with_built_in_property_Function_0_of_constructor_function_1; - const className = getNameOfSymbol(getSymbolOfNode(node)); + const className = getNameOfSymbolAsWritten(getSymbolOfNode(node)); error(memberNameNode, message, memberName, className); break; } @@ -18981,14 +19149,13 @@ namespace ts { function checkPropertyDeclaration(node: PropertyDeclaration) { // Grammar checking - checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarProperty(node) || checkGrammarComputedPropertyName(node.name); - + if (!checkGrammarDecoratorsAndModifiers(node) && !checkGrammarProperty(node)) checkGrammarComputedPropertyName(node.name); checkVariableLikeDeclaration(node); } function checkMethodDeclaration(node: MethodDeclaration) { // Grammar checking - checkGrammarMethod(node) || checkGrammarComputedPropertyName(node.name); + if (!checkGrammarMethod(node)) checkGrammarComputedPropertyName(node.name); // Grammar checking for modifiers is done inside the function checkGrammarFunctionLikeDeclaration checkFunctionOrMethodDeclaration(node); @@ -19004,7 +19171,7 @@ namespace ts { // Grammar check on signature of constructor and modifier of the constructor is done in checkSignatureDeclaration function. checkSignatureDeclaration(node); // Grammar check for checking only related to constructorDeclaration - checkGrammarConstructorTypeParameters(node) || checkGrammarConstructorTypeAnnotation(node); + if (!checkGrammarConstructorTypeParameters(node)) checkGrammarConstructorTypeAnnotation(node); checkSourceElement(node.body); registerForUnusedIdentifiersCheck(node); @@ -19101,12 +19268,12 @@ namespace ts { function checkAccessorDeclaration(node: AccessorDeclaration) { if (produceDiagnostics) { // Grammar checking accessors - 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 (!isInAmbientContext(node) && 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); } @@ -19289,7 +19456,7 @@ namespace ts { } function isPrivateWithinAmbient(node: Node): boolean { - return hasModifier(node, ModifierFlags.Private) && isInAmbientContext(node); + return hasModifier(node, ModifierFlags.Private) && !!(node.flags & NodeFlags.Ambient); } function getEffectiveDeclarationFlags(n: Node, flagsToCheck: ModifierFlags): ModifierFlags { @@ -19300,7 +19467,7 @@ namespace ts { if (n.parent.kind !== SyntaxKind.InterfaceDeclaration && n.parent.kind !== SyntaxKind.ClassDeclaration && n.parent.kind !== SyntaxKind.ClassExpression && - isInAmbientContext(n)) { + n.flags & NodeFlags.Ambient) { if (!(flags & ModifierFlags.Ambient)) { // It is nested in an ambient context, which means it is automatically exported flags |= ModifierFlags.Export; @@ -19439,7 +19606,7 @@ namespace ts { let multipleConstructorImplementation = false; for (const current of declarations) { const node = current; - const inAmbientContext = isInAmbientContext(node); + const inAmbientContext = node.flags & NodeFlags.Ambient; const inAmbientContextOrInterface = node.parent.kind === SyntaxKind.InterfaceDeclaration || node.parent.kind === SyntaxKind.TypeLiteral || inAmbientContext; if (inAmbientContextOrInterface) { // check if declarations are consecutive only if they are non-ambient @@ -20095,6 +20262,10 @@ namespace ts { case SyntaxKind.Parameter: markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(node)); + const containingSignature = (node as ParameterDeclaration).parent; + for (const parameter of containingSignature.parameters) { + markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(parameter)); + } break; } } @@ -20280,21 +20451,20 @@ namespace ts { case SyntaxKind.MethodSignature: case SyntaxKind.CallSignature: case SyntaxKind.ConstructSignature: - case SyntaxKind.IndexSignature: case SyntaxKind.FunctionType: case SyntaxKind.ConstructorType: - checkUnusedTypeParameters(node); - break; case SyntaxKind.TypeAliasDeclaration: - checkUnusedTypeParameters(node); + checkUnusedTypeParameters(node); break; + default: + Debug.fail("Node should not have been registered for unused identifiers check"); } } } } function checkUnusedLocalsAndParameters(node: Node): void { - if (node.parent.kind !== SyntaxKind.InterfaceDeclaration && noUnusedIdentifiers && !isInAmbientContext(node)) { + if (noUnusedIdentifiers && !(node.flags & NodeFlags.Ambient)) { node.locals.forEach(local => { if (!local.isReferenced) { if (local.valueDeclaration && getRootDeclaration(local.valueDeclaration).kind === SyntaxKind.Parameter) { @@ -20347,7 +20517,7 @@ namespace ts { } function checkUnusedClassMembers(node: ClassDeclaration | ClassExpression): void { - if (compilerOptions.noUnusedLocals && !isInAmbientContext(node)) { + if (compilerOptions.noUnusedLocals && !(node.flags & NodeFlags.Ambient)) { if (node.members) { for (const member of node.members) { if (member.kind === SyntaxKind.MethodDeclaration || member.kind === SyntaxKind.PropertyDeclaration) { @@ -20368,7 +20538,7 @@ namespace ts { } function checkUnusedTypeParameters(node: ClassDeclaration | ClassExpression | FunctionDeclaration | MethodDeclaration | FunctionExpression | ArrowFunction | ConstructorDeclaration | SignatureDeclaration | InterfaceDeclaration | TypeAliasDeclaration) { - if (compilerOptions.noUnusedLocals && !isInAmbientContext(node)) { + if (compilerOptions.noUnusedLocals && !(node.flags & NodeFlags.Ambient)) { if (node.typeParameters) { // Only report errors on the last declaration for the type parameter container; // this ensures that all uses have been accounted for. @@ -20387,7 +20557,7 @@ namespace ts { } function checkUnusedModuleMembers(node: ModuleDeclaration | SourceFile): void { - if (compilerOptions.noUnusedLocals && !isInAmbientContext(node)) { + if (compilerOptions.noUnusedLocals && !(node.flags & NodeFlags.Ambient)) { node.locals.forEach(local => { if (!local.isReferenced && !local.exportSymbol) { for (const declaration of local.declarations) { @@ -20420,7 +20590,7 @@ namespace ts { function checkCollisionWithArgumentsInGeneratedCode(node: SignatureDeclaration) { // no rest parameters \ declaration context \ overload - no codegen impact - if (!hasRestParameter(node) || isInAmbientContext(node) || nodeIsMissing((node).body)) { + if (!hasRestParameter(node) || node.flags & NodeFlags.Ambient || nodeIsMissing((node).body)) { return; } @@ -20446,7 +20616,7 @@ namespace ts { return false; } - if (isInAmbientContext(node)) { + if (node.flags & NodeFlags.Ambient) { // ambient context - no codegen impact return false; } @@ -20511,7 +20681,7 @@ namespace ts { // bubble up and find containing type const enclosingClass = getContainingClass(node); // if containing type was not found or it is ambient - exit (no codegen) - if (!enclosingClass || isInAmbientContext(enclosingClass)) { + if (!enclosingClass || enclosingClass.flags & NodeFlags.Ambient) { return; } @@ -20864,8 +21034,7 @@ namespace ts { function checkVariableStatement(node: VariableStatement) { // Grammar checking - checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarVariableDeclarationList(node.declarationList) || checkGrammarForDisallowedLetOrConstStatement(node); - + if (!checkGrammarDecoratorsAndModifiers(node) && !checkGrammarVariableDeclarationList(node.declarationList)) checkGrammarForDisallowedLetOrConstStatement(node); forEach(node.declarationList.declarations, checkSourceElement); } @@ -21373,7 +21542,7 @@ namespace ts { function checkBreakOrContinueStatement(node: BreakOrContinueStatement) { // Grammar checking - checkGrammarStatementInAmbientContext(node) || checkGrammarBreakOrContinueStatement(node); + if (!checkGrammarStatementInAmbientContext(node)) checkGrammarBreakOrContinueStatement(node); // TODO: Check that target label is valid } @@ -21826,7 +21995,7 @@ namespace ts { checkClassForDuplicateDeclarations(node); // Only check for reserved static identifiers on non-ambient context. - if (!isInAmbientContext(node)) { + if (!(node.flags & NodeFlags.Ambient)) { checkClassForStaticPropertyNameConflicts(node); } @@ -22054,7 +22223,7 @@ namespace ts { function checkInterfaceDeclaration(node: InterfaceDeclaration) { // Grammar checking - checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarInterfaceDeclaration(node); + if (!checkGrammarDecoratorsAndModifiers(node)) checkGrammarInterfaceDeclaration(node); checkTypeParameters(node.typeParameters); if (produceDiagnostics) { @@ -22096,7 +22265,7 @@ namespace ts { function checkTypeAliasDeclaration(node: TypeAliasDeclaration) { // Grammar checking - checkGrammarDecorators(node) || checkGrammarModifiers(node); + checkGrammarDecoratorsAndModifiers(node); checkTypeNameIsReserved(node.name, Diagnostics.Type_alias_name_cannot_be_0); checkTypeParameters(node.typeParameters); @@ -22132,7 +22301,7 @@ namespace ts { } // In ambient enum declarations that specify no const modifier, enum member declarations that omit // a value are considered computed members (as opposed to having auto-incremented values). - if (isInAmbientContext(member.parent) && !isConst(member.parent)) { + if (member.parent.flags & NodeFlags.Ambient && !isConst(member.parent)) { return undefined; } // If the member declaration specifies no value, the member is considered a constant enum member. @@ -22165,7 +22334,7 @@ namespace ts { else if (isConstEnum) { error(initializer, Diagnostics.In_const_enum_declarations_member_initializer_must_be_constant_expression); } - else if (isInAmbientContext(member.parent)) { + else if (member.parent.flags & NodeFlags.Ambient) { error(initializer, Diagnostics.In_ambient_enum_declarations_member_initializer_must_be_constant_expression); } else { @@ -22266,7 +22435,7 @@ namespace ts { } // Grammar checking - checkGrammarDecorators(node) || checkGrammarModifiers(node); + checkGrammarDecoratorsAndModifiers(node); checkTypeNameIsReserved(node.name, Diagnostics.Enum_name_cannot_be_0); checkCollisionWithCapturedThisVariable(node, node.name); @@ -22278,7 +22447,7 @@ namespace ts { computeEnumMemberValues(node); const enumIsConst = isConst(node); - if (compilerOptions.isolatedModules && enumIsConst && isInAmbientContext(node)) { + if (compilerOptions.isolatedModules && enumIsConst && node.flags & NodeFlags.Ambient) { error(node.name, Diagnostics.Ambient_const_enums_are_not_allowed_when_the_isolatedModules_flag_is_provided); } @@ -22330,7 +22499,7 @@ namespace ts { for (const declaration of declarations) { if ((declaration.kind === SyntaxKind.ClassDeclaration || (declaration.kind === SyntaxKind.FunctionDeclaration && nodeIsPresent((declaration).body))) && - !isInAmbientContext(declaration)) { + !(declaration.flags & NodeFlags.Ambient)) { return declaration; } } @@ -22355,7 +22524,7 @@ namespace ts { if (produceDiagnostics) { // Grammar checking const isGlobalAugmentation = isGlobalScopeAugmentation(node); - const inAmbientContext = isInAmbientContext(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); } @@ -22369,7 +22538,7 @@ namespace ts { return; } - if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node)) { + if (!checkGrammarDecoratorsAndModifiers(node)) { if (!inAmbientContext && node.name.kind === SyntaxKind.StringLiteral) { grammarErrorOnNode(node.name, Diagnostics.Only_ambient_modules_can_use_quoted_names); } @@ -22574,7 +22743,7 @@ namespace ts { if (compilerOptions.isolatedModules && node.kind === SyntaxKind.ExportSpecifier && !(target.flags & SymbolFlags.Value) - && !isInAmbientContext(node)) { + && !(node.flags & NodeFlags.Ambient)) { error(node, Diagnostics.Cannot_re_export_a_type_when_the_isolatedModules_flag_is_provided); } } @@ -22592,7 +22761,7 @@ namespace ts { // If we hit an import declaration in an illegal context, just bail out to avoid cascading errors. return; } - if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && hasModifiers(node)) { + if (!checkGrammarDecoratorsAndModifiers(node) && hasModifiers(node)) { grammarErrorOnFirstToken(node, Diagnostics.An_import_declaration_cannot_have_modifiers); } if (checkExternalImportOrExportDeclaration(node)) { @@ -22619,13 +22788,13 @@ namespace ts { return; } - checkGrammarDecorators(node) || checkGrammarModifiers(node); + checkGrammarDecoratorsAndModifiers(node); if (isInternalModuleImportEqualsDeclaration(node) || checkExternalImportOrExportDeclaration(node)) { checkImportBinding(node); if (hasModifier(node, ModifierFlags.Export)) { markExportAsReferenced(node); } - if (isInternalModuleImportEqualsDeclaration(node)) { + if (node.moduleReference.kind !== SyntaxKind.ExternalModuleReference) { const target = resolveAlias(getSymbolOfNode(node)); if (target !== unknownSymbol) { if (target.flags & SymbolFlags.Value) { @@ -22641,7 +22810,7 @@ namespace ts { } } else { - if (modulekind >= ModuleKind.ES2015 && !isInAmbientContext(node)) { + if (modulekind >= ModuleKind.ES2015 && !(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); } @@ -22655,7 +22824,7 @@ namespace ts { return; } - if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && hasModifiers(node)) { + if (!checkGrammarDecoratorsAndModifiers(node) && hasModifiers(node)) { grammarErrorOnFirstToken(node, Diagnostics.An_export_declaration_cannot_have_modifiers); } @@ -22667,7 +22836,7 @@ namespace ts { const inAmbientExternalModule = node.parent.kind === SyntaxKind.ModuleBlock && isAmbientModule(node.parent.parent); const inAmbientNamespaceDeclaration = !inAmbientExternalModule && node.parent.kind === SyntaxKind.ModuleBlock && - !node.moduleSpecifier && isInAmbientContext(node); + !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); } @@ -22728,7 +22897,7 @@ namespace ts { return; } // Grammar checking - if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && hasModifiers(node)) { + if (!checkGrammarDecoratorsAndModifiers(node) && hasModifiers(node)) { grammarErrorOnFirstToken(node, Diagnostics.An_export_assignment_cannot_have_modifiers); } if (node.expression.kind === SyntaxKind.Identifier) { @@ -22740,11 +22909,11 @@ namespace ts { checkExternalModuleExports(container); - if (isInAmbientContext(node) && !isEntityNameExpression(node.expression)) { + 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); } - if (node.isExportEquals && !isInAmbientContext(node)) { + if (node.isExportEquals && !(node.flags & NodeFlags.Ambient)) { if (modulekind >= ModuleKind.ES2015) { // 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); @@ -22773,29 +22942,31 @@ namespace ts { } // Checks for export * conflicts const exports = getExportsOfModule(moduleSymbol); - exports && exports.forEach(({ declarations, flags }, id) => { - if (id === "__export") { - return; - } - // ECMA262: 15.2.1.1 It is a Syntax Error if the ExportedNames of ModuleItemList contains any duplicate entries. - // (TS Exceptions: namespaces, function overloads, enums, and interfaces) - if (flags & (SymbolFlags.Namespace | SymbolFlags.Interface | SymbolFlags.Enum)) { - return; - } - const exportedDeclarationsCount = countWhere(declarations, isNotOverloadAndNotAccessor); - 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) - return; - } - if (exportedDeclarationsCount > 1) { - for (const declaration of declarations) { - if (isNotOverload(declaration)) { - diagnostics.add(createDiagnosticForNode(declaration, Diagnostics.Cannot_redeclare_exported_variable_0, unescapeLeadingUnderscores(id))); + if (exports) { + exports.forEach(({ declarations, flags }, id) => { + if (id === "__export") { + return; + } + // ECMA262: 15.2.1.1 It is a Syntax Error if the ExportedNames of ModuleItemList contains any duplicate entries. + // (TS Exceptions: namespaces, function overloads, enums, and interfaces) + if (flags & (SymbolFlags.Namespace | SymbolFlags.Interface | SymbolFlags.Enum)) { + return; + } + const exportedDeclarationsCount = countWhere(declarations, isNotOverloadAndNotAccessor); + 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) + return; + } + if (exportedDeclarationsCount > 1) { + for (const declaration of declarations) { + if (isNotOverload(declaration)) { + diagnostics.add(createDiagnosticForNode(declaration, Diagnostics.Cannot_redeclare_exported_variable_0, unescapeLeadingUnderscores(id))); + } } } - } - }); + }); + } links.exportsChecked = true; } } @@ -23035,7 +23206,7 @@ namespace ts { checkDeferredNodes(); - if (isExternalModule(node)) { + if (isExternalOrCommonJsModule(node)) { registerForUnusedIdentifiersCheck(node); } @@ -23263,9 +23434,9 @@ namespace ts { return result; } - function isNodeWithinConstructor(node: Node, classDeclaration: ClassLikeDeclaration) { + function isNodeWithinConstructorOfClass(node: Node, classDeclaration: ClassLikeDeclaration) { return findAncestor(node, element => { - if (isConstructorDeclaration(element) && nodeIsPresent(element.body)) { + if (isConstructorDeclaration(element) && nodeIsPresent(element.body) && element.parent === classDeclaration) { return true; } else if (element === classDeclaration || isFunctionLikeDeclaration(element)) { @@ -23376,7 +23547,7 @@ namespace ts { return typeParameter && typeParameter.symbol; } - if (isPartOfExpression(entityName)) { + if (isExpressionNode(entityName)) { if (nodeIsMissing(entityName)) { // Missing entity name. return undefined; @@ -23508,6 +23679,8 @@ namespace ts { return objectType && getPropertyOfType(objectType, escapeLeadingUnderscores((node as StringLiteral | NumericLiteral).text)); case SyntaxKind.DefaultKeyword: + case SyntaxKind.FunctionKeyword: + case SyntaxKind.EqualsGreaterThanToken: return getSymbolOfNode(node.parent); default: @@ -23550,7 +23723,7 @@ namespace ts { return typeFromTypeNode; } - if (isPartOfExpression(node)) { + if (isExpressionNode(node)) { return getRegularTypeOfExpression(node); } @@ -24376,7 +24549,7 @@ namespace ts { function checkExternalEmitHelpers(location: Node, helpers: ExternalEmitHelpers) { if ((requestedExternalEmitHelpers & helpers) !== helpers && compilerOptions.importHelpers) { const sourceFile = getSourceFileOfNode(location); - if (isEffectiveExternalModule(sourceFile, compilerOptions) && !isInAmbientContext(location)) { + if (isEffectiveExternalModule(sourceFile, compilerOptions) && !(location.flags & NodeFlags.Ambient)) { const helpersModule = resolveHelpersModule(sourceFile, location); if (helpersModule !== unknownSymbol) { const uncheckedHelpers = helpers & ~requestedExternalEmitHelpers; @@ -24426,12 +24599,16 @@ namespace ts { } // GRAMMAR CHECKING + function checkGrammarDecoratorsAndModifiers(node: Node): boolean { + return checkGrammarDecorators(node) || checkGrammarModifiers(node); + } + function checkGrammarDecorators(node: Node): boolean { if (!node.decorators) { return false; } if (!nodeCanBeDecorated(node)) { - if (node.kind === SyntaxKind.MethodDeclaration && !ts.nodeIsPresent((node).body)) { + if (node.kind === SyntaxKind.MethodDeclaration && !nodeIsPresent((node).body)) { return grammarErrorOnFirstToken(node, Diagnostics.A_decorator_can_only_decorate_a_method_implementation_not_an_overload); } else { @@ -24578,7 +24755,7 @@ namespace ts { else if (node.kind === SyntaxKind.Parameter) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "declare"); } - else if (isInAmbientContext(node.parent) && node.parent.kind === SyntaxKind.ModuleBlock) { + 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); } flags |= ModifierFlags.Ambient; @@ -24614,7 +24791,7 @@ namespace ts { if (flags & ModifierFlags.Async) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "async"); } - else if (flags & ModifierFlags.Ambient || isInAmbientContext(node.parent)) { + else if (flags & ModifierFlags.Ambient || node.parent.flags & NodeFlags.Ambient) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "async"); } else if (node.kind === SyntaxKind.Parameter) { @@ -24781,7 +24958,7 @@ namespace ts { function checkGrammarFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean { // Prevent cascading error by short-circuit const file = getSourceFileOfNode(node); - return checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarTypeParameterList(node.typeParameters, file) || + return checkGrammarDecoratorsAndModifiers(node) || checkGrammarTypeParameterList(node.typeParameters, file) || checkGrammarParameterList(node.parameters) || checkGrammarArrowFunction(node, file); } @@ -24837,7 +25014,7 @@ namespace ts { function checkGrammarIndexSignature(node: SignatureDeclaration) { // Prevent cascading error by short-circuit - return checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarIndexSignatureParameters(node); + return checkGrammarDecoratorsAndModifiers(node) || checkGrammarIndexSignatureParameters(node); } function checkGrammarForAtLeastOneTypeArgument(node: Node, typeArguments: NodeArray): boolean { @@ -24888,7 +25065,7 @@ namespace ts { let seenExtendsClause = false; let seenImplementsClause = false; - if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && node.heritageClauses) { + if (!checkGrammarDecoratorsAndModifiers(node) && node.heritageClauses) { for (const heritageClause of node.heritageClauses) { if (heritageClause.token === SyntaxKind.ExtendsKeyword) { if (seenExtendsClause) { @@ -24962,7 +25139,7 @@ namespace ts { node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression || node.kind === SyntaxKind.MethodDeclaration); - if (isInAmbientContext(node)) { + if (node.flags & NodeFlags.Ambient) { return grammarErrorOnNode(node.asteriskToken, Diagnostics.Generators_are_not_allowed_in_an_ambient_context); } if (!node.body) { @@ -24978,11 +25155,13 @@ namespace ts { } function checkGrammarObjectLiteralExpression(node: ObjectLiteralExpression, inDestructuring: boolean) { - const seen = createUnderscoreEscapedMap(); - const Property = 1; - const GetAccessor = 2; - const SetAccessor = 4; - const GetOrSetAccessor = GetAccessor | SetAccessor; + const enum Flags { + Property = 1, + GetAccessor = 2, + SetAccessor = 4, + GetOrSetAccessor = GetAccessor | SetAccessor, + } + const seen = createUnderscoreEscapedMap(); for (const prop of node.properties) { if (prop.kind === SyntaxKind.SpreadAssignment) { @@ -25017,26 +25196,27 @@ namespace ts { // c.IsAccessorDescriptor(previous) is true and IsDataDescriptor(propId.descriptor) is true. // d.IsAccessorDescriptor(previous) is true and IsAccessorDescriptor(propId.descriptor) is true // and either both previous and propId.descriptor have[[Get]] fields or both previous and propId.descriptor have[[Set]] fields - let currentKind: number; - if (prop.kind === SyntaxKind.PropertyAssignment || prop.kind === SyntaxKind.ShorthandPropertyAssignment) { - // Grammar checking for computedPropertyName and shorthandPropertyAssignment - checkGrammarForInvalidQuestionMark((prop).questionToken, Diagnostics.An_object_member_cannot_be_declared_optional); - if (name.kind === SyntaxKind.NumericLiteral) { - checkGrammarNumericLiteral(name); - } - currentKind = Property; - } - else if (prop.kind === SyntaxKind.MethodDeclaration) { - currentKind = Property; - } - else if (prop.kind === SyntaxKind.GetAccessor) { - currentKind = GetAccessor; - } - else if (prop.kind === SyntaxKind.SetAccessor) { - currentKind = SetAccessor; - } - else { - Debug.assertNever(prop, "Unexpected syntax kind:" + (prop).kind); + let currentKind: Flags; + switch (prop.kind) { + case SyntaxKind.PropertyAssignment: + case SyntaxKind.ShorthandPropertyAssignment: + // Grammar checking for computedPropertyName and shorthandPropertyAssignment + checkGrammarForInvalidQuestionMark((prop).questionToken, Diagnostics.An_object_member_cannot_be_declared_optional); + if (name.kind === SyntaxKind.NumericLiteral) { + checkGrammarNumericLiteral(name); + } + // falls through + case SyntaxKind.MethodDeclaration: + currentKind = Flags.Property; + break; + case SyntaxKind.GetAccessor: + currentKind = Flags.GetAccessor; + break; + case SyntaxKind.SetAccessor: + currentKind = Flags.SetAccessor; + break; + default: + Debug.assertNever(prop, "Unexpected syntax kind:" + (prop).kind); } const effectiveName = getPropertyNameForPropertyNameNode(name); @@ -25049,11 +25229,11 @@ namespace ts { seen.set(effectiveName, currentKind); } else { - if (currentKind === Property && existingKind === Property) { + if (currentKind === Flags.Property && existingKind === Flags.Property) { grammarErrorOnNode(name, Diagnostics.Duplicate_identifier_0, getTextOfNode(name)); } - else if ((currentKind & GetOrSetAccessor) && (existingKind & GetOrSetAccessor)) { - if (existingKind !== GetOrSetAccessor && currentKind !== existingKind) { + else if ((currentKind & Flags.GetOrSetAccessor) && (existingKind & Flags.GetOrSetAccessor)) { + if (existingKind !== Flags.GetOrSetAccessor && currentKind !== existingKind) { seen.set(effectiveName, currentKind | existingKind); } else { @@ -25149,7 +25329,7 @@ namespace ts { if (languageVersion < ScriptTarget.ES5) { return grammarErrorOnNode(accessor.name, Diagnostics.Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher); } - else if (isInAmbientContext(accessor)) { + else if (accessor.flags & NodeFlags.Ambient) { return grammarErrorOnNode(accessor.name, Diagnostics.An_accessor_cannot_be_declared_in_an_ambient_context); } else if (accessor.body === undefined && !hasModifier(accessor, ModifierFlags.Abstract)) { @@ -25228,7 +25408,7 @@ namespace ts { // However, property declarations disallow computed names in general, // and accessors are not allowed in ambient contexts in general, // so this error only really matters for methods. - if (isInAmbientContext(node)) { + if (node.flags & NodeFlags.Ambient) { return checkGrammarForNonSymbolComputedProperty(node.name, Diagnostics.A_computed_property_name_in_an_ambient_context_must_directly_refer_to_a_built_in_symbol); } else if (!node.body) { @@ -25323,7 +25503,7 @@ namespace ts { function checkGrammarVariableDeclaration(node: VariableDeclaration) { if (node.parent.parent.kind !== SyntaxKind.ForInStatement && node.parent.parent.kind !== SyntaxKind.ForOfStatement) { - if (isInAmbientContext(node)) { + if (node.flags & NodeFlags.Ambient) { if (node.initializer) { if (isConst(node) && !node.type) { if (!isStringOrNumberLiteralExpression(node.initializer)) { @@ -25353,7 +25533,7 @@ namespace ts { } if (compilerOptions.module !== ModuleKind.ES2015 && compilerOptions.module !== ModuleKind.ESNext && compilerOptions.module !== ModuleKind.System && !compilerOptions.noEmit && - !isInAmbientContext(node.parent.parent) && hasModifier(node.parent.parent, ModifierFlags.Export)) { + !(node.parent.parent.flags & NodeFlags.Ambient) && hasModifier(node.parent.parent, ModifierFlags.Export)) { checkESModuleMarker(node.name); } @@ -25512,7 +25692,7 @@ namespace ts { } } - if (isInAmbientContext(node) && node.initializer) { + if (node.flags & NodeFlags.Ambient && node.initializer) { return grammarErrorOnFirstToken(node.initializer, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts); } } @@ -25555,11 +25735,11 @@ namespace ts { } function checkGrammarSourceFile(node: SourceFile): boolean { - return isInAmbientContext(node) && checkGrammarTopLevelElementsForRequiredDeclareModifier(node); + return !!(node.flags & NodeFlags.Ambient) && checkGrammarTopLevelElementsForRequiredDeclareModifier(node); } function checkGrammarStatementInAmbientContext(node: Node): boolean { - if (isInAmbientContext(node)) { + if (node.flags & NodeFlags.Ambient) { // An accessors is already reported about the ambient context if (isAccessor(node.parent)) { return getNodeLinks(node).hasReportedStatementInAmbientContext = true; @@ -25681,4 +25861,17 @@ namespace ts { return false; } } + + namespace JsxNames { + // tslint:disable variable-name + export const JSX = "JSX" as __String; + export const IntrinsicElements = "IntrinsicElements" as __String; + export const ElementClass = "ElementClass" as __String; + export const ElementAttributesPropertyNameContainer = "ElementAttributesProperty" as __String; + export const ElementChildrenAttributeNameContainer = "ElementChildrenAttribute" as __String; + export const Element = "Element" as __String; + export const IntrinsicAttributes = "IntrinsicAttributes" as __String; + export const IntrinsicClassAttributes = "IntrinsicClassAttributes" as __String; + // tslint:enable variable-name + } } diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index f050c4a5d16..43ea77c8020 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -76,13 +76,13 @@ namespace ts { name: "target", shortName: "t", type: createMapFromTemplate({ - "es3": ScriptTarget.ES3, - "es5": ScriptTarget.ES5, - "es6": ScriptTarget.ES2015, - "es2015": ScriptTarget.ES2015, - "es2016": ScriptTarget.ES2016, - "es2017": ScriptTarget.ES2017, - "esnext": ScriptTarget.ESNext, + es3: ScriptTarget.ES3, + es5: ScriptTarget.ES5, + es6: ScriptTarget.ES2015, + es2015: ScriptTarget.ES2015, + es2016: ScriptTarget.ES2016, + es2017: ScriptTarget.ES2017, + esnext: ScriptTarget.ESNext, }), paramType: Diagnostics.VERSION, showInSimplifiedHelpView: true, @@ -93,14 +93,14 @@ namespace ts { name: "module", shortName: "m", type: createMapFromTemplate({ - "none": ModuleKind.None, - "commonjs": ModuleKind.CommonJS, - "amd": ModuleKind.AMD, - "system": ModuleKind.System, - "umd": ModuleKind.UMD, - "es6": ModuleKind.ES2015, - "es2015": ModuleKind.ES2015, - "esnext": ModuleKind.ESNext + none: ModuleKind.None, + commonjs: ModuleKind.CommonJS, + amd: ModuleKind.AMD, + system: ModuleKind.System, + umd: ModuleKind.UMD, + es6: ModuleKind.ES2015, + es2015: ModuleKind.ES2015, + esnext: ModuleKind.ESNext }), paramType: Diagnostics.KIND, showInSimplifiedHelpView: true, @@ -141,6 +141,7 @@ namespace ts { "es2017.sharedmemory": "lib.es2017.sharedmemory.d.ts", "es2017.string": "lib.es2017.string.d.ts", "es2017.intl": "lib.es2017.intl.d.ts", + "es2017.typedarrays": "lib.es2017.typedarrays.d.ts", "esnext.asynciterable": "lib.esnext.asynciterable.d.ts", }), }, @@ -325,8 +326,8 @@ namespace ts { { name: "moduleResolution", type: createMapFromTemplate({ - "node": ModuleResolutionKind.NodeJs, - "classic": ModuleResolutionKind.Classic, + node: ModuleResolutionKind.NodeJs, + classic: ModuleResolutionKind.Classic, }), paramType: Diagnostics.STRATEGY, category: Diagnostics.Module_Resolution_Options, @@ -521,8 +522,8 @@ namespace ts { { name: "newLine", type: createMapFromTemplate({ - "crlf": NewLineKind.CarriageReturnLineFeed, - "lf": NewLineKind.LineFeed + crlf: NewLineKind.CarriageReturnLineFeed, + lf: NewLineKind.LineFeed }), paramType: Diagnostics.NEWLINE, category: Diagnostics.Advanced_Options, @@ -1138,6 +1139,13 @@ namespace ts { reportInvalidOptionValue(option && option.type !== "number"); return Number((valueExpression).text); + case SyntaxKind.PrefixUnaryExpression: + if ((valueExpression).operator !== SyntaxKind.MinusToken || (valueExpression).operand.kind !== SyntaxKind.NumericLiteral) { + break; // not valid JSON syntax + } + reportInvalidOptionValue(option && option.type !== "number"); + return -Number(((valueExpression).operand).text); + case SyntaxKind.ObjectLiteralExpression: reportInvalidOptionValue(option && option.type !== "object"); const objectLiteralExpression = valueExpression; diff --git a/src/compiler/comments.ts b/src/compiler/comments.ts index 025a4f36d26..1fec1e9562f 100644 --- a/src/compiler/comments.ts +++ b/src/compiler/comments.ts @@ -260,7 +260,7 @@ namespace ts { } } - 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 (!hasWrittenComment) { emitNewLineBeforeLeadingCommentOfPosition(currentLineMap, writer, rangePos, commentPos); hasWrittenComment = true; @@ -274,7 +274,7 @@ namespace ts { if (hasTrailingNewLine) { writer.writeLine(); } - else { + else if (kind === SyntaxKind.MultiLineCommentTrivia) { writer.write(" "); } } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 657f362067b..f3dd99ee5bf 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -20,12 +20,6 @@ namespace ts { /* @internal */ namespace ts { - - // More efficient to create a collator once and use its `compare` than to call `a.localeCompare(b)` many times. - export const collator: { compare(a: string, b: string): number } = typeof Intl === "object" && typeof Intl.Collator === "function" ? new Intl.Collator(/*locales*/ undefined, { usage: "sort", sensitivity: "accent" }) : undefined; - // Intl is missing in Safari, and node 0.10 treats "a" as greater than "B". - export const localeCompareIsCorrect = ts.collator && ts.collator.compare("a", "B") < 0; - /** Create a MapLike with good performance. */ function createDictionaryObject(): MapLike { const map = Object.create(/*prototype*/ null); // tslint:disable-line:no-null-keyword @@ -76,7 +70,7 @@ namespace ts { // The global Map object. This may not be available, so we must test for it. declare const Map: { new (): Map } | undefined; // Internet Explorer's Map doesn't support iteration, so don't use it. - // tslint:disable-next-line:no-in-operator + // tslint:disable-next-line no-in-operator variable-name const MapCtr = typeof Map !== "undefined" && "entries" in Map.prototype ? Map : shimMap(); // Keep the class inside a function so it doesn't get compiled if it's not used. @@ -165,12 +159,6 @@ namespace ts { return getCanonicalFileName(nonCanonicalizedPath); } - export const enum Comparison { - LessThan = -1, - EqualTo = 0, - GreaterThan = 1 - } - export function length(array: ReadonlyArray) { return array ? array.length : 0; } @@ -307,10 +295,10 @@ namespace ts { Debug.fail(); } - export function contains(array: ReadonlyArray, value: T): boolean { + export function contains(array: ReadonlyArray, value: T, equalityComparer: EqualityComparer = equateValues): boolean { if (array) { for (const v of array) { - if (v === value) { + if (equalityComparer(v, value)) { return true; } } @@ -655,24 +643,85 @@ namespace ts { return [...array1, ...array2]; } - // TODO: fixme (N^2) - add optional comparer so collection can be sorted before deduplication. - export function deduplicate(array: ReadonlyArray, areEqual?: (a: T, b: T) => boolean): T[] { - let result: T[]; - if (array) { - result = []; - loop: for (const item of array) { - for (const res of result) { - if (areEqual ? areEqual(res, item) : res === item) { - continue loop; - } - } - result.push(item); + function deduplicateRelational(array: ReadonlyArray, 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 = array.map((_, i) => i); + stableSortIndices(array, indices, comparer); + + let last = array[indices[0]]; + const deduplicated: number[] = [indices[0]]; + for (let i = 1; i < indices.length; i++) { + const index = indices[i]; + const item = array[index]; + if (!equalityComparer(last, item)) { + deduplicated.push(index); + last = item; } } + + // restore original order + deduplicated.sort(); + return deduplicated.map(i => array[i]); + } + + function deduplicateEquality(array: ReadonlyArray, equalityComparer: EqualityComparer) { + const result: T[] = []; + for (const item of array) { + pushIfUnique(result, item, equalityComparer); + } return result; } - export function arrayIsEqualTo(array1: ReadonlyArray, array2: ReadonlyArray, equaler?: (a: T, b: T) => boolean): boolean { + /** + * Deduplicates an unsorted array. + * @param equalityComparer An optional `EqualityComparer` used to determine if two values are duplicates. + * @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: ReadonlyArray, equalityComparer: EqualityComparer, comparer?: Comparer): T[] { + return !array ? undefined : + 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: ReadonlyArray, comparer: EqualityComparer | Comparer) { + if (!array) return undefined; + if (array.length === 0) return []; + + let last = array[0]; + const deduplicated: T[] = [last]; + for (let i = 1; i < array.length; i++) { + const next = array[i]; + switch (comparer(next, last)) { + // equality comparison + case true: + + // relational comparison + case Comparison.EqualTo: + continue; + + case Comparison.LessThan: + // If `array` is sorted, `next` should **never** be less than `last`. + return Debug.fail("Array is unsorted."); + } + + deduplicated.push(last = next); + } + + return deduplicated; + } + + export function sortAndDeduplicate(array: ReadonlyArray, comparer: Comparer, equalityComparer?: EqualityComparer) { + return deduplicateSorted(sort(array, comparer), equalityComparer || comparer); + } + + export function arrayIsEqualTo(array1: ReadonlyArray, array2: ReadonlyArray, equalityComparer: (a: T, b: T) => boolean = equateValues): boolean { if (!array1 || !array2) { return array1 === array2; } @@ -682,8 +731,7 @@ namespace ts { } for (let i = 0; i < array1.length; i++) { - const equals = equaler ? equaler(array1[i], array2[i]) : array1[i] === array2[i]; - if (!equals) { + if (!equalityComparer(array1[i], array2[i])) { return false; } } @@ -734,22 +782,44 @@ namespace ts { } /** - * Gets the relative complement of `arrayA` with respect to `b`, returning the elements that + * Gets the relative complement of `arrayA` with respect to `arrayB`, returning the elements that * 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 = compareValues, offsetA = 0, offsetB = 0): 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[] = []; - outer: for (; offsetB < arrayB.length; offsetB++) { - inner: for (; offsetA < arrayA.length; offsetA++) { + loopB: for (let offsetA = 0, offsetB = 0; offsetB < arrayB.length; offsetB++) { + if (offsetB > 0) { + // Ensure `arrayB` is properly sorted. + Debug.assertGreaterThanOrEqual(comparer(arrayB[offsetB], arrayB[offsetB - 1]), Comparison.EqualTo); + } + + loopA: for (const startA = offsetA; offsetA < arrayA.length; offsetA++) { + if (offsetA > startA) { + // Ensure `arrayA` is properly sorted. We only need to perform this check if + // `offsetA` has changed since we entered the loop. + Debug.assertGreaterThanOrEqual(comparer(arrayA[offsetA], arrayA[offsetA - 1]), Comparison.EqualTo); + } + switch (comparer(arrayB[offsetB], arrayA[offsetA])) { - case Comparison.LessThan: break inner; - case Comparison.EqualTo: continue outer; - case Comparison.GreaterThan: continue inner; + case Comparison.LessThan: + // If B is less than A, B does not exist in arrayA. Add B to the result and + // move to the next element in arrayB without changing the current position + // in arrayA. + result.push(arrayB[offsetB]); + continue loopB; + case Comparison.EqualTo: + // If B is equal to A, B exists in arrayA. Move to the next element in + // arrayB without adding B to the result or changing the current position + // in arrayA. + continue loopB; + case Comparison.GreaterThan: + // If B is greater than A, we need to keep looking for B in arrayA. Move to + // the next element in arrayA and recheck. + continue loopA; } } - result.push(arrayB[offsetB]); } return result; } @@ -802,8 +872,7 @@ namespace ts { start = start === undefined ? 0 : toOffset(from, start); end = end === undefined ? from.length : toOffset(from, end); for (let i = start; i < end && i < from.length; i++) { - const v = from[i]; - if (v !== undefined) { + if (from[i] !== undefined) { to.push(from[i]); } } @@ -813,8 +882,8 @@ namespace ts { /** * @return Whether the value was added. */ - export function pushIfUnique(array: T[], toAdd: T): boolean { - if (contains(array, toAdd)) { + export function pushIfUnique(array: T[], toAdd: T, equalityComparer?: EqualityComparer): boolean { + if (contains(array, toAdd, equalityComparer)) { return false; } else { @@ -826,9 +895,9 @@ namespace ts { /** * Unlike `pushIfUnique`, this can take `undefined` as an input, and returns a new array. */ - export function appendIfUnique(array: T[] | undefined, toAdd: T): T[] { + export function appendIfUnique(array: T[] | undefined, toAdd: T, equalityComparer?: EqualityComparer): T[] { if (array) { - pushIfUnique(array, toAdd); + pushIfUnique(array, toAdd, equalityComparer); return array; } else { @@ -836,14 +905,25 @@ namespace ts { } } + function stableSortIndices(array: ReadonlyArray, indices: number[], comparer: Comparer) { + // sort indices by value then position + indices.sort((x, y) => comparer(array[x], array[y]) || compareValues(x, y)); + } + + /** + * Returns a new sorted array. + */ + export function sort(array: ReadonlyArray, comparer: Comparer) { + return array.slice().sort(comparer); + } + /** * Stable sort of an array. Elements equal to each other maintain their relative position in the array. */ - export function stableSort(array: ReadonlyArray, comparer: Comparer = compareValues) { - return array - .map((_, i) => i) // create array of indices - .sort((x, y) => comparer(array[x], array[y]) || compareValues(x, y)) // sort indices by value then position - .map(i => array[i]); // get sorted array + export function stableSort(array: ReadonlyArray, comparer: Comparer) { + const indices = array.map((_, i) => i); + stableSortIndices(array, indices, comparer); + return indices.map(i => array[i]); } export function rangeEquals(array1: ReadonlyArray, array2: ReadonlyArray, pos: number, end: number) { @@ -921,38 +1001,37 @@ namespace ts { return result; } - export type Comparer = (a: T, b: T) => Comparison; - /** - * Performs a binary search, finding the index at which 'value' occurs in 'array'. + * Performs a binary search, finding the index at which `value` occurs in `array`. * If no such index is found, returns the 2's-complement of first index at which - * number[index] exceeds number. + * `array[index]` exceeds `value`. * @param array A sorted array whose first element must be no larger than number - * @param number The value to be searched for in the array. + * @param value The value to be searched for in the array. + * @param keySelector A callback used to select the search key from `value` and each element of + * `array`. + * @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: ReadonlyArray, value: T, comparer?: Comparer, offset?: number): number { + export function binarySearch(array: ReadonlyArray, value: T, keySelector: (v: T) => U, keyComparer: Comparer, offset?: number): number { if (!array || array.length === 0) { return -1; } let low = offset || 0; let high = array.length - 1; - comparer = comparer !== undefined - ? comparer - : (v1, v2) => (v1 < v2 ? -1 : (v1 > v2 ? 1 : 0)); - + const key = keySelector(value); while (low <= high) { const middle = low + ((high - low) >> 1); - const midValue = array[middle]; - - if (comparer(midValue, value) === 0) { - return middle; - } - else if (comparer(midValue, value) > 0) { - high = middle - 1; - } - else { - low = middle + 1; + const midKey = keySelector(array[middle]); + switch (keyComparer(midKey, key)) { + case Comparison.LessThan: + low = middle + 1; + break; + case Comparison.EqualTo: + return middle; + case Comparison.GreaterThan: + high = middle - 1; + break; } } @@ -985,32 +1064,6 @@ namespace ts { return initial; } - export function reduceRight(array: ReadonlyArray, f: (memo: U, value: T, i: number) => U, initial: U, start?: number, count?: number): U; - export function reduceRight(array: ReadonlyArray, f: (memo: T, value: T, i: number) => T): T; - export function reduceRight(array: T[], f: (memo: T, value: T, i: number) => T, initial?: T, start?: number, count?: number): T { - if (array) { - const size = array.length; - if (size > 0) { - let pos = start === undefined || start > size - 1 ? size - 1 : start; - const end = count === undefined || pos - count < 0 ? 0 : pos - count; - let result: T; - if (arguments.length <= 2) { - result = array[pos]; - pos--; - } - else { - result = initial; - } - while (pos >= end) { - result = f(result, array[pos], pos); - pos--; - } - return result; - } - } - return initial; - } - const hasOwnProperty = Object.prototype.hasOwnProperty; /** @@ -1130,13 +1183,13 @@ 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, right: MapLike, equalityComparer?: (left: T, right: T) => boolean) { + export function equalOwnProperties(left: MapLike, right: MapLike, equalityComparer: EqualityComparer = equateValues) { if (left === right) return true; if (!left || !right) return false; for (const key in left) { if (hasOwnProperty.call(left, key)) { if (!hasOwnProperty.call(right, key) === undefined) return false; - if (equalityComparer ? !equalityComparer(left[key], right[key]) : left[key] !== right[key]) return false; + if (!equalityComparer(left[key], right[key])) return false; } } @@ -1288,7 +1341,7 @@ namespace ts { } /** Does nothing. */ - export function noop(): void { } + export function noop(_?: {} | null | undefined): void { } // tslint:disable-line no-empty /** Do nothing and return false */ export function returnFalse(): false { return false; } @@ -1489,37 +1542,210 @@ namespace ts { return headChain; } - export function compareValues(a: T, b: T): Comparison { - if (a === b) return Comparison.EqualTo; - if (a === undefined) return Comparison.LessThan; - if (b === undefined) return Comparison.GreaterThan; - return a < b ? Comparison.LessThan : Comparison.GreaterThan; + export function equateValues(a: T, b: T) { + return a === b; } - export function compareStrings(a: string, b: string, ignoreCase?: boolean): Comparison { + /** + * Compare the equality of two strings using a case-sensitive ordinal comparison. + * + * Case-sensitive comparisons compare both strings one code-point at a time using the integer + * value of each code-point after applying `toUpperCase` to each string. We always map both + * strings to their upper-case form as some unicode characters do not properly round-trip to + * lowercase (such as `ẞ` (German sharp capital s)). + */ + export function equateStringsCaseInsensitive(a: string, b: string) { + return a === b + || a !== undefined + && b !== undefined + && a.toUpperCase() === b.toUpperCase(); + } + + /** + * Compare the equality of two strings using a case-sensitive ordinal comparison. + * + * Case-sensitive comparisons compare both strings one code-point at a time using the + * integer value of each code-point. + */ + export function equateStringsCaseSensitive(a: string, b: string) { + return equateValues(a, b); + } + + function compareComparableValues(a: string, b: string): Comparison; + function compareComparableValues(a: number, b: number): Comparison; + function compareComparableValues(a: string | number, b: string | number) { + return a === b ? Comparison.EqualTo : + a === undefined ? Comparison.LessThan : + b === undefined ? Comparison.GreaterThan : + a < b ? Comparison.LessThan : + Comparison.GreaterThan; + } + + /** + * Compare two numeric values for their order relative to each other. + * To compare strings, use any of the `compareStrings` functions. + */ + export function compareValues(a: number, b: number) { + return compareComparableValues(a, b); + } + + /** + * Compare two strings using a case-insensitive ordinal comparison. + * + * Ordinal comparisons are based on the difference between the unicode code points of both + * strings. Characters with multiple unicode representations are considered unequal. Ordinal + * comparisons provide predictable ordering, but place "a" after "B". + * + * Case-insensitive comparisons compare both strings one code-point at a time using the integer + * value of each code-point after applying `toUpperCase` to each string. We always map both + * strings to their upper-case form as some unicode characters do not properly round-trip to + * lowercase (such as `ẞ` (German sharp capital s)). + */ + export function compareStringsCaseInsensitive(a: string, b: string) { if (a === b) return Comparison.EqualTo; if (a === undefined) return Comparison.LessThan; if (b === undefined) return Comparison.GreaterThan; - if (ignoreCase) { - // Checking if "collator exists indicates that Intl is available. - // We still have to check if "collator.compare" is correct. If it is not, use "String.localeComapre" - if (collator) { - const result = localeCompareIsCorrect ? - collator.compare(a, b) : - a.localeCompare(b, /*locales*/ undefined, { usage: "sort", sensitivity: "accent" }); // accent means a ≠ b, a ≠ á, a = A - return result < 0 ? Comparison.LessThan : result > 0 ? Comparison.GreaterThan : Comparison.EqualTo; - } + a = a.toUpperCase(); + b = b.toUpperCase(); + return a < b ? Comparison.LessThan : a > b ? Comparison.GreaterThan : Comparison.EqualTo; + } - a = a.toUpperCase(); - b = b.toUpperCase(); + /** + * Compare two strings using a case-sensitive ordinal comparison. + * + * Ordinal comparisons are based on the difference between the unicode code points of both + * strings. Characters with multiple unicode representations are considered unequal. Ordinal + * comparisons provide predictable ordering, but place "a" after "B". + * + * Case-sensitive comparisons compare both strings one code-point at a time using the integer + * value of each code-point. + */ + export function compareStringsCaseSensitive(a: string, b: string) { + return compareComparableValues(a, b); + } + + /** + * Creates a string comparer for use with string collation in the UI. + */ + const createUIStringComparer = (() => { + let defaultComparer: Comparer | undefined; + let enUSComparer: Comparer | undefined; + + const stringComparerFactory = getStringComparerFactory(); + return createStringComparer; + + 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; + const value = comparer(a, b); + return value < 0 ? Comparison.LessThan : value > 0 ? Comparison.GreaterThan : Comparison.EqualTo; } - return a < b ? Comparison.LessThan : Comparison.GreaterThan; + function createIntlCollatorStringComparer(locale: string | undefined): Comparer { + // Intl.Collator.prototype.compare is bound to the collator. See NOTE in + // http://www.ecma-international.org/ecma-402/2.0/#sec-Intl.Collator.prototype.compare + const comparer = new Intl.Collator(locale, { usage: "sort", sensitivity: "variant" }).compare; + return (a, b) => compareWithCallback(a, b, comparer); + } + + function createLocaleCompareStringComparer(locale: string | undefined): Comparer { + // if the locale is not the default locale (`undefined`), use the fallback comparer. + if (locale !== undefined) return createFallbackStringComparer(); + + return (a, b) => compareWithCallback(a, b, compareStrings); + + function compareStrings(a: string, b: string) { + return a.localeCompare(b); + } + } + + function createFallbackStringComparer(): Comparer { + // An ordinal comparison puts "A" after "b", but for the UI we want "A" before "b". + // We first sort case insensitively. So "Aaa" will come before "baa". + // Then we sort case sensitively, so "aaa" will come before "Aaa". + // + // For case insensitive comparisons we always map both strings to their + // upper-case form as some unicode characters do not properly round-trip to + // lowercase (such as `ẞ` (German sharp capital s)). + return (a, b) => compareWithCallback(a, b, compareDictionaryOrder); + + function compareDictionaryOrder(a: string, b: string) { + return compareStrings(a.toUpperCase(), b.toUpperCase()) || compareStrings(a, b); + } + + function compareStrings(a: string, b: string) { + return a < b ? Comparison.LessThan : a > b ? Comparison.GreaterThan : Comparison.EqualTo; + } + } + + function getStringComparerFactory() { + // If the host supports Intl, we use it for comparisons using the default locale. + if (typeof Intl === "object" && typeof Intl.Collator === "function") { + return createIntlCollatorStringComparer; + } + + // 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) { + return createLocaleCompareStringComparer; + } + + // Otherwise, fall back to ordinal comparison: + return createFallbackStringComparer; + } + + function createStringComparer(locale: string | undefined) { + // Hold onto common string comparers. This avoids constantly reallocating comparers during + // tests. + if (locale === undefined) { + return defaultComparer || (defaultComparer = stringComparerFactory(locale)); + } + else if (locale === "en-US") { + return enUSComparer || (enUSComparer = stringComparerFactory(locale)); + } + else { + return stringComparerFactory(locale); + } + } + })(); + + let uiComparerCaseSensitive: Comparer | undefined; + let uiLocale: string | undefined; + + export function getUILocale() { + return uiLocale; } - export function compareStringsCaseInsensitive(a: string, b: string) { - return compareStrings(a, b, /*ignoreCase*/ true); + export function setUILocale(value: string) { + if (uiLocale !== value) { + uiLocale = value; + uiComparerCaseSensitive = undefined; + } + } + + /** + * Compare two strings in a using the case-sensitive sort behavior of the UI locale. + * + * Ordering is not predictable between different host locales, but is best for displaying + * ordered data for UI presentation. Characters with multiple unicode representations may + * be considered equal. + * + * Case-sensitive comparisons compare strings that differ in base characters, or + * accents/diacritic marks, or case as unequal. + */ + export function compareStringsCaseSensitiveUI(a: string, b: string) { + const comparer = uiComparerCaseSensitive || (uiComparerCaseSensitive = createUIStringComparer(uiLocale)); + return comparer(a, b); + } + + export function compareProperties(a: T, b: T, key: K, comparer: Comparer) { + return a === b ? Comparison.EqualTo : + a === undefined ? Comparison.LessThan : + b === undefined ? Comparison.GreaterThan : + comparer(a[key], b[key]); } function getDiagnosticFileName(diagnostic: Diagnostic): string { @@ -1527,7 +1753,7 @@ namespace ts { } export function compareDiagnostics(d1: Diagnostic, d2: Diagnostic): Comparison { - return compareValues(getDiagnosticFileName(d1), getDiagnosticFileName(d2)) || + return compareStringsCaseSensitive(getDiagnosticFileName(d1), getDiagnosticFileName(d2)) || compareValues(d1.start, d2.start) || compareValues(d1.length, d2.length) || compareValues(d1.code, d2.code) || @@ -1541,7 +1767,7 @@ namespace ts { const string1 = isString(text1) ? text1 : text1.messageText; const string2 = isString(text2) ? text2 : text2.messageText; - const res = compareValues(string1, string2); + const res = compareStringsCaseSensitive(string1, string2); if (res) { return res; } @@ -1559,27 +1785,8 @@ namespace ts { return text1 ? Comparison.GreaterThan : Comparison.LessThan; } - export function sortAndDeduplicateDiagnostics(diagnostics: Diagnostic[]): Diagnostic[] { - return deduplicateSortedDiagnostics(diagnostics.sort(compareDiagnostics)); - } - - export function deduplicateSortedDiagnostics(diagnostics: Diagnostic[]): Diagnostic[] { - if (diagnostics.length < 2) { - return diagnostics; - } - - const newDiagnostics = [diagnostics[0]]; - let previousDiagnostic = diagnostics[0]; - for (let i = 1; i < diagnostics.length; i++) { - const currentDiagnostic = diagnostics[i]; - const isDupe = compareDiagnostics(currentDiagnostic, previousDiagnostic) === Comparison.EqualTo; - if (!isDupe) { - newDiagnostics.push(currentDiagnostic); - previousDiagnostic = currentDiagnostic; - } - } - - return newDiagnostics; + export function sortAndDeduplicateDiagnostics(diagnostics: ReadonlyArray): Diagnostic[] { + return sortAndDeduplicate(diagnostics, compareDiagnostics); } export function normalizeSlashes(path: string): string { @@ -1600,7 +1807,6 @@ namespace ts { } if (path.charCodeAt(1) === CharacterCodes.colon) { if (path.charCodeAt(2) === CharacterCodes.slash) return 3; - return 2; } // Per RFC 1738 'file' URI schema has the shape file:/// // if is omitted then it is assumed that host value is 'localhost', @@ -1710,6 +1916,19 @@ namespace ts { return moduleResolution; } + export function getAllowSyntheticDefaultImports(compilerOptions: CompilerOptions) { + const moduleKind = getEmitModuleKind(compilerOptions); + return compilerOptions.allowSyntheticDefaultImports !== undefined + ? compilerOptions.allowSyntheticDefaultImports + : moduleKind === ModuleKind.System; + } + + export type StrictOptionName = "noImplicitAny" | "noImplicitThis" | "strictNullChecks" | "strictFunctionTypes" | "alwaysStrict"; + + export function getStrictOptionValue(compilerOptions: CompilerOptions, flag: StrictOptionName): boolean { + return compilerOptions[flag] === undefined ? compilerOptions.strict : compilerOptions[flag]; + } + export function hasZeroOrOneAsteriskCharacter(str: string): boolean { let seenAsterisk = false; for (let i = 0; i < str.length; i++) { @@ -1904,8 +2123,9 @@ namespace ts { const aComponents = getNormalizedPathComponents(a, currentDirectory); const bComponents = getNormalizedPathComponents(b, currentDirectory); const sharedLength = Math.min(aComponents.length, bComponents.length); + const comparer = ignoreCase ? compareStringsCaseInsensitive : compareStringsCaseSensitive; for (let i = 0; i < sharedLength; i++) { - const result = compareStrings(aComponents[i], bComponents[i], ignoreCase); + const result = comparer(aComponents[i], bComponents[i]); if (result !== Comparison.EqualTo) { return result; } @@ -1926,9 +2146,9 @@ namespace ts { return false; } + const equalityComparer = ignoreCase ? equateStringsCaseInsensitive : equateStringsCaseSensitive; for (let i = 0; i < parentComponents.length; i++) { - const result = compareStrings(parentComponents[i], childComponents[i], ignoreCase); - if (result !== Comparison.EqualTo) { + if (!equalityComparer(parentComponents[i], childComponents[i])) { return false; } } @@ -2173,6 +2393,7 @@ namespace ts { path = normalizePath(path); currentDirectory = normalizePath(currentDirectory); + const comparer = useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive; const patterns = getFileMatcherPatterns(path, excludes, includes, useCaseSensitiveFileNames, currentDirectory); const regexFlag = useCaseSensitiveFileNames ? "" : "i"; @@ -2184,7 +2405,6 @@ namespace ts { // If there are no "includes", then just put everything in results[0]. const results: string[][] = includeFileRegexes ? includeFileRegexes.map(() => []) : [[]]; - const comparer = useCaseSensitiveFileNames ? compareStrings : compareStringsCaseInsensitive; for (const basePath of patterns.basePaths) { visitDirectory(basePath, combinePaths(currentDirectory, basePath), depth); } @@ -2192,10 +2412,9 @@ namespace ts { return flatten(results); function visitDirectory(path: string, absolutePath: string, depth: number | undefined) { - let { files, directories } = getFileSystemEntries(path); - files = files.slice().sort(comparer); + const { files, directories } = getFileSystemEntries(path); - for (const current of files) { + for (const current of sort(files, comparer)) { const name = combinePaths(path, current); const absoluteName = combinePaths(absolutePath, current); if (extensions && !fileExtensionIsOneOf(name, extensions)) continue; @@ -2218,8 +2437,7 @@ namespace ts { } } - directories = directories.slice().sort(comparer); - for (const current of directories) { + for (const current of sort(directories, comparer)) { const name = combinePaths(path, current); const absoluteName = combinePaths(absolutePath, current); if ((!includeDirectoryRegex || includeDirectoryRegex.test(absoluteName)) && @@ -2249,7 +2467,7 @@ namespace ts { } // Sort the offsets array using either the literal or canonical path representations. - includeBasePaths.sort(useCaseSensitiveFileNames ? compareStrings : compareStringsCaseInsensitive); + includeBasePaths.sort(useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive); // Iterate over each include base path and include unique base paths that are not a // subpath of an existing base path @@ -2316,7 +2534,11 @@ namespace ts { if (!extraFileExtensions || extraFileExtensions.length === 0 || !needAllExtensions) { return needAllExtensions ? allSupportedExtensions : supportedTypeScriptExtensions; } - return deduplicate([...allSupportedExtensions, ...extraFileExtensions.map(e => e.extension)]); + return deduplicate( + [...allSupportedExtensions, ...extraFileExtensions.map(e => e.extension)], + equateStringsCaseSensitive, + compareStringsCaseSensitive + ); } export function hasJavaScriptFileExtension(fileName: string) { @@ -2448,8 +2670,7 @@ namespace ts { } } - function Signature() { - } + function Signature() {} // tslint:disable-line no-empty function Node(this: Node, kind: SyntaxKind, pos: number, end: number) { this.id = 0; @@ -2720,7 +2941,7 @@ namespace ts { return (arg: T) => f(arg) && g(arg); } - export function assertTypeIsNever(_: never): void { } + export function assertTypeIsNever(_: never): void { } // tslint:disable-line no-empty export interface FileAndDirectoryExistence { fileExists: boolean; @@ -2887,10 +3108,9 @@ namespace ts { function addOrDeleteFileOrDirectory(fileOrDirectory: string, fileOrDirectoryPath: Path) { const existingResult = getCachedFileSystemEntries(fileOrDirectoryPath); if (existingResult) { - // This was a folder already present, remove it if this doesnt exist any more - if (!host.directoryExists(fileOrDirectory)) { - cachedReadDirectoryResult.delete(fileOrDirectoryPath); - } + // Just clear the cache for now + // For now just clear the cache, since this could mean that multiple level entries might need to be re-evaluated + clearCache(); } else { // This was earlier a file (hence not in cached directory contents) @@ -2903,8 +3123,14 @@ namespace ts { fileExists: host.fileExists(fileOrDirectoryPath), directoryExists: host.directoryExists(fileOrDirectoryPath) }; - updateFilesOfFileSystemEntry(parentResult, baseName, fsQueryResult.fileExists); - updateFileSystemEntry(parentResult.directories, baseName, fsQueryResult.directoryExists); + if (fsQueryResult.directoryExists || hasEntry(parentResult.directories, baseName)) { + // Folder added or removed, clear the cache instead of updating the folder and its structure + clearCache(); + } + else { + // No need to update the directory structure, just files + updateFilesOfFileSystemEntry(parentResult, baseName, fsQueryResult.fileExists); + } return fsQueryResult; } } diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 48b97b048e9..3276e68b2ac 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -1429,45 +1429,40 @@ namespace ts { function getAccessorDeclarationTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic { let diagnosticMessage: DiagnosticMessage; if (accessorWithTypeAnnotation.kind === SyntaxKind.SetAccessor) { - // Setters have to have type named and cannot infer it so, the type should always be named - if (hasModifier(accessorWithTypeAnnotation.parent, ModifierFlags.Static)) { + // 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 (hasModifier(accessorWithTypeAnnotation, ModifierFlags.Static)) { diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - Diagnostics.Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_private_name_1; + 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_0_of_public_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_private_name_1; + 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; } - return { - diagnosticMessage, - errorNode: accessorWithTypeAnnotation.parameters[0], - // TODO(jfreeman): Investigate why we are passing node.name instead of node.parameters[0].name - typeName: accessorWithTypeAnnotation.name - }; } else { if (hasModifier(accessorWithTypeAnnotation, ModifierFlags.Static)) { diagnosticMessage = symbolAccessibilityResult.errorModuleName ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : - Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_private_module_1 : - Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_private_name_0; + 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_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : - Diagnostics.Return_type_of_public_property_getter_from_exported_class_has_or_is_using_name_0_from_private_module_1 : - Diagnostics.Return_type_of_public_property_getter_from_exported_class_has_or_is_using_private_name_0; + 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 { - diagnosticMessage, - errorNode: accessorWithTypeAnnotation.name, - typeName: undefined - }; } + return { + diagnosticMessage, + errorNode: accessorWithTypeAnnotation.name, + typeName: accessorWithTypeAnnotation.name + }; } } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 0f88d5e4ac5..964264ff6e8 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1716,7 +1716,7 @@ "category": "Error", "code": 2510 }, - "Cannot create an instance of the abstract class '{0}'.": { + "Cannot create an instance of an abstract class.": { "category": "Error", "code": 2511 }, @@ -2321,43 +2321,43 @@ "category": "Error", "code": 4033 }, - "Parameter '{0}' of public static property setter from exported class has or is using name '{1}' from private module '{2}'.": { + "Parameter type of public static setter '{0}' from exported class has or is using name '{1}' from private module '{2}'.": { "category": "Error", "code": 4034 }, - "Parameter '{0}' of public static property setter from exported class has or is using private name '{1}'.": { + "Parameter type of public static setter '{0}' from exported class has or is using private name '{1}'.": { "category": "Error", "code": 4035 }, - "Parameter '{0}' of public property setter from exported class has or is using name '{1}' from private module '{2}'.": { + "Parameter type of public setter '{0}' from exported class has or is using name '{1}' from private module '{2}'.": { "category": "Error", "code": 4036 }, - "Parameter '{0}' of public property setter from exported class has or is using private name '{1}'.": { + "Parameter type of public setter '{0}' from exported class has or is using private name '{1}'.": { "category": "Error", "code": 4037 }, - "Return type of public static property getter from exported class has or is using name '{0}' from external module {1} but cannot be named.": { + "Return type of public static getter '{0}' from exported class has or is using name '{1}' from external module {2} but cannot be named.": { "category": "Error", "code": 4038 }, - "Return type of public static property getter from exported class has or is using name '{0}' from private module '{1}'.": { + "Return type of public static getter '{0}' from exported class has or is using name '{1}' from private module '{2}'.": { "category": "Error", "code": 4039 }, - "Return type of public static property getter from exported class has or is using private name '{0}'.": { + "Return type of public static getter '{0}' from exported class has or is using private name '{1}'.": { "category": "Error", "code": 4040 }, - "Return type of public property getter from exported class has or is using name '{0}' from external module {1} but cannot be named.": { + "Return type of public getter '{0}' from exported class has or is using name '{1}' from external module {2} but cannot be named.": { "category": "Error", "code": 4041 }, - "Return type of public property getter from exported class has or is using name '{0}' from private module '{1}'.": { + "Return type of public getter '{0}' from exported class has or is using name '{1}' from private module '{2}'.": { "category": "Error", "code": 4042 }, - "Return type of public property getter from exported class has or is using private name '{0}'.": { + "Return type of public getter '{0}' from exported class has or is using private name '{1}'.": { "category": "Error", "code": 4043 }, @@ -3615,6 +3615,18 @@ "category": "Error", "code": 17013 }, + "JSX fragment has no corresponding closing tag.": { + "category": "Error", + "code": 17014 + }, + "Expected corresponding closing tag for JSX fragment.": { + "category": "Error", + "code": 17015 + }, + "JSX fragment is not supported when using --jsxFactory": { + "category": "Error", + "code":17016 + }, "Circularity detected while resolving configuration: {0}": { "category": "Error", @@ -3781,5 +3793,21 @@ "Infer parameter types from usage.": { "category": "Message", "code": 95012 + }, + "Convert to default import": { + "category": "Message", + "code": 95013 + }, + "Install '{0}'": { + "category": "Message", + "code": 95014 + }, + "Import '{0}' = require(\"{1}\").": { + "category": "Message", + "code": 95015 + }, + "Import * as '{0}' from \"{1}\".": { + "category": "Message", + "code": 95016 } } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 9ce220e723f..7a1d88d3bfd 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -699,9 +699,11 @@ namespace ts { case SyntaxKind.JsxText: return emitJsxText(node); case SyntaxKind.JsxOpeningElement: - return emitJsxOpeningElement(node); + case SyntaxKind.JsxOpeningFragment: + return emitJsxOpeningElementOrFragment(node); case SyntaxKind.JsxClosingElement: - return emitJsxClosingElement(node); + case SyntaxKind.JsxClosingFragment: + return emitJsxClosingElementOrFragment(node); case SyntaxKind.JsxAttribute: return emitJsxAttribute(node); case SyntaxKind.JsxAttributes: @@ -836,6 +838,8 @@ namespace ts { return emitJsxElement(node); case SyntaxKind.JsxSelfClosingElement: return emitJsxSelfClosingElement(node); + case SyntaxKind.JsxFragment: + return emitJsxFragment(node); // Transformation nodes case SyntaxKind.PartiallyEmittedExpression: @@ -1729,26 +1733,15 @@ namespace ts { increaseIndent(); } - if (getEmitFlags(node) & EmitFlags.ReuseTempVariableScope) { - emitSignatureHead(node); - if (onEmitNode) { - onEmitNode(EmitHint.Unspecified, body, emitBlockCallback); - } - else { - emitBlockFunctionBody(body); - } + pushNameGenerationScope(node); + emitSignatureHead(node); + if (onEmitNode) { + onEmitNode(EmitHint.Unspecified, body, emitBlockCallback); } else { - pushNameGenerationScope(); - emitSignatureHead(node); - if (onEmitNode) { - onEmitNode(EmitHint.Unspecified, body, emitBlockCallback); - } - else { - emitBlockFunctionBody(body); - } - popNameGenerationScope(); + emitBlockFunctionBody(body); } + popNameGenerationScope(node); if (indentedFlag) { decreaseIndent(); @@ -1867,11 +1860,9 @@ namespace ts { emitTypeParameters(node, node.typeParameters); emitList(node, node.heritageClauses, ListFormat.ClassHeritageClauses); - pushNameGenerationScope(); write(" {"); emitList(node, node.members, ListFormat.ClassMembers); write("}"); - popNameGenerationScope(); if (indentedFlag) { decreaseIndent(); @@ -1905,11 +1896,9 @@ namespace ts { emitModifiers(node, node.modifiers); write("enum "); emit(node.name); - pushNameGenerationScope(); write(" {"); emitList(node, node.members, ListFormat.EnumMembers); write("}"); - popNameGenerationScope(); } function emitModuleDeclaration(node: ModuleDeclaration) { @@ -1931,11 +1920,11 @@ namespace ts { } function emitModuleBlock(node: ModuleBlock) { - pushNameGenerationScope(); + pushNameGenerationScope(node); write("{"); emitBlockStatements(node, /*forceSingleLine*/ isEmptyBlock(node)); write("}"); - popNameGenerationScope(); + popNameGenerationScope(node); } function emitCaseBlock(node: CaseBlock) { @@ -2060,7 +2049,7 @@ namespace ts { function emitJsxElement(node: JsxElement) { emit(node.openingElement); - emitList(node, node.children, ListFormat.JsxElementChildren); + emitList(node, node.children, ListFormat.JsxElementOrFragmentChildren); emit(node.closingElement); } @@ -2075,14 +2064,24 @@ namespace ts { write("/>"); } - function emitJsxOpeningElement(node: JsxOpeningElement) { + function emitJsxFragment(node: JsxFragment) { + emit(node.openingFragment); + emitList(node, node.children, ListFormat.JsxElementOrFragmentChildren); + emit(node.closingFragment); + } + + function emitJsxOpeningElementOrFragment(node: JsxOpeningElement | JsxOpeningFragment) { write("<"); - emitJsxTagName(node.tagName); - writeIfAny(node.attributes.properties, " "); - // We are checking here so we won't re-enter the emitting pipeline and emit extra sourcemap - if (node.attributes.properties && node.attributes.properties.length > 0) { - emit(node.attributes); + + if (isJsxOpeningElement(node)) { + emitJsxTagName(node.tagName); + // We are checking here so we won't re-enter the emitting pipeline and emit extra sourcemap + if (node.attributes.properties && node.attributes.properties.length > 0) { + write(" "); + emit(node.attributes); + } } + write(">"); } @@ -2090,9 +2089,11 @@ namespace ts { writer.writeLiteral(getTextOfNode(node, /*includeTrivia*/ true)); } - function emitJsxClosingElement(node: JsxClosingElement) { + function emitJsxClosingElementOrFragment(node: JsxClosingElement | JsxClosingFragment) { write(""); } @@ -2268,11 +2269,11 @@ namespace ts { function emitSourceFileWorker(node: SourceFile) { const statements = node.statements; - pushNameGenerationScope(); + pushNameGenerationScope(node); emitHelpersIndirect(node); const index = findIndex(statements, statement => !isPrologueDirective(statement)); emitList(node, statements, ListFormat.MultiLine, index === -1 ? statements.length : index); - popNameGenerationScope(); + popNameGenerationScope(node); } // Transformation nodes @@ -2611,12 +2612,6 @@ namespace ts { writer.decreaseIndent(); } - function writeIfAny(nodes: NodeArray, text: string) { - if (some(nodes)) { - write(text); - } - } - function writeToken(token: SyntaxKind, pos: number, contextNode?: Node) { return onEmitSourceMapOfToken ? onEmitSourceMapOfToken(contextNode, token, pos, writeTokenText) @@ -2651,8 +2646,8 @@ namespace ts { function writeLines(text: string): void { const lines = text.split(/\r\n?|\n/g); const indentation = guessIndentation(lines); - for (let i = 0; i < lines.length; i++) { - const line = indentation ? lines[i].slice(indentation) : lines[i]; + for (const lineText of lines) { + const line = indentation ? lineText.slice(indentation) : lineText; if (line.length) { writeLine(); write(line); @@ -2741,7 +2736,7 @@ namespace ts { } } else { - return nextNode.startsOnNewLine; + return getStartsOnNewLine(nextNode); } } @@ -2772,7 +2767,7 @@ namespace ts { function synthesizedNodeStartsOnNewLine(node: Node, format?: ListFormat) { if (nodeIsSynthesized(node)) { - const startsOnNewLine = node.startsOnNewLine; + const startsOnNewLine = getStartsOnNewLine(node); if (startsOnNewLine === undefined) { return (format & ListFormat.PreferNewLine) !== 0; } @@ -2789,7 +2784,7 @@ namespace ts { node2 = skipSynthesizedParentheses(node2); // Always use a newline for synthesized code if the synthesizer desires it. - if (node2.startsOnNewLine) { + if (getStartsOnNewLine(node2)) { return true; } @@ -2848,7 +2843,10 @@ namespace ts { /** * Push a new name generation scope. */ - function pushNameGenerationScope() { + function pushNameGenerationScope(node: Node | undefined) { + if (node && getEmitFlags(node) & EmitFlags.ReuseTempVariableScope) { + return; + } tempFlagsStack.push(tempFlags); tempFlags = 0; } @@ -2856,7 +2854,10 @@ namespace ts { /** * Pop the current name generation scope. */ - function popNameGenerationScope() { + function popNameGenerationScope(node: Node | undefined) { + if (node && getEmitFlags(node) & EmitFlags.ReuseTempVariableScope) { + return; + } tempFlags = tempFlagsStack.pop(); } @@ -2867,8 +2868,17 @@ namespace ts { if (name.autoGenerateKind === GeneratedIdentifierKind.Node) { // Node names generate unique names based on their original node // and are cached based on that node's id. - const node = getNodeForGeneratedName(name); - return generateNameCached(node); + if (name.skipNameGenerationScope) { + const savedTempFlags = tempFlags; + popNameGenerationScope(/*node*/ undefined); + const result = generateNameCached(getNodeForGeneratedName(name)); + pushNameGenerationScope(/*node*/ undefined); + tempFlags = savedTempFlags; + return result; + } + else { + return generateNameCached(getNodeForGeneratedName(name)); + } } else { // Auto, Loop, and Unique names are cached based on their unique @@ -3176,7 +3186,7 @@ namespace ts { EnumMembers = CommaDelimited | Indented | MultiLine, CaseBlockClauses = Indented | MultiLine, NamedImportsOrExportsElements = CommaDelimited | SpaceBetweenSiblings | AllowTrailingComma | SingleLine | SpaceBetweenBraces, - JsxElementChildren = SingleLine | NoInterveningComments, + JsxElementOrFragmentChildren = SingleLine | NoInterveningComments, JsxElementAttributes = SingleLine | SpaceBetweenSiblings | NoInterveningComments, CaseOrDefaultClauseStatements = Indented | MultiLine | NoTrailingNewLine | OptionalIfEmpty, HeritageClauseTypes = CommaDelimited | SpaceBetweenSiblings | SingleLine, diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 65c1c92f366..e8dfcbc1e94 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -13,9 +13,6 @@ namespace ts { if (updated !== original) { setOriginalNode(updated, original); setTextRange(updated, original); - if (original.startsOnNewLine) { - updated.startsOnNewLine = true; - } aggregateTransformFlags(updated); } return updated; @@ -73,11 +70,10 @@ namespace ts { // Literals - export function createLiteral(value: string): StringLiteral; + /** If a node is passed, creates a string literal whose source text is read from a source node during emit. */ + export function createLiteral(value: string | StringLiteral | NumericLiteral | Identifier): StringLiteral; export function createLiteral(value: number): NumericLiteral; export function createLiteral(value: boolean): BooleanLiteral; - /** Create a string literal whose source text is read from a source node during emit. */ - export function createLiteral(sourceNode: StringLiteral | NumericLiteral | Identifier): StringLiteral; export function createLiteral(value: string | number | boolean): PrimaryExpression; export function createLiteral(value: string | number | boolean | StringLiteral | NumericLiteral | Identifier): PrimaryExpression { if (typeof value === "number") { @@ -116,6 +112,7 @@ namespace ts { export function createIdentifier(text: string): Identifier; /* @internal */ + // tslint:disable-next-line unified-signatures export function createIdentifier(text: string, typeArguments: ReadonlyArray): Identifier; export function createIdentifier(text: string, typeArguments?: ReadonlyArray): Identifier { const node = createSynthesizedNode(SyntaxKind.Identifier); @@ -168,11 +165,15 @@ namespace ts { } /** Create a unique name generated for a node. */ - export function getGeneratedNameForNode(node: Node): Identifier { + export function getGeneratedNameForNode(node: Node): Identifier; + // tslint:disable-next-line unified-signatures + /*@internal*/ export function getGeneratedNameForNode(node: Node, shouldSkipNameGenerationScope?: boolean): Identifier; + export function getGeneratedNameForNode(node: Node, shouldSkipNameGenerationScope?: boolean): Identifier { const name = createIdentifier(""); name.autoGenerateKind = GeneratedIdentifierKind.Node; name.autoGenerateId = nextAutoGenerateId; name.original = node; + name.skipNameGenerationScope = !!shouldSkipNameGenerationScope; nextAutoGenerateId++; return name; } @@ -1982,7 +1983,7 @@ namespace ts { node.decorators = asNodeArray(decorators); node.modifiers = asNodeArray(modifiers); node.isExportEquals = isExportEquals; - node.expression = expression; + node.expression = isExportEquals ? parenthesizeBinaryOperand(SyntaxKind.EqualsToken, expression, /*isLeftSideOfBinary*/ false, /*leftOperand*/ undefined) : parenthesizeDefaultExpression(expression); return node; } @@ -2115,6 +2116,22 @@ namespace ts { : node; } + export function createJsxFragment(openingFragment: JsxOpeningFragment, children: ReadonlyArray, closingFragment: JsxClosingFragment) { + const node = createSynthesizedNode(SyntaxKind.JsxFragment); + node.openingFragment = openingFragment; + node.children = createNodeArray(children); + node.closingFragment = closingFragment; + return node; + } + + export function updateJsxFragment(node: JsxFragment, openingFragment: JsxOpeningFragment, children: ReadonlyArray, closingFragment: JsxClosingFragment) { + return node.openingFragment !== openingFragment + || node.children !== children + || node.closingFragment !== closingFragment + ? updateNode(createJsxFragment(openingFragment, children, closingFragment), node) + : node; + } + export function createJsxAttribute(name: Identifier, initializer: StringLiteral | JsxExpression) { const node = createSynthesizedNode(SyntaxKind.JsxAttribute); node.name = name; @@ -2625,7 +2642,7 @@ namespace ts { /** * Gets a custom text range to use when emitting source maps. */ - export function getSourceMapRange(node: Node) { + export function getSourceMapRange(node: Node): SourceMapRange { const emitNode = node.emitNode; return (emitNode && emitNode.sourceMapRange) || node; } @@ -2638,6 +2655,7 @@ namespace ts { return node; } + // tslint:disable-next-line variable-name let SourceMapSource: new (fileName: string, text: string, skipTrivia?: (pos: number) => number) => SourceMapSource; /** @@ -2666,6 +2684,24 @@ namespace ts { return node; } + /** + * Gets a custom text range to use when emitting comments. + */ + /*@internal*/ + export function getStartsOnNewLine(node: Node) { + const emitNode = node.emitNode; + return emitNode && emitNode.startsOnNewLine; + } + + /** + * Sets a custom text range to use when emitting comments. + */ + /*@internal*/ + export function setStartsOnNewLine(node: T, newLine: boolean) { + getOrCreateEmitNode(node).startsOnNewLine = newLine; + return node; + } + /** * Gets a custom text range to use when emitting comments. */ @@ -2824,7 +2860,8 @@ namespace ts { sourceMapRange, tokenSourceMapRanges, constantValue, - helpers + helpers, + startsOnNewLine, } = sourceEmitNode; if (!destEmitNode) destEmitNode = {}; // We are using `.slice()` here in case `destEmitNode.leadingComments` is pushed to later. @@ -2836,6 +2873,7 @@ namespace ts { if (tokenSourceMapRanges) destEmitNode.tokenSourceMapRanges = mergeTokenSourceMapRanges(tokenSourceMapRanges, destEmitNode.tokenSourceMapRanges); if (constantValue !== undefined) destEmitNode.constantValue = constantValue; if (helpers) destEmitNode.helpers = addRange(destEmitNode.helpers, helpers); + if (startsOnNewLine !== undefined) destEmitNode.startsOnNewLine = startsOnNewLine; return destEmitNode; } @@ -2951,7 +2989,7 @@ namespace ts { ); } - function createReactNamespace(reactNamespace: string, parent: JsxOpeningLikeElement) { + function createReactNamespace(reactNamespace: string, parent: JsxOpeningLikeElement | JsxOpeningFragment) { // To ensure the emit resolver can properly resolve the namespace, we need to // treat this identifier as if it were a source tree node by clearing the `Synthesized` // flag and setting a parent node. @@ -2963,7 +3001,7 @@ namespace ts { return react; } - function createJsxFactoryExpressionFromEntityName(jsxFactory: EntityName, parent: JsxOpeningLikeElement): Expression { + function createJsxFactoryExpressionFromEntityName(jsxFactory: EntityName, parent: JsxOpeningLikeElement | JsxOpeningFragment): Expression { if (isQualifiedName(jsxFactory)) { const left = createJsxFactoryExpressionFromEntityName(jsxFactory.left, parent); const right = createIdentifier(idText(jsxFactory.right)); @@ -2975,7 +3013,7 @@ namespace ts { } } - function createJsxFactoryExpression(jsxFactoryEntity: EntityName, reactNamespace: string, parent: JsxOpeningLikeElement): Expression { + function createJsxFactoryExpression(jsxFactoryEntity: EntityName, reactNamespace: string, parent: JsxOpeningLikeElement | JsxOpeningFragment): Expression { return jsxFactoryEntity ? createJsxFactoryExpressionFromEntityName(jsxFactoryEntity, parent) : createPropertyAccess( @@ -2997,7 +3035,38 @@ namespace ts { if (children.length > 1) { for (const child of children) { - child.startsOnNewLine = true; + startOnNewLine(child); + argumentsList.push(child); + } + } + else { + argumentsList.push(children[0]); + } + } + + return setTextRange( + createCall( + createJsxFactoryExpression(jsxFactoryEntity, reactNamespace, parentElement), + /*typeArguments*/ undefined, + argumentsList + ), + location + ); + } + + export function createExpressionForJsxFragment(jsxFactoryEntity: EntityName, reactNamespace: string, children: Expression[], parentElement: JsxOpeningFragment, location: TextRange): LeftHandSideExpression { + const tagName = createPropertyAccess( + createReactNamespace(reactNamespace, parentElement), + "Fragment" + ); + + const argumentsList = [tagName]; + argumentsList.push(createNull()); + + if (children && children.length > 0) { + if (children.length > 1) { + for (const child of children) { + startOnNewLine(child); argumentsList.push(child); } } @@ -3572,8 +3641,8 @@ namespace ts { ); setOriginalNode(updated, node); setTextRange(updated, node); - if (node.startsOnNewLine) { - updated.startsOnNewLine = true; + if (getStartsOnNewLine(node)) { + setStartsOnNewLine(updated, /*newLine*/ true); } aggregateTransformFlags(updated); return updated; @@ -3885,6 +3954,27 @@ namespace ts { : e; } + /** + * [Per the spec](https://tc39.github.io/ecma262/#prod-ExportDeclaration), `export default` accepts _AssigmentExpression_ but + * has a lookahead restriction for `function`, `async function`, and `class`. + * + * Basically, that means we need to parenthesize in the following cases: + * + * - BinaryExpression of CommaToken + * - CommaList (synthetic list of multiple comma expressions) + * - FunctionExpression + * - ClassExpression + */ + export function parenthesizeDefaultExpression(e: Expression) { + const check = skipPartiallyEmittedExpressions(e); + return (check.kind === SyntaxKind.ClassExpression || + check.kind === SyntaxKind.FunctionExpression || + check.kind === SyntaxKind.CommaListExpression || + isBinaryExpression(check) && check.operatorToken.kind === SyntaxKind.CommaToken) + ? createParen(e) + : e; + } + /** * Wraps an expression in parentheses if it is needed in order to use the expression * as the expression of a NewExpression node. @@ -4181,8 +4271,7 @@ namespace ts { } export function startOnNewLine(node: T): T { - node.startsOnNewLine = true; - return node; + return setStartsOnNewLine(node, /*newLine*/ true); } export function getExternalHelpersModuleName(node: SourceFile) { @@ -4230,7 +4319,7 @@ namespace ts { const namespaceDeclaration = getNamespaceDeclarationNode(node); if (namespaceDeclaration && !isDefaultImport(node)) { const name = namespaceDeclaration.name; - return isGeneratedIdentifier(name) ? name : createIdentifier(getSourceTextOfNodeFromSourceFile(sourceFile, namespaceDeclaration.name)); + return isGeneratedIdentifier(name) ? name : createIdentifier(getSourceTextOfNodeFromSourceFile(sourceFile, name) || idText(name)); } if (node.kind === SyntaxKind.ImportDeclaration && (node).importClause) { return getGeneratedNameForNode(node); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index b27d4811ecb..79b5eb30c49 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -12,10 +12,12 @@ namespace ts { JSDoc = 1 << 5, } + // tslint:disable variable-name let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; let IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; + // tslint:enable variable-name export function createNode(kind: SyntaxKind, pos?: number, end?: number): Node { if (kind === SyntaxKind.SourceFile) { @@ -377,6 +379,10 @@ namespace ts { return visitNode(cbNode, (node).openingElement) || visitNodes(cbNode, cbNodes, (node).children) || visitNode(cbNode, (node).closingElement); + case SyntaxKind.JsxFragment: + return visitNode(cbNode, (node).openingFragment) || + visitNodes(cbNode, cbNodes, (node).children) || + visitNode(cbNode, (node).closingFragment); case SyntaxKind.JsxSelfClosingElement: case SyntaxKind.JsxOpeningElement: return visitNode(cbNode, (node).tagName) || @@ -520,10 +526,12 @@ namespace ts { const disallowInAndDecoratorContext = NodeFlags.DisallowInContext | NodeFlags.DecoratorContext; // capture constructors in 'initializeState' to avoid null checks + // tslint:disable variable-name let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; let IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; + // tslint:enable variable-name let sourceFile: SourceFile; let parseDiagnostics: Diagnostic[]; @@ -627,6 +635,7 @@ namespace ts { } export function parseIsolatedEntityName(content: string, languageVersion: ScriptTarget): EntityName { + // Choice of `isDeclarationFile` should be arbitrary initializeState(content, languageVersion, /*syntaxCursor*/ undefined, ScriptKind.JS); // Prime the scanner. nextToken(); @@ -639,7 +648,7 @@ namespace ts { export function parseJsonText(fileName: string, sourceText: string): JsonSourceFile { initializeState(sourceText, ScriptTarget.ES2015, /*syntaxCursor*/ undefined, ScriptKind.JSON); // Set source file so that errors will be reported with this file name - sourceFile = createSourceFile(fileName, ScriptTarget.ES2015, ScriptKind.JSON); + sourceFile = createSourceFile(fileName, ScriptTarget.ES2015, ScriptKind.JSON, /*isDeclaration*/ false); const result = sourceFile; // Prime the scanner. @@ -681,7 +690,16 @@ namespace ts { identifierCount = 0; nodeCount = 0; - contextFlags = scriptKind === ScriptKind.JS || scriptKind === ScriptKind.JSX || scriptKind === ScriptKind.JSON ? NodeFlags.JavaScriptFile : NodeFlags.None; + switch (scriptKind) { + case ScriptKind.JS: + case ScriptKind.JSX: + case ScriptKind.JSON: + contextFlags = NodeFlags.JavaScriptFile; + break; + default: + contextFlags = NodeFlags.None; + break; + } parseErrorBeforeNextFinishedNode = false; // Initialize and prime the scanner before parsing the source elements. @@ -705,7 +723,12 @@ namespace ts { } function parseSourceFileWorker(fileName: string, languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind): SourceFile { - sourceFile = createSourceFile(fileName, languageVersion, scriptKind); + const isDeclarationFile = isDeclarationFileName(fileName); + if (isDeclarationFile) { + contextFlags |= NodeFlags.Ambient; + } + + sourceFile = createSourceFile(fileName, languageVersion, scriptKind, isDeclarationFile); sourceFile.flags = contextFlags; // Prime the scanner. @@ -782,7 +805,7 @@ namespace ts { } } - function createSourceFile(fileName: string, languageVersion: ScriptTarget, scriptKind: ScriptKind): SourceFile { + function createSourceFile(fileName: string, languageVersion: ScriptTarget, scriptKind: ScriptKind, isDeclarationFile: boolean): SourceFile { // code from createNode is inlined here so createNode won't have to deal with special case of creating source files // this is quite rare comparing to other nodes and createNode should be as fast as possible const sourceFile = new SourceFileConstructor(SyntaxKind.SourceFile, /*pos*/ 0, /* end */ sourceText.length); @@ -793,7 +816,7 @@ namespace ts { sourceFile.languageVersion = languageVersion; sourceFile.fileName = normalizePath(fileName); sourceFile.languageVariant = getLanguageVariant(scriptKind); - sourceFile.isDeclarationFile = fileExtensionIs(sourceFile.fileName, Extension.Dts); + sourceFile.isDeclarationFile = isDeclarationFile; sourceFile.scriptKind = scriptKind; return sourceFile; @@ -1423,6 +1446,11 @@ namespace ts { return tokenIsIdentifierOrKeyword(token()); } + function nextTokenIsIdentifierOrKeywordOrGreaterThan() { + nextToken(); + return tokenIsIdentifierOrKeywordOrGreaterThan(token()); + } + function isHeritageClauseExtendsOrImplementsKeyword(): boolean { if (token() === SyntaxKind.ImplementsKeyword || token() === SyntaxKind.ExtendsKeyword) { @@ -3802,9 +3830,9 @@ namespace ts { node.operand = parseLeftHandSideExpressionOrHigher(); return finishNode(node); } - else if (sourceFile.languageVariant === LanguageVariant.JSX && token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsIdentifierOrKeyword)) { + else if (sourceFile.languageVariant === LanguageVariant.JSX && token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsIdentifierOrKeywordOrGreaterThan)) { // JSXElement is part of primaryExpression - return parseJsxElementOrSelfClosingElement(/*inExpressionContext*/ true); + return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true); } const expression = parseLeftHandSideExpressionOrHigher(); @@ -3959,14 +3987,14 @@ namespace ts { } - function parseJsxElementOrSelfClosingElement(inExpressionContext: boolean): JsxElement | JsxSelfClosingElement { - const opening = parseJsxOpeningOrSelfClosingElement(inExpressionContext); - let result: JsxElement | JsxSelfClosingElement; + function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean): JsxElement | JsxSelfClosingElement | JsxFragment { + const opening = parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext); + let result: JsxElement | JsxSelfClosingElement | JsxFragment; if (opening.kind === SyntaxKind.JsxOpeningElement) { const node = createNode(SyntaxKind.JsxElement, opening.pos); node.openingElement = opening; - node.children = parseJsxChildren(node.openingElement.tagName); + node.children = parseJsxChildren(node.openingElement); node.closingElement = parseJsxClosingElement(inExpressionContext); if (!tagNamesAreEquivalent(node.openingElement.tagName, node.closingElement.tagName)) { @@ -3975,6 +4003,14 @@ namespace ts { result = finishNode(node); } + else if (opening.kind === SyntaxKind.JsxOpeningFragment) { + const node = createNode(SyntaxKind.JsxFragment, opening.pos); + node.openingFragment = opening; + node.children = parseJsxChildren(node.openingFragment); + node.closingFragment = parseJsxClosingFragment(inExpressionContext); + + result = finishNode(node); + } else { Debug.assert(opening.kind === SyntaxKind.JsxSelfClosingElement); // Nothing else to do for self-closing elements @@ -3989,7 +4025,7 @@ namespace ts { // Since JSX elements are invalid < operands anyway, this lookahead parse will only occur in error scenarios // of one sort or another. if (inExpressionContext && token() === SyntaxKind.LessThanToken) { - const invalidElement = tryParse(() => parseJsxElementOrSelfClosingElement(/*inExpressionContext*/ true)); + const invalidElement = tryParse(() => parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true)); if (invalidElement) { parseErrorAtCurrentToken(Diagnostics.JSX_expressions_must_have_one_parent_element); const badNode = createNode(SyntaxKind.BinaryExpression, result.pos); @@ -4020,12 +4056,12 @@ namespace ts { case SyntaxKind.OpenBraceToken: return parseJsxExpression(/*inExpressionContext*/ false); case SyntaxKind.LessThanToken: - return parseJsxElementOrSelfClosingElement(/*inExpressionContext*/ false); + return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ false); } Debug.fail("Unknown JSX child kind " + token()); } - function parseJsxChildren(openingTagName: LeftHandSideExpression): NodeArray { + function parseJsxChildren(openingTag: JsxOpeningElement | JsxOpeningFragment): NodeArray { const list = []; const listPos = getNodePos(); const saveParsingContext = parsingContext; @@ -4040,7 +4076,13 @@ namespace ts { else if (token() === SyntaxKind.EndOfFileToken) { // If we hit EOF, issue the error at the tag that lacks the closing element // rather than at the end of the file (which is useless) - parseErrorAtPosition(openingTagName.pos, openingTagName.end - openingTagName.pos, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTagName)); + if (isJsxOpeningFragment(openingTag)) { + parseErrorAtPosition(openingTag.pos, openingTag.end - openingTag.pos, Diagnostics.JSX_fragment_has_no_corresponding_closing_tag); + } + else { + const openingTagName = openingTag.tagName; + parseErrorAtPosition(openingTagName.pos, openingTagName.end - openingTagName.pos, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTagName)); + } break; } else if (token() === SyntaxKind.ConflictMarkerTrivia) { @@ -4063,11 +4105,17 @@ namespace ts { return finishNode(jsxAttributes); } - function parseJsxOpeningOrSelfClosingElement(inExpressionContext: boolean): JsxOpeningElement | JsxSelfClosingElement { + function parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext: boolean): JsxOpeningElement | JsxSelfClosingElement | JsxOpeningFragment { const fullStart = scanner.getStartPos(); parseExpected(SyntaxKind.LessThanToken); + if (token() === SyntaxKind.GreaterThanToken) { + parseExpected(SyntaxKind.GreaterThanToken); + const node: JsxOpeningFragment = createNode(SyntaxKind.JsxOpeningFragment, fullStart); + return finishNode(node); + } + const tagName = parseJsxElementName(); const attributes = parseJsxAttributes(); @@ -4179,6 +4227,23 @@ namespace ts { return finishNode(node); } + function parseJsxClosingFragment(inExpressionContext: boolean): JsxClosingFragment { + const node = createNode(SyntaxKind.JsxClosingFragment); + parseExpected(SyntaxKind.LessThanSlashToken); + if (tokenIsIdentifierOrKeyword(token())) { + const unexpectedTagName = parseJsxElementName(); + parseErrorAtPosition(unexpectedTagName.pos, unexpectedTagName.end - unexpectedTagName.pos, Diagnostics.Expected_corresponding_closing_tag_for_JSX_fragment); + } + if (inExpressionContext) { + parseExpected(SyntaxKind.GreaterThanToken); + } + else { + parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false); + scanJsxText(); + } + return finishNode(node); + } + function parseTypeAssertion(): TypeAssertion { const node = createNode(SyntaxKind.TypeAssertionExpression); parseExpected(SyntaxKind.LessThanToken); @@ -5089,6 +5154,18 @@ namespace ts { const fullStart = getNodePos(); const decorators = parseDecorators(); const modifiers = parseModifiers(); + if (some(modifiers, m => m.kind === SyntaxKind.DeclareKeyword)) { + for (const m of modifiers) { + m.flags |= NodeFlags.Ambient; + } + return doInsideOfContext(NodeFlags.Ambient, () => parseDeclarationWorker(fullStart, decorators, modifiers)); + } + else { + return parseDeclarationWorker(fullStart, decorators, modifiers); + } + } + + function parseDeclarationWorker(fullStart: number, decorators: NodeArray | undefined, modifiers: NodeArray | undefined): Statement { switch (token()) { case SyntaxKind.VarKeyword: case SyntaxKind.LetKeyword: @@ -5446,8 +5523,8 @@ namespace ts { return false; } - function parseDecorators(): NodeArray { - let list: Decorator[]; + function parseDecorators(): NodeArray | undefined { + let list: Decorator[] | undefined; const listPos = getNodePos(); while (true) { const decoratorStart = getNodePos(); @@ -6069,7 +6146,7 @@ namespace ts { const checkJsDirectiveMatchResult = checkJsDirectiveRegEx.exec(comment); if (checkJsDirectiveMatchResult) { checkJsDirective = { - enabled: compareStrings(checkJsDirectiveMatchResult[1], "@ts-check", /*ignoreCase*/ true) === Comparison.EqualTo, + enabled: equateStringsCaseInsensitive(checkJsDirectiveMatchResult[1], "@ts-check"), end: range.end, pos: range.pos }; @@ -6131,7 +6208,7 @@ namespace ts { export namespace JSDocParser { export function parseJSDocTypeExpressionForTests(content: string, start: number, length: number): { jsDocTypeExpression: JSDocTypeExpression, diagnostics: Diagnostic[] } | undefined { initializeState(content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS); - sourceFile = createSourceFile("file.js", ScriptTarget.Latest, ScriptKind.JS); + sourceFile = createSourceFile("file.js", ScriptTarget.Latest, ScriptKind.JS, /*isDeclarationFile*/ false); scanner.setText(content, start, length); currentToken = scanner.scan(); const jsDocTypeExpression = parseJSDocTypeExpression(); @@ -7461,4 +7538,8 @@ namespace ts { Value = -1 } } + + function isDeclarationFileName(fileName: string): boolean { + return fileExtensionIs(fileName, Extension.Dts); + } } diff --git a/src/compiler/performance.ts b/src/compiler/performance.ts index 8c24b3b9f1b..225b34de9cf 100644 --- a/src/compiler/performance.ts +++ b/src/compiler/performance.ts @@ -10,9 +10,7 @@ namespace ts { namespace ts.performance { declare const onProfilerEvent: { (markName: string): void; profiler: boolean; }; - const profilerEvent = typeof onProfilerEvent === "function" && onProfilerEvent.profiler === true - ? onProfilerEvent - : (_markName: string) => { }; + const profilerEvent: (markName: string) => void = typeof onProfilerEvent === "function" && onProfilerEvent.profiler === true ? onProfilerEvent : noop; let enabled = false; let profilerStart = 0; diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 0ff78a77ecd..cf7c03556f1 100755 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -7,18 +7,10 @@ namespace ts { const ignoreDiagnosticCommentRegEx = /(^\s*$)|(^\s*\/\/\/?\s*(@ts-ignore)?)/; export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean, configName = "tsconfig.json"): string { - while (true) { - const fileName = combinePaths(searchPath, configName); - if (fileExists(fileName)) { - return fileName; - } - const parentPath = getDirectoryPath(searchPath); - if (parentPath === searchPath) { - break; - } - searchPath = parentPath; - } - return undefined; + return forEachAncestorDirectory(searchPath, ancestor => { + const fileName = combinePaths(ancestor, configName); + return fileExists(fileName) ? fileName : undefined; + }); } export function resolveTripleslashReference(moduleName: string, containingFile: string): string { @@ -1101,11 +1093,12 @@ 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; if (!options.lib) { - return compareStrings(file.fileName, getDefaultLibraryFileName(), /*ignoreCase*/ !host.useCaseSensitiveFileNames()) === Comparison.EqualTo; + return equalityComparer(file.fileName, getDefaultLibraryFileName()); } else { - return forEach(options.lib, libFileName => compareStrings(file.fileName, combinePaths(defaultLibraryPath, libFileName), /*ignoreCase*/ !host.useCaseSensitiveFileNames()) === Comparison.EqualTo); + return forEach(options.lib, libFileName => equalityComparer(file.fileName, combinePaths(defaultLibraryPath, libFileName))); } } @@ -1186,11 +1179,11 @@ namespace ts { return emitResult; } - function getSourceFile(fileName: string): SourceFile { + function getSourceFile(fileName: string): SourceFile | undefined { return getSourceFileByPath(toPath(fileName)); } - function getSourceFileByPath(path: Path): SourceFile { + function getSourceFileByPath(path: Path): SourceFile | undefined { return filesByName.get(path); } @@ -2131,7 +2124,7 @@ namespace ts { createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "lib", "noLib"); } - if (options.noImplicitUseStrict && (options.alwaysStrict === undefined ? options.strict : options.alwaysStrict)) { + if (options.noImplicitUseStrict && getStrictOptionValue(options, "alwaysStrict")) { createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noImplicitUseStrict", "alwaysStrict"); } @@ -2360,7 +2353,7 @@ namespace ts { return options.jsx ? undefined : Diagnostics.Module_0_was_resolved_to_1_but_jsx_is_not_set; } function needAllowJs() { - return options.allowJs || !options.noImplicitAny ? undefined : Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type; + return options.allowJs || !getStrictOptionValue(options, "noImplicitAny") ? undefined : Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type; } } diff --git a/src/compiler/resolutionCache.ts b/src/compiler/resolutionCache.ts index b988da0fd5f..e21e81a2e88 100644 --- a/src/compiler/resolutionCache.ts +++ b/src/compiler/resolutionCache.ts @@ -69,9 +69,8 @@ namespace ts { export const maxNumberOfFilesToIterateForInvalidation = 256; - interface GetResolutionWithResolvedFileName { - (resolution: T): R; - } + type GetResolutionWithResolvedFileName = + (resolution: T) => R; export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootDirForResolution: string): ResolutionCache { let filesWithChangedSetOfUnresolvedImports: Path[] | undefined; @@ -320,6 +319,10 @@ namespace ts { return endsWith(dirPath, "/node_modules"); } + function isNodeModulesAtTypesDirectory(dirPath: Path) { + return endsWith(dirPath, "/node_modules/@types"); + } + function isDirectoryAtleastAtLevelFromFSRoot(dirPath: Path, minLevels: number) { for (let searchIndex = getRootLength(dirPath); minLevels > 0; minLevels--) { searchIndex = dirPath.indexOf(directorySeparator, searchIndex) + 1; @@ -560,11 +563,21 @@ namespace ts { else { // Some file or directory in the watching directory is created // Return early if it does not have any of the watching extension or not the custom failed lookup path - if (!isPathWithDefaultFailedLookupExtension(fileOrDirectoryPath) && !customFailedLookupPaths.has(fileOrDirectoryPath)) { - return false; + const dirOfFileOrDirectory = getDirectoryPath(fileOrDirectoryPath); + if (isNodeModulesAtTypesDirectory(dirOfFileOrDirectory) || isNodeModulesDirectory(dirOfFileOrDirectory)) { + // Invalidate any resolution from this directory + isChangedFailedLookupLocation = location => { + const locationPath = resolutionHost.toPath(location); + return locationPath === fileOrDirectoryPath || startsWith(resolutionHost.toPath(location), fileOrDirectoryPath); + }; + } + else { + if (!isPathWithDefaultFailedLookupExtension(fileOrDirectoryPath) && !customFailedLookupPaths.has(fileOrDirectoryPath)) { + return false; + } + // Resolution need to be invalidated if failed lookup location is same as the file or directory getting created + isChangedFailedLookupLocation = location => resolutionHost.toPath(location) === fileOrDirectoryPath; } - // Resolution need to be invalidated if failed lookup location is same as the file or directory getting created - isChangedFailedLookupLocation = location => resolutionHost.toPath(location) === fileOrDirectoryPath; } const hasChangedFailedLookupLocation = (resolution: ResolutionWithFailedLookupLocations) => some(resolution.failedLookupLocations, isChangedFailedLookupLocation); const invalidatedFilesCount = filesWithInvalidatedResolutions && filesWithInvalidatedResolutions.size; diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 6dab127ca33..fd8c54a18cc 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -2,15 +2,18 @@ /// namespace ts { - export interface ErrorCallback { - (message: DiagnosticMessage, length: number): void; - } + export type ErrorCallback = (message: DiagnosticMessage, length: number) => void; /* @internal */ export function tokenIsIdentifierOrKeyword(token: SyntaxKind): boolean { return token >= SyntaxKind.Identifier; } + /* @internal */ + export function tokenIsIdentifierOrKeywordOrGreaterThan(token: SyntaxKind): boolean { + return token === SyntaxKind.GreaterThanToken || tokenIsIdentifierOrKeyword(token); + } + export interface Scanner { getStartPos(): number; getToken(): SyntaxKind; @@ -352,7 +355,7 @@ namespace ts { * We assume the first line starts at position 0 and 'position' is non-negative. */ export function computeLineAndCharacterOfPosition(lineStarts: ReadonlyArray, position: number): LineAndCharacter { - let lineNumber = binarySearch(lineStarts, position); + let lineNumber = binarySearch(lineStarts, position, identity, compareValues); if (lineNumber < 0) { // If the actual position was not found, // the binary search returns the 2's-complement of the next line start diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 1169af191b8..529ece36fa6 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -124,7 +124,7 @@ namespace ts { getEnvironmentVariable?(name: string): string; }; - export let sys: System = (function() { + export let sys: System = (() => { function getNodeSystem(): System { const _fs = require("fs"); const _path = require("path"); @@ -511,7 +511,7 @@ namespace ts { return stat.size; } } - catch (e) { } + catch { /*ignore*/ } return 0; }, exit(exitCode?: number): void { @@ -525,7 +525,7 @@ namespace ts { try { require("source-map-support").install(); } - catch (e) { + catch { // Could not enable source maps. } }, @@ -594,7 +594,7 @@ namespace ts { if (sys) { // patch writefile to create folder before writing the file const originalWriteFile = sys.writeFile; - sys.writeFile = function(path, data, writeBom) { + sys.writeFile = (path, data, writeBom) => { const directoryPath = getDirectoryPath(normalizeSlashes(path)); if (directoryPath && !sys.directoryExists(directoryPath)) { recursiveCreateDirectory(directoryPath, sys); diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index a1e52480172..989b0827570 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -787,9 +787,7 @@ namespace ts { // To preserve the behavior of the old emitter, we explicitly indent // the body of the function here if it was requested in an earlier // transformation. - if (getEmitFlags(node) & EmitFlags.Indented) { - setEmitFlags(classFunction, EmitFlags.Indented); - } + setEmitFlags(classFunction, (getEmitFlags(node) & EmitFlags.Indented) | EmitFlags.ReuseTempVariableScope); // "inner" and "outer" below are added purely to preserve source map locations from // the old emitter @@ -1327,7 +1325,8 @@ namespace ts { EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps ) ); - statement.startsOnNewLine = true; + + startOnNewLine(statement); setTextRange(statement, parameter); setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue); statements.push(statement); @@ -1683,7 +1682,7 @@ namespace ts { ] ); if (startsOnNewLine) { - call.startsOnNewLine = true; + startOnNewLine(call); } exitSubtree(ancestorFacts, HierarchyFacts.PropagateNewTargetMask, hierarchyFacts & HierarchyFacts.PropagateNewTargetMask ? HierarchyFacts.NewTarget : HierarchyFacts.None); @@ -2602,7 +2601,7 @@ namespace ts { ); if (node.multiLine) { - assignment.startsOnNewLine = true; + startOnNewLine(assignment); } expressions.push(assignment); @@ -3083,7 +3082,7 @@ namespace ts { ); setTextRange(expression, property); if (startsOnNewLine) { - expression.startsOnNewLine = true; + startOnNewLine(expression); } return expression; } @@ -3105,7 +3104,7 @@ namespace ts { ); setTextRange(expression, property); if (startsOnNewLine) { - expression.startsOnNewLine = true; + startOnNewLine(expression); } return expression; } @@ -3128,7 +3127,7 @@ namespace ts { ); setTextRange(expression, method); if (startsOnNewLine) { - expression.startsOnNewLine = true; + startOnNewLine(expression); } exitSubtree(ancestorFacts, HierarchyFacts.PropagateNewTargetMask, hierarchyFacts & HierarchyFacts.PropagateNewTargetMask ? HierarchyFacts.NewTarget : HierarchyFacts.None); return expression; diff --git a/src/compiler/transformers/generators.ts b/src/compiler/transformers/generators.ts index 7ede62b1540..bd2a4ef554d 100644 --- a/src/compiler/transformers/generators.ts +++ b/src/compiler/transformers/generators.ts @@ -1077,7 +1077,7 @@ namespace ts { const visited = visitNode(expression, visitor, isExpression); if (visited) { if (multiLine) { - visited.startsOnNewLine = true; + startOnNewLine(visited); } expressions.push(visited); } @@ -2683,8 +2683,7 @@ namespace ts { if (clauses) { const labelExpression = createPropertyAccess(state, "label"); const switchStatement = createSwitch(labelExpression, createCaseBlock(clauses)); - switchStatement.startsOnNewLine = true; - return [switchStatement]; + return [startOnNewLine(switchStatement)]; } if (statements) { diff --git a/src/compiler/transformers/jsx.ts b/src/compiler/transformers/jsx.ts index bbe05afe878..ab44db8ef4b 100644 --- a/src/compiler/transformers/jsx.ts +++ b/src/compiler/transformers/jsx.ts @@ -41,6 +41,9 @@ namespace ts { case SyntaxKind.JsxSelfClosingElement: return visitJsxSelfClosingElement(node, /*isChild*/ false); + case SyntaxKind.JsxFragment: + return visitJsxFragment(node, /*isChild*/ false); + case SyntaxKind.JsxExpression: return visitJsxExpression(node); @@ -63,6 +66,9 @@ namespace ts { case SyntaxKind.JsxSelfClosingElement: return visitJsxSelfClosingElement(node, /*isChild*/ true); + case SyntaxKind.JsxFragment: + return visitJsxFragment(node, /*isChild*/ true); + default: Debug.failBadSyntaxKind(node); return undefined; @@ -77,6 +83,10 @@ namespace ts { return visitJsxOpeningLikeElement(node, /*children*/ undefined, isChild, /*location*/ node); } + function visitJsxFragment(node: JsxFragment, isChild: boolean) { + return visitJsxOpeningFragment(node.openingFragment, node.children, isChild, /*location*/ node); + } + function visitJsxOpeningLikeElement(node: JsxOpeningLikeElement, children: ReadonlyArray, isChild: boolean, location: TextRange) { const tagName = getTagName(node); let objectProperties: Expression; @@ -126,6 +136,22 @@ namespace ts { return element; } + function visitJsxOpeningFragment(node: JsxOpeningFragment, children: ReadonlyArray, isChild: boolean, location: TextRange) { + const element = createExpressionForJsxFragment( + context.getEmitResolver().getJsxFactoryEntity(), + compilerOptions.reactNamespace, + mapDefined(children, transformJsxChildToExpression), + node, + location + ); + + if (isChild) { + startOnNewLine(element); + } + + return element; + } + function transformJsxSpreadAttributeToExpression(node: JsxSpreadAttribute) { return visitNode(node.expression, visitor, isExpression); } @@ -283,258 +309,258 @@ namespace ts { } const entities = createMapFromTemplate({ - "quot": 0x0022, - "amp": 0x0026, - "apos": 0x0027, - "lt": 0x003C, - "gt": 0x003E, - "nbsp": 0x00A0, - "iexcl": 0x00A1, - "cent": 0x00A2, - "pound": 0x00A3, - "curren": 0x00A4, - "yen": 0x00A5, - "brvbar": 0x00A6, - "sect": 0x00A7, - "uml": 0x00A8, - "copy": 0x00A9, - "ordf": 0x00AA, - "laquo": 0x00AB, - "not": 0x00AC, - "shy": 0x00AD, - "reg": 0x00AE, - "macr": 0x00AF, - "deg": 0x00B0, - "plusmn": 0x00B1, - "sup2": 0x00B2, - "sup3": 0x00B3, - "acute": 0x00B4, - "micro": 0x00B5, - "para": 0x00B6, - "middot": 0x00B7, - "cedil": 0x00B8, - "sup1": 0x00B9, - "ordm": 0x00BA, - "raquo": 0x00BB, - "frac14": 0x00BC, - "frac12": 0x00BD, - "frac34": 0x00BE, - "iquest": 0x00BF, - "Agrave": 0x00C0, - "Aacute": 0x00C1, - "Acirc": 0x00C2, - "Atilde": 0x00C3, - "Auml": 0x00C4, - "Aring": 0x00C5, - "AElig": 0x00C6, - "Ccedil": 0x00C7, - "Egrave": 0x00C8, - "Eacute": 0x00C9, - "Ecirc": 0x00CA, - "Euml": 0x00CB, - "Igrave": 0x00CC, - "Iacute": 0x00CD, - "Icirc": 0x00CE, - "Iuml": 0x00CF, - "ETH": 0x00D0, - "Ntilde": 0x00D1, - "Ograve": 0x00D2, - "Oacute": 0x00D3, - "Ocirc": 0x00D4, - "Otilde": 0x00D5, - "Ouml": 0x00D6, - "times": 0x00D7, - "Oslash": 0x00D8, - "Ugrave": 0x00D9, - "Uacute": 0x00DA, - "Ucirc": 0x00DB, - "Uuml": 0x00DC, - "Yacute": 0x00DD, - "THORN": 0x00DE, - "szlig": 0x00DF, - "agrave": 0x00E0, - "aacute": 0x00E1, - "acirc": 0x00E2, - "atilde": 0x00E3, - "auml": 0x00E4, - "aring": 0x00E5, - "aelig": 0x00E6, - "ccedil": 0x00E7, - "egrave": 0x00E8, - "eacute": 0x00E9, - "ecirc": 0x00EA, - "euml": 0x00EB, - "igrave": 0x00EC, - "iacute": 0x00ED, - "icirc": 0x00EE, - "iuml": 0x00EF, - "eth": 0x00F0, - "ntilde": 0x00F1, - "ograve": 0x00F2, - "oacute": 0x00F3, - "ocirc": 0x00F4, - "otilde": 0x00F5, - "ouml": 0x00F6, - "divide": 0x00F7, - "oslash": 0x00F8, - "ugrave": 0x00F9, - "uacute": 0x00FA, - "ucirc": 0x00FB, - "uuml": 0x00FC, - "yacute": 0x00FD, - "thorn": 0x00FE, - "yuml": 0x00FF, - "OElig": 0x0152, - "oelig": 0x0153, - "Scaron": 0x0160, - "scaron": 0x0161, - "Yuml": 0x0178, - "fnof": 0x0192, - "circ": 0x02C6, - "tilde": 0x02DC, - "Alpha": 0x0391, - "Beta": 0x0392, - "Gamma": 0x0393, - "Delta": 0x0394, - "Epsilon": 0x0395, - "Zeta": 0x0396, - "Eta": 0x0397, - "Theta": 0x0398, - "Iota": 0x0399, - "Kappa": 0x039A, - "Lambda": 0x039B, - "Mu": 0x039C, - "Nu": 0x039D, - "Xi": 0x039E, - "Omicron": 0x039F, - "Pi": 0x03A0, - "Rho": 0x03A1, - "Sigma": 0x03A3, - "Tau": 0x03A4, - "Upsilon": 0x03A5, - "Phi": 0x03A6, - "Chi": 0x03A7, - "Psi": 0x03A8, - "Omega": 0x03A9, - "alpha": 0x03B1, - "beta": 0x03B2, - "gamma": 0x03B3, - "delta": 0x03B4, - "epsilon": 0x03B5, - "zeta": 0x03B6, - "eta": 0x03B7, - "theta": 0x03B8, - "iota": 0x03B9, - "kappa": 0x03BA, - "lambda": 0x03BB, - "mu": 0x03BC, - "nu": 0x03BD, - "xi": 0x03BE, - "omicron": 0x03BF, - "pi": 0x03C0, - "rho": 0x03C1, - "sigmaf": 0x03C2, - "sigma": 0x03C3, - "tau": 0x03C4, - "upsilon": 0x03C5, - "phi": 0x03C6, - "chi": 0x03C7, - "psi": 0x03C8, - "omega": 0x03C9, - "thetasym": 0x03D1, - "upsih": 0x03D2, - "piv": 0x03D6, - "ensp": 0x2002, - "emsp": 0x2003, - "thinsp": 0x2009, - "zwnj": 0x200C, - "zwj": 0x200D, - "lrm": 0x200E, - "rlm": 0x200F, - "ndash": 0x2013, - "mdash": 0x2014, - "lsquo": 0x2018, - "rsquo": 0x2019, - "sbquo": 0x201A, - "ldquo": 0x201C, - "rdquo": 0x201D, - "bdquo": 0x201E, - "dagger": 0x2020, - "Dagger": 0x2021, - "bull": 0x2022, - "hellip": 0x2026, - "permil": 0x2030, - "prime": 0x2032, - "Prime": 0x2033, - "lsaquo": 0x2039, - "rsaquo": 0x203A, - "oline": 0x203E, - "frasl": 0x2044, - "euro": 0x20AC, - "image": 0x2111, - "weierp": 0x2118, - "real": 0x211C, - "trade": 0x2122, - "alefsym": 0x2135, - "larr": 0x2190, - "uarr": 0x2191, - "rarr": 0x2192, - "darr": 0x2193, - "harr": 0x2194, - "crarr": 0x21B5, - "lArr": 0x21D0, - "uArr": 0x21D1, - "rArr": 0x21D2, - "dArr": 0x21D3, - "hArr": 0x21D4, - "forall": 0x2200, - "part": 0x2202, - "exist": 0x2203, - "empty": 0x2205, - "nabla": 0x2207, - "isin": 0x2208, - "notin": 0x2209, - "ni": 0x220B, - "prod": 0x220F, - "sum": 0x2211, - "minus": 0x2212, - "lowast": 0x2217, - "radic": 0x221A, - "prop": 0x221D, - "infin": 0x221E, - "ang": 0x2220, - "and": 0x2227, - "or": 0x2228, - "cap": 0x2229, - "cup": 0x222A, - "int": 0x222B, - "there4": 0x2234, - "sim": 0x223C, - "cong": 0x2245, - "asymp": 0x2248, - "ne": 0x2260, - "equiv": 0x2261, - "le": 0x2264, - "ge": 0x2265, - "sub": 0x2282, - "sup": 0x2283, - "nsub": 0x2284, - "sube": 0x2286, - "supe": 0x2287, - "oplus": 0x2295, - "otimes": 0x2297, - "perp": 0x22A5, - "sdot": 0x22C5, - "lceil": 0x2308, - "rceil": 0x2309, - "lfloor": 0x230A, - "rfloor": 0x230B, - "lang": 0x2329, - "rang": 0x232A, - "loz": 0x25CA, - "spades": 0x2660, - "clubs": 0x2663, - "hearts": 0x2665, - "diams": 0x2666 + quot: 0x0022, + amp: 0x0026, + apos: 0x0027, + lt: 0x003C, + gt: 0x003E, + nbsp: 0x00A0, + iexcl: 0x00A1, + cent: 0x00A2, + pound: 0x00A3, + curren: 0x00A4, + yen: 0x00A5, + brvbar: 0x00A6, + sect: 0x00A7, + uml: 0x00A8, + copy: 0x00A9, + ordf: 0x00AA, + laquo: 0x00AB, + not: 0x00AC, + shy: 0x00AD, + reg: 0x00AE, + macr: 0x00AF, + deg: 0x00B0, + plusmn: 0x00B1, + sup2: 0x00B2, + sup3: 0x00B3, + acute: 0x00B4, + micro: 0x00B5, + para: 0x00B6, + middot: 0x00B7, + cedil: 0x00B8, + sup1: 0x00B9, + ordm: 0x00BA, + raquo: 0x00BB, + frac14: 0x00BC, + frac12: 0x00BD, + frac34: 0x00BE, + iquest: 0x00BF, + Agrave: 0x00C0, + Aacute: 0x00C1, + Acirc: 0x00C2, + Atilde: 0x00C3, + Auml: 0x00C4, + Aring: 0x00C5, + AElig: 0x00C6, + Ccedil: 0x00C7, + Egrave: 0x00C8, + Eacute: 0x00C9, + Ecirc: 0x00CA, + Euml: 0x00CB, + Igrave: 0x00CC, + Iacute: 0x00CD, + Icirc: 0x00CE, + Iuml: 0x00CF, + ETH: 0x00D0, + Ntilde: 0x00D1, + Ograve: 0x00D2, + Oacute: 0x00D3, + Ocirc: 0x00D4, + Otilde: 0x00D5, + Ouml: 0x00D6, + times: 0x00D7, + Oslash: 0x00D8, + Ugrave: 0x00D9, + Uacute: 0x00DA, + Ucirc: 0x00DB, + Uuml: 0x00DC, + Yacute: 0x00DD, + THORN: 0x00DE, + szlig: 0x00DF, + agrave: 0x00E0, + aacute: 0x00E1, + acirc: 0x00E2, + atilde: 0x00E3, + auml: 0x00E4, + aring: 0x00E5, + aelig: 0x00E6, + ccedil: 0x00E7, + egrave: 0x00E8, + eacute: 0x00E9, + ecirc: 0x00EA, + euml: 0x00EB, + igrave: 0x00EC, + iacute: 0x00ED, + icirc: 0x00EE, + iuml: 0x00EF, + eth: 0x00F0, + ntilde: 0x00F1, + ograve: 0x00F2, + oacute: 0x00F3, + ocirc: 0x00F4, + otilde: 0x00F5, + ouml: 0x00F6, + divide: 0x00F7, + oslash: 0x00F8, + ugrave: 0x00F9, + uacute: 0x00FA, + ucirc: 0x00FB, + uuml: 0x00FC, + yacute: 0x00FD, + thorn: 0x00FE, + yuml: 0x00FF, + OElig: 0x0152, + oelig: 0x0153, + Scaron: 0x0160, + scaron: 0x0161, + Yuml: 0x0178, + fnof: 0x0192, + circ: 0x02C6, + tilde: 0x02DC, + Alpha: 0x0391, + Beta: 0x0392, + Gamma: 0x0393, + Delta: 0x0394, + Epsilon: 0x0395, + Zeta: 0x0396, + Eta: 0x0397, + Theta: 0x0398, + Iota: 0x0399, + Kappa: 0x039A, + Lambda: 0x039B, + Mu: 0x039C, + Nu: 0x039D, + Xi: 0x039E, + Omicron: 0x039F, + Pi: 0x03A0, + Rho: 0x03A1, + Sigma: 0x03A3, + Tau: 0x03A4, + Upsilon: 0x03A5, + Phi: 0x03A6, + Chi: 0x03A7, + Psi: 0x03A8, + Omega: 0x03A9, + alpha: 0x03B1, + beta: 0x03B2, + gamma: 0x03B3, + delta: 0x03B4, + epsilon: 0x03B5, + zeta: 0x03B6, + eta: 0x03B7, + theta: 0x03B8, + iota: 0x03B9, + kappa: 0x03BA, + lambda: 0x03BB, + mu: 0x03BC, + nu: 0x03BD, + xi: 0x03BE, + omicron: 0x03BF, + pi: 0x03C0, + rho: 0x03C1, + sigmaf: 0x03C2, + sigma: 0x03C3, + tau: 0x03C4, + upsilon: 0x03C5, + phi: 0x03C6, + chi: 0x03C7, + psi: 0x03C8, + omega: 0x03C9, + thetasym: 0x03D1, + upsih: 0x03D2, + piv: 0x03D6, + ensp: 0x2002, + emsp: 0x2003, + thinsp: 0x2009, + zwnj: 0x200C, + zwj: 0x200D, + lrm: 0x200E, + rlm: 0x200F, + ndash: 0x2013, + mdash: 0x2014, + lsquo: 0x2018, + rsquo: 0x2019, + sbquo: 0x201A, + ldquo: 0x201C, + rdquo: 0x201D, + bdquo: 0x201E, + dagger: 0x2020, + Dagger: 0x2021, + bull: 0x2022, + hellip: 0x2026, + permil: 0x2030, + prime: 0x2032, + Prime: 0x2033, + lsaquo: 0x2039, + rsaquo: 0x203A, + oline: 0x203E, + frasl: 0x2044, + euro: 0x20AC, + image: 0x2111, + weierp: 0x2118, + real: 0x211C, + trade: 0x2122, + alefsym: 0x2135, + larr: 0x2190, + uarr: 0x2191, + rarr: 0x2192, + darr: 0x2193, + harr: 0x2194, + crarr: 0x21B5, + lArr: 0x21D0, + uArr: 0x21D1, + rArr: 0x21D2, + dArr: 0x21D3, + hArr: 0x21D4, + forall: 0x2200, + part: 0x2202, + exist: 0x2203, + empty: 0x2205, + nabla: 0x2207, + isin: 0x2208, + notin: 0x2209, + ni: 0x220B, + prod: 0x220F, + sum: 0x2211, + minus: 0x2212, + lowast: 0x2217, + radic: 0x221A, + prop: 0x221D, + infin: 0x221E, + ang: 0x2220, + and: 0x2227, + or: 0x2228, + cap: 0x2229, + cup: 0x222A, + int: 0x222B, + there4: 0x2234, + sim: 0x223C, + cong: 0x2245, + asymp: 0x2248, + ne: 0x2260, + equiv: 0x2261, + le: 0x2264, + ge: 0x2265, + sub: 0x2282, + sup: 0x2283, + nsub: 0x2284, + sube: 0x2286, + supe: 0x2287, + oplus: 0x2295, + otimes: 0x2297, + perp: 0x22A5, + sdot: 0x22C5, + lceil: 0x2308, + rceil: 0x2309, + lfloor: 0x230A, + rfloor: 0x230B, + lang: 0x2329, + rang: 0x232A, + loz: 0x25CA, + spades: 0x2660, + clubs: 0x2663, + hearts: 0x2665, + diams: 0x2666 }); } \ No newline at end of file diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index bd360fdffe4..f60e50ea365 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -91,7 +91,7 @@ namespace ts { startLexicalEnvironment(); const statements: Statement[] = []; - const ensureUseStrict = compilerOptions.alwaysStrict || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile)); + const ensureUseStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile)); const statementOffset = addPrologue(statements, node.statements, ensureUseStrict, sourceElementVisitor); if (shouldEmitUnderscoreUnderscoreESModule()) { diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index d674546efb9..e5d638cf04d 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -146,8 +146,7 @@ namespace ts { function collectDependencyGroups(externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[]) { const groupIndices = createMap(); const dependencyGroups: DependencyGroup[] = []; - for (let i = 0; i < externalImports.length; i++) { - const externalImport = externalImports[i]; + for (const externalImport of externalImports) { const externalModuleName = getExternalModuleNameLiteral(externalImport, currentSourceFile, host, resolver, compilerOptions); if (externalModuleName) { const text = externalModuleName.text; @@ -225,7 +224,7 @@ namespace ts { startLexicalEnvironment(); // Add any prologue directives. - const ensureUseStrict = compilerOptions.alwaysStrict || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile)); + const ensureUseStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile)); const statementOffset = addPrologue(statements, node.statements, ensureUseStrict, sourceElementVisitor); // var __moduleName = context_1 && context_1.id; diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index ba4b5fcdf52..39a4cc83bda 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -45,7 +45,7 @@ namespace ts { const resolver = context.getEmitResolver(); const compilerOptions = context.getCompilerOptions(); - const strictNullChecks = typeof compilerOptions.strictNullChecks === "undefined" ? compilerOptions.strict : compilerOptions.strictNullChecks; + const strictNullChecks = getStrictOptionValue(compilerOptions, "strictNullChecks"); const languageVersion = getEmitScriptTarget(compilerOptions); const moduleKind = getEmitModuleKind(compilerOptions); @@ -86,6 +86,12 @@ namespace ts { */ let applicableSubstitutions: TypeScriptSubstitutionFlags; + /** + * Tracks what computed name expressions originating from elided names must be inlined + * at the next execution site, in document order + */ + let pendingExpressions: Expression[] | undefined; + return transformSourceFile; /** @@ -225,6 +231,13 @@ namespace ts { if (parsed !== node) { // If the node has been transformed by a `before` transformer, perform no ellision on it // As the type information we would attempt to lookup to perform ellision is potentially unavailable for the synthesized nodes + // We do not reuse `visitorWorker`, as the ellidable statement syntax kinds are technically unrecognized by the switch-case in `visitTypeScript`, + // and will trigger debug failures when debug verbosity is turned up + if (node.transformFlags & TransformFlags.ContainsTypeScript) { + // This node contains TypeScript, so we should visit its children. + return visitEachChild(node, visitor, context); + } + // Otherwise, we can just return the node return node; } switch (node.kind) { @@ -388,9 +401,11 @@ namespace ts { case SyntaxKind.TypeAliasDeclaration: // TypeScript type-only declarations are elided. + return undefined; case SyntaxKind.PropertyDeclaration: - // TypeScript property declarations are elided. + // TypeScript property declarations are elided. However their names are still visited, and can potentially be retained if they could have sideeffects + return visitPropertyDeclaration(node as PropertyDeclaration); case SyntaxKind.NamespaceExportDeclaration: // TypeScript namespace export declarations are elided. @@ -521,7 +536,7 @@ namespace ts { } function visitSourceFile(node: SourceFile) { - const alwaysStrict = (compilerOptions.alwaysStrict === undefined ? compilerOptions.strict : compilerOptions.alwaysStrict) && + const alwaysStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") && !(isExternalModule(node) && moduleKind >= ModuleKind.ES2015); return updateSourceFileNode( node, @@ -577,6 +592,9 @@ namespace ts { * @param node The node to transform. */ function visitClassDeclaration(node: ClassDeclaration): VisitResult { + const savedPendingExpressions = pendingExpressions; + pendingExpressions = undefined; + const staticProperties = getInitializedProperties(node, /*isStatic*/ true); const facts = getClassFacts(node, staticProperties); @@ -591,6 +609,12 @@ namespace ts { let statements: Statement[] = [classStatement]; + // Write any pending expressions from elided or moved computed property names + if (some(pendingExpressions)) { + statements.push(createStatement(inlineExpressions(pendingExpressions))); + } + pendingExpressions = savedPendingExpressions; + // Emit static property assignment. Because classDeclaration is lexically evaluated, // it is safe to emit static property assignment after classDeclaration // From ES6 specification: @@ -849,6 +873,9 @@ namespace ts { * @param node The node to transform. */ function visitClassExpression(node: ClassExpression): Expression { + const savedPendingExpressions = pendingExpressions; + pendingExpressions = undefined; + const staticProperties = getInitializedProperties(node, /*isStatic*/ true); const heritageClauses = visitNodes(node.heritageClauses, visitor, isHeritageClause); const members = transformClassMembers(node, some(heritageClauses, c => c.token === SyntaxKind.ExtendsKeyword)); @@ -864,7 +891,7 @@ namespace ts { setOriginalNode(classExpression, node); setTextRange(classExpression, node); - if (staticProperties.length > 0) { + if (some(staticProperties) || some(pendingExpressions)) { const expressions: Expression[] = []; const temp = createTempVariable(hoistVariableDeclaration); if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference) { @@ -877,11 +904,15 @@ namespace ts { // the body of a class with static initializers. setEmitFlags(classExpression, EmitFlags.Indented | getEmitFlags(classExpression)); expressions.push(startOnNewLine(createAssignment(temp, classExpression))); + // Add any pending expressions leftover from elided or relocated computed property names + addRange(expressions, map(pendingExpressions, startOnNewLine)); + pendingExpressions = savedPendingExpressions; addRange(expressions, generateInitializedPropertyExpressions(staticProperties, temp)); expressions.push(startOnNewLine(temp)); return inlineExpressions(expressions); } + pendingExpressions = savedPendingExpressions; return classExpression; } @@ -1195,7 +1226,7 @@ namespace ts { const expressions: Expression[] = []; for (const property of properties) { const expression = transformInitializedProperty(property, receiver); - expression.startsOnNewLine = true; + startOnNewLine(expression); setSourceMapRange(expression, moveRangePastModifiers(property)); setCommentRange(expression, property); expressions.push(expression); @@ -1211,7 +1242,10 @@ namespace ts { * @param receiver The object receiving the property assignment. */ function transformInitializedProperty(property: PropertyDeclaration, receiver: LeftHandSideExpression) { - const propertyName = visitPropertyNameOfClassElement(property); + // 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 propertyName = isComputedPropertyName(property.name) && !isSimpleInlineableExpression(property.name.expression) + ? updateComputedPropertyName(property.name, getGeneratedNameForNode(property.name, !hasModifier(property, ModifierFlags.Static))) + : property.name; const initializer = visitNode(property.initializer, visitor, isExpression); const memberAccess = createMemberAccessForPropertyName(receiver, propertyName, /*location*/ propertyName); @@ -2034,6 +2068,16 @@ namespace ts { ); } + /** + * A simple inlinable expression is an expression which can be copied into multiple locations + * without risk of repeating any sideeffects and whose value could not possibly change between + * any such locations + */ + function isSimpleInlineableExpression(expression: Expression) { + return !isIdentifier(expression) && isSimpleCopiableExpression(expression) || + isWellKnownSymbolSyntactically(expression); + } + /** * Gets an expression that represents a property name. For a computed property, a * name is generated for the node. @@ -2043,7 +2087,7 @@ namespace ts { function getExpressionForPropertyName(member: ClassElement | EnumMember, generateNameForComputedPropertyName: boolean): Expression { const name = member.name; if (isComputedPropertyName(name)) { - return generateNameForComputedPropertyName + return generateNameForComputedPropertyName && !isSimpleInlineableExpression((name).expression) ? getGeneratedNameForNode(name) : (name).expression; } @@ -2055,6 +2099,26 @@ namespace ts { } } + /** + * If the name is a computed property, this function transforms it, then either returns an expression which caches the + * value of the result or the expression itself if the value is either unused or safe to inline into multiple locations + * @param shouldHoist Does the expression need to be reused? (ie, for an initializer or a decorator) + * @param omitSimple Should expressions with no observable side-effects be elided? (ie, the expression is not hoisted for a decorator or initializer and is a literal) + */ + function getPropertyNameExpressionIfNeeded(name: PropertyName, shouldHoist: boolean, omitSimple: boolean): Expression { + if (isComputedPropertyName(name)) { + const expression = visitNode(name.expression, visitor, isExpression); + const innerExpression = skipPartiallyEmittedExpressions(expression); + const inlinable = isSimpleInlineableExpression(innerExpression); + if (!inlinable && shouldHoist) { + const generatedName = getGeneratedNameForNode(name); + hoistVariableDeclaration(generatedName); + return createAssignment(generatedName, expression); + } + return (omitSimple && (inlinable || isIdentifier(innerExpression))) ? undefined : expression; + } + } + /** * Visits the property name of a class element, for use when emitting property * initializers. For a computed property on a node with decorators, a temporary @@ -2064,15 +2128,14 @@ namespace ts { */ function visitPropertyNameOfClassElement(member: ClassElement): PropertyName { const name = member.name; - if (isComputedPropertyName(name)) { - let expression = visitNode(name.expression, visitor, isExpression); - if (member.decorators) { - const generatedName = getGeneratedNameForNode(name); - hoistVariableDeclaration(generatedName); - expression = createAssignment(generatedName, expression); + let expr = getPropertyNameExpressionIfNeeded(name, some(member.decorators), /*omitSimple*/ false); + if (expr) { // expr only exists if `name` is a computed property name + // Inline any pending expressions from previous elided or relocated computed property name expressions in order to preserve execution order + if (some(pendingExpressions)) { + expr = inlineExpressions([...pendingExpressions, expr]); + pendingExpressions.length = 0; } - - return updateComputedPropertyName(name, expression); + return updateComputedPropertyName(name as ComputedPropertyName, expr); } else { return name; @@ -2129,6 +2192,14 @@ namespace ts { return !nodeIsMissing(node.body); } + function visitPropertyDeclaration(node: PropertyDeclaration): undefined { + const expr = getPropertyNameExpressionIfNeeded(node.name, some(node.decorators) || !!node.initializer, /*omitSimple*/ true); + if (expr && !isSimpleInlineableExpression(expr)) { + (pendingExpressions || (pendingExpressions = [])).push(expr); + } + return undefined; + } + function visitConstructor(node: ConstructorDeclaration) { if (!shouldEmitFunctionLikeDeclaration(node)) { return undefined; @@ -2149,7 +2220,7 @@ namespace ts { * This function will be called when one of the following conditions are met: * - The node is an overload * - The node is marked as abstract, public, private, protected, or readonly - * - The node has both a decorator and a computed property name + * - The node has a computed property name * * @param node The method node. */ @@ -2193,7 +2264,7 @@ namespace ts { * * This function will be called when one of the following conditions are met: * - The node is marked as abstract, public, private, or protected - * - The node has both a decorator and a computed property name + * - The node has a computed property name * * @param node The get accessor node. */ @@ -2224,7 +2295,7 @@ namespace ts { * * This function will be called when one of the following conditions are met: * - The node is marked as abstract, public, private, or protected - * - The node has both a decorator and a computed property name + * - The node has a computed property name * * @param node The set accessor node. */ diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index 680daeeb485..01fb45e4f7d 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -43,20 +43,12 @@ namespace ts { return s; } - function isJSONSupported() { - return typeof JSON === "object" && typeof JSON.parse === "function"; - } - export function executeCommandLine(args: string[]): void { const commandLine = parseCommandLine(args); // Configuration file name (if any) let configFileName: string; if (commandLine.options.locale) { - if (!isJSONSupported()) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--locale")); - return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); - } validateLocaleAndSetLanguage(commandLine.options.locale, sys, commandLine.errors); } @@ -84,10 +76,6 @@ namespace ts { } if (commandLine.options.project) { - if (!isJSONSupported()) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--project")); - return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); - } if (commandLine.fileNames.length !== 0) { reportDiagnostic(createCompilerDiagnostic(Diagnostics.Option_project_cannot_be_mixed_with_source_files_on_a_command_line)); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); @@ -109,7 +97,7 @@ namespace ts { } } } - else if (commandLine.fileNames.length === 0 && isJSONSupported()) { + else if (commandLine.fileNames.length === 0) { const searchPath = normalizePath(sys.getCurrentDirectory()); configFileName = findConfigFile(searchPath, sys.fileExists); } @@ -306,7 +294,7 @@ namespace ts { // Sort our options by their names, (e.g. "--noImplicitAny" comes before "--watch") const optsList = showAllOptions ? - optionDeclarations.slice().sort((a, b) => compareValues(a.name.toLowerCase(), b.name.toLowerCase())) : + sort(optionDeclarations, (a, b) => compareStringsCaseInsensitive(a.name, b.name)) : filter(optionDeclarations.slice(), v => v.showInSimplifiedHelpView); // We want our descriptions to align at the same column in our output, @@ -317,9 +305,7 @@ namespace ts { const optionsDescriptionMap = createMap(); // Map between option.description and list of option.type if it is a kind - for (let i = 0; i < optsList.length; i++) { - const option = optsList[i]; - + for (const option of optsList) { // If an option lacks a description, // it is not officially supported. if (!option.description) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ff2a33266ed..d2107572ab4 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -36,6 +36,19 @@ namespace ts { push(...values: T[]): void; } + /* @internal */ + export type EqualityComparer = (a: T, b: T) => boolean; + + /* @internal */ + export type Comparer = (a: T, b: T) => Comparison; + + /* @internal */ + export const enum Comparison { + LessThan = -1, + EqualTo = 0, + GreaterThan = 1 + } + // branded string type used to store absolute, normalized and canonicalized paths // arbitrary file name can be converted to Path via toPath function export type Path = string & { __pathBrand: any }; @@ -328,6 +341,9 @@ namespace ts { JsxSelfClosingElement, JsxOpeningElement, JsxClosingElement, + JsxFragment, + JsxOpeningFragment, + JsxClosingFragment, JsxAttribute, JsxAttributes, JsxSpreadAttribute, @@ -362,6 +378,7 @@ namespace ts { JSDocFunctionType, JSDocVariadicType, JSDocComment, + JSDocTypeLiteral, JSDocTag, JSDocAugmentsTag, JSDocClassTag, @@ -371,7 +388,6 @@ namespace ts { JSDocTemplateTag, JSDocTypedefTag, JSDocPropertyTag, - JSDocTypeLiteral, // Synthesized list SyntaxList, @@ -413,9 +429,9 @@ namespace ts { LastBinaryOperator = CaretEqualsToken, FirstNode = QualifiedName, FirstJSDocNode = JSDocTypeExpression, - LastJSDocNode = JSDocTypeLiteral, + LastJSDocNode = JSDocPropertyTag, FirstJSDocTagNode = JSDocTag, - LastJSDocTagNode = JSDocTypeLiteral + LastJSDocTagNode = JSDocPropertyTag } export const enum NodeFlags { @@ -451,7 +467,8 @@ namespace ts { /* @internal */ PossiblyContainsDynamicImport = 1 << 19, JSDoc = 1 << 20, // If node was parsed inside jsdoc - /* @internal */ InWithStatement = 1 << 21, // If any ancestor of node was the `statement` of a WithStatement (not the `expression`) + /* @internal */ Ambient = 1 << 21, // If node was inside an ambient context -- a declaration file, or inside something with the `declare` modifier. + /* @internal */ InWithStatement = 1 << 22, // If any ancestor of node was the `statement` of a WithStatement (not the `expression`) BlockScoped = Let | Const, @@ -459,7 +476,7 @@ namespace ts { ReachabilityAndEmitFlags = ReachabilityCheckFlags | HasAsyncFunctions, // Parsing context flags - ContextFlags = DisallowInContext | YieldContext | DecoratorContext | AwaitContext | JavaScriptFile | InWithStatement, + ContextFlags = DisallowInContext | YieldContext | DecoratorContext | AwaitContext | JavaScriptFile | InWithStatement | Ambient, // Exclude these flags when parsing a Type TypeExcludesFlags = YieldContext | AwaitContext, @@ -516,7 +533,6 @@ namespace ts { /* @internal */ id?: number; // Unique id (used to look up NodeLinks) parent?: Node; // Parent node (initialized by binding) /* @internal */ original?: Node; // The original node if this is an updated node. - /* @internal */ startsOnNewLine?: boolean; // Whether a synthesized node should start on a new line (used by transforms). /* @internal */ symbol?: Symbol; // Symbol declared by node (initialized by binding) /* @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding) /* @internal */ nextContainer?: Node; // Next container in declaration order (initialized by binding) @@ -626,6 +642,7 @@ namespace ts { isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace /*@internal*/ typeArguments?: NodeArray; // Only defined on synthesized nodes. Though not syntactically valid, used in emitting diagnostics. /*@internal*/ jsdocDotPos?: number; // Identifier occurs in JSDoc-style generic: Id. + /*@internal*/ skipNameGenerationScope?: boolean; // Should skip a name generation scope when generating the name for this identifier } // Transient identifier node (marked by id === -1) @@ -1620,7 +1637,7 @@ namespace ts { closingElement: JsxClosingElement; } - /// Either the opening tag in a ... pair, or the lone in a self-closing form + /// Either the opening tag in a ... pair or the lone in a self-closing form export type JsxOpeningLikeElement = JsxSelfClosingElement | JsxOpeningElement; export type JsxAttributeLike = JsxAttribute | JsxSpreadAttribute; @@ -1646,6 +1663,26 @@ namespace ts { attributes: JsxAttributes; } + /// A JSX expression of the form <>... + export interface JsxFragment extends PrimaryExpression { + kind: SyntaxKind.JsxFragment; + openingFragment: JsxOpeningFragment; + children: NodeArray; + closingFragment: JsxClosingFragment; + } + + /// The opening element of a <>... JsxFragment + export interface JsxOpeningFragment extends Expression { + kind: SyntaxKind.JsxOpeningFragment; + parent?: JsxFragment; + } + + /// The closing element of a <>... JsxFragment + export interface JsxClosingFragment extends Expression { + kind: SyntaxKind.JsxClosingFragment; + parent?: JsxFragment; + } + export interface JsxAttribute extends ObjectLiteralElement { kind: SyntaxKind.JsxAttribute; parent?: JsxAttributes; @@ -1679,7 +1716,7 @@ namespace ts { parent?: JsxElement; } - export type JsxChild = JsxText | JsxExpression | JsxElement | JsxSelfClosingElement; + export type JsxChild = JsxText | JsxExpression | JsxElement | JsxSelfClosingElement | JsxFragment; export interface Statement extends Node { _statementBrand: any; @@ -2429,8 +2466,8 @@ namespace ts { export interface ScriptReferenceHost { getCompilerOptions(): CompilerOptions; - getSourceFile(fileName: string): SourceFile; - getSourceFileByPath(path: Path): SourceFile; + getSourceFile(fileName: string): SourceFile | undefined; + getSourceFileByPath(path: Path): SourceFile | undefined; getCurrentDirectory(): string; } @@ -2448,9 +2485,13 @@ namespace ts { readFile(path: string): string | undefined; } - export interface WriteFileCallback { - (fileName: string, data: string, writeByteOrderMark: boolean, onError: ((message: string) => void) | undefined, sourceFiles: ReadonlyArray): void; - } + export type WriteFileCallback = ( + fileName: string, + data: string, + writeByteOrderMark: boolean, + onError: ((message: string) => void) | undefined, + sourceFiles: ReadonlyArray, + ) => void; export class OperationCanceledException { } @@ -2980,6 +3021,10 @@ namespace ts { Optional = 1 << 24, // Optional property Transient = 1 << 25, // Transient symbol (created during type check) + /* @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, + Enum = RegularEnum | ConstEnum, Variable = FunctionScopedVariable | BlockScopedVariable, Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor, @@ -3327,6 +3372,7 @@ namespace ts { ObjectLiteral = 1 << 7, // Originates in an object literal EvolvingArray = 1 << 8, // Evolving array type ObjectLiteralPatternWithComputedProperties = 1 << 9, // Object literal pattern with computed properties + ContainsSpread = 1 << 10, // Object literal contains spread operation ClassOrInterface = Class | Interface } @@ -3558,9 +3604,7 @@ namespace ts { } /* @internal */ - export interface TypeMapper { - (t: TypeParameter): Type; - } + export type TypeMapper = (t: TypeParameter) => Type; export const enum InferencePriority { Contravariant = 1 << 0, // Inference from contravariant position @@ -3609,6 +3653,14 @@ namespace ts { compareTypes: TypeComparer; // Type comparer function } + /* @internal */ + export interface WideningContext { + parent?: WideningContext; // Parent context + propertyName?: __String; // Name of property in parent + siblings?: Type[]; // Types of siblings + resolvedPropertyNames?: __String[]; // Property names occurring in sibling object literals + } + /* @internal */ export const enum SpecialPropertyAssignmentKind { None, @@ -4160,9 +4212,7 @@ namespace ts { } /* @internal */ - export interface HasInvalidatedResolution { - (sourceFile: Path): boolean; - } + export type HasInvalidatedResolution = (sourceFile: Path) => boolean; export interface CompilerHost extends ModuleResolutionHost { getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined; @@ -4297,6 +4347,7 @@ namespace ts { constantValue?: string | number; // The constant value of an expression externalHelpersModuleName?: Identifier; // The local name for an imported helpers module helpers?: EmitHelper[]; // Emit helpers for the node + startsOnNewLine?: boolean; // If the node should begin on a new line } export const enum EmitFlags { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 01bb36e9065..41a5512cb2a 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -321,16 +321,16 @@ namespace ts { return getSourceTextOfNodeFromSourceFile(getSourceFileOfNode(node), node, includeTrivia); } + function getPos(range: Node) { + return range.pos; + } + /** * Note: it is expected that the `nodeArray` and the `node` are within the same file. * For example, searching for a `SourceFile` in a `SourceFile[]` wouldn't work. */ export function indexOfNode(nodeArray: ReadonlyArray, node: Node) { - return binarySearch(nodeArray, node, compareNodePos); - } - - function compareNodePos({ pos: aPos }: Node, { pos: bPos}: Node) { - return aPos < bPos ? Comparison.LessThan : bPos < aPos ? Comparison.GreaterThan : Comparison.EqualTo; + return binarySearch(nodeArray, node, getPos, compareValues); } /** @@ -363,8 +363,10 @@ namespace ts { case SyntaxKind.NoSubstitutionTemplateLiteral: return "`" + escapeText(node.text, CharacterCodes.backtick) + "`"; case SyntaxKind.TemplateHead: + // tslint:disable-next-line no-invalid-template-strings return "`" + escapeText(node.text, CharacterCodes.backtick) + "${"; case SyntaxKind.TemplateMiddle: + // tslint:disable-next-line no-invalid-template-strings return "}" + escapeText(node.text, CharacterCodes.backtick) + "${"; case SyntaxKind.TemplateTail: return "}" + escapeText(node.text, CharacterCodes.backtick) + "`"; @@ -1132,7 +1134,7 @@ namespace ts { } /** - * Determines whether a node is a property or element access expression for super. + * Determines whether a node is a property or element access expression for `super`. */ export function isSuperProperty(node: Node): node is SuperProperty { const kind = node.kind; @@ -1140,7 +1142,16 @@ namespace ts { && (node).expression.kind === SyntaxKind.SuperKeyword; } - export function getEntityNameFromTypeNode(node: TypeNode): EntityNameOrEntityNameExpression { + /** + * Determines whether a node is a property or element access expression for `this`. + */ + export function isThisProperty(node: Node): boolean { + const kind = node.kind; + return (kind === SyntaxKind.PropertyAccessExpression || kind === SyntaxKind.ElementAccessExpression) + && (node).expression.kind === SyntaxKind.ThisKeyword; + } + + export function getEntityNameFromTypeNode(node: TypeNode): EntityNameOrEntityNameExpression { switch (node.kind) { case SyntaxKind.TypeReference: return (node).typeName; @@ -1228,7 +1239,7 @@ namespace ts { return false; } - export function isPartOfExpression(node: Node): boolean { + export function isExpressionNode(node: Node): boolean { switch (node.kind) { case SyntaxKind.SuperKeyword: case SyntaxKind.NullKeyword: @@ -1262,6 +1273,7 @@ namespace ts { case SyntaxKind.OmittedExpression: case SyntaxKind.JsxElement: case SyntaxKind.JsxSelfClosingElement: + case SyntaxKind.JsxFragment: case SyntaxKind.YieldExpression: case SyntaxKind.AwaitExpression: case SyntaxKind.MetaProperty: @@ -1331,7 +1343,7 @@ namespace ts { case SyntaxKind.ExpressionWithTypeArguments: return (parent).expression === node && isExpressionWithTypeArgumentsInClassExtendsClause(parent); default: - return isPartOfExpression(parent); + return isExpressionNode(parent); } } @@ -1394,8 +1406,8 @@ namespace ts { return charCode === CharacterCodes.singleQuote || charCode === CharacterCodes.doubleQuote; } - export function isStringDoubleQuoted(string: StringLiteral, sourceFile: SourceFile): boolean { - return getSourceTextOfNodeFromSourceFile(sourceFile, string).charCodeAt(0) === CharacterCodes.doubleQuote; + export function isStringDoubleQuoted(str: StringLiteral, sourceFile: SourceFile): boolean { + return getSourceTextOfNodeFromSourceFile(sourceFile, str).charCodeAt(0) === CharacterCodes.doubleQuote; } /** @@ -1718,16 +1730,6 @@ namespace ts { return false; } - export function isInAmbientContext(node: Node): boolean { - while (node) { - if (hasModifier(node, ModifierFlags.Ambient) || (node.kind === SyntaxKind.SourceFile && (node as SourceFile).isDeclarationFile)) { - return true; - } - node = node.parent; - } - return false; - } - // True if the given identifier, string literal, or number literal is the name of a declaration node export function isDeclarationName(name: Node): boolean { switch (name.kind) { @@ -2170,6 +2172,7 @@ namespace ts { case SyntaxKind.ClassExpression: case SyntaxKind.JsxElement: case SyntaxKind.JsxSelfClosingElement: + case SyntaxKind.JsxFragment: case SyntaxKind.RegularExpressionLiteral: case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.TemplateExpression: @@ -2291,6 +2294,7 @@ namespace ts { let nonFileDiagnostics: Diagnostic[] = []; const fileDiagnostics = createMap(); + let hasReadNonFileDiagnostics = false; let diagnosticsModified = false; let modificationCount = 0; @@ -2320,6 +2324,12 @@ namespace ts { } } else { + // If we've already read the non-file diagnostics, do not modify the existing array. + if (hasReadNonFileDiagnostics) { + hasReadNonFileDiagnostics = false; + nonFileDiagnostics = nonFileDiagnostics.slice(); + } + diagnostics = nonFileDiagnostics; } @@ -2330,6 +2340,7 @@ namespace ts { function getGlobalDiagnostics(): Diagnostic[] { sortAndDeduplicate(); + hasReadNonFileDiagnostics = true; return nonFileDiagnostics; } @@ -3591,7 +3602,7 @@ namespace ts { } /** Calls `callback` on `directory` and every ancestor directory it has, returning the first defined result. */ - export function forEachAncestorDirectory(directory: string, callback: (directory: string) => T): T { + export function forEachAncestorDirectory(directory: string, callback: (directory: string) => T | undefined): T | undefined { while (true) { const result = callback(directory); if (result !== undefined) { @@ -3949,6 +3960,9 @@ namespace ts { trySetLanguageAndTerritory(language, /*territory*/ undefined, errors); } + // Set the UI locale for string collation + setUILocale(locale); + function trySetLanguageAndTerritory(language: string, territory: string, errors?: Push): boolean { const compilerFilePath = normalizePath(sys.getExecutingFilePath()); const containingDirectoryPath = getDirectoryPath(compilerFilePath); @@ -4794,6 +4808,18 @@ namespace ts { return node.kind === SyntaxKind.JsxClosingElement; } + export function isJsxFragment(node: Node): node is JsxFragment { + return node.kind === SyntaxKind.JsxFragment; + } + + export function isJsxOpeningFragment(node: Node): node is JsxOpeningFragment { + return node.kind === SyntaxKind.JsxOpeningFragment; + } + + export function isJsxClosingFragment(node: Node): node is JsxClosingFragment { + return node.kind === SyntaxKind.JsxClosingFragment; + } + export function isJsxAttribute(node: Node): node is JsxAttribute { return node.kind === SyntaxKind.JsxAttribute; } @@ -5319,6 +5345,7 @@ namespace ts { case SyntaxKind.CallExpression: case SyntaxKind.JsxElement: case SyntaxKind.JsxSelfClosingElement: + case SyntaxKind.JsxFragment: case SyntaxKind.TaggedTemplateExpression: case SyntaxKind.ArrayLiteralExpression: case SyntaxKind.ParenthesizedExpression: @@ -5381,7 +5408,7 @@ namespace ts { /* @internal */ /** * Determines whether a node is an expression based only on its kind. - * Use `isPartOfExpression` if not in transforms. + * Use `isExpressionNode` if not in transforms. */ export function isExpression(node: Node): node is Expression { return isExpressionKind(skipPartiallyEmittedExpressions(node).kind); @@ -5640,7 +5667,8 @@ namespace ts { return kind === SyntaxKind.JsxElement || kind === SyntaxKind.JsxExpression || kind === SyntaxKind.JsxSelfClosingElement - || kind === SyntaxKind.JsxText; + || kind === SyntaxKind.JsxText + || kind === SyntaxKind.JsxFragment; } /* @internal */ diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 7d46630e227..0b40e20a7b7 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -819,6 +819,12 @@ namespace ts { return updateJsxClosingElement(node, visitNode((node).tagName, visitor, isJsxTagNameExpression)); + case SyntaxKind.JsxFragment: + return updateJsxFragment(node, + visitNode((node).openingFragment, visitor, isJsxOpeningFragment), + nodesVisitor((node).children, visitor, isJsxChild), + visitNode((node).closingFragment, visitor, isJsxClosingFragment)); + case SyntaxKind.JsxAttribute: return updateJsxAttribute(node, visitNode((node).name, visitor, isIdentifier), @@ -1334,6 +1340,12 @@ namespace ts { result = reduceNode((node).closingElement, cbNode, result); break; + case SyntaxKind.JsxFragment: + result = reduceNode((node).openingFragment, cbNode, result); + result = reduceLeft((node).children, cbNode, result); + result = reduceNode((node).closingFragment, cbNode, result); + break; + case SyntaxKind.JsxSelfClosingElement: case SyntaxKind.JsxOpeningElement: result = reduceNode((node).tagName, cbNode, result); @@ -1573,13 +1585,13 @@ namespace ts { // Add additional properties in debug mode to assist with debugging. Object.defineProperties(objectAllocator.getSymbolConstructor().prototype, { - "__debugFlags": { get(this: Symbol) { return formatSymbolFlags(this.flags); } } + __debugFlags: { get(this: Symbol) { return formatSymbolFlags(this.flags); } } }); Object.defineProperties(objectAllocator.getTypeConstructor().prototype, { - "__debugFlags": { get(this: Type) { return formatTypeFlags(this.flags); } }, - "__debugObjectFlags": { get(this: Type) { return this.flags & TypeFlags.Object ? formatObjectFlags((this).objectFlags) : ""; } }, - "__debugTypeToString": { value(this: Type) { return this.checker.typeToString(this); } }, + __debugFlags: { get(this: Type) { return formatTypeFlags(this.flags); } }, + __debugObjectFlags: { get(this: Type) { return this.flags & TypeFlags.Object ? formatObjectFlags((this).objectFlags) : ""; } }, + __debugTypeToString: { value(this: Type) { return this.checker.typeToString(this); } }, }); const nodeConstructors = [ @@ -1592,11 +1604,11 @@ namespace ts { for (const ctor of nodeConstructors) { if (!ctor.prototype.hasOwnProperty("__debugKind")) { Object.defineProperties(ctor.prototype, { - "__debugKind": { get(this: Node) { return formatSyntaxKind(this.kind); } }, - "__debugModifierFlags": { get(this: Node) { return formatModifierFlags(getModifierFlagsNoCache(this)); } }, - "__debugTransformFlags": { get(this: Node) { return formatTransformFlags(this.transformFlags); } }, - "__debugEmitFlags": { get(this: Node) { return formatEmitFlags(getEmitFlags(this)); } }, - "__debugGetText": { + __debugKind: { get(this: Node) { return formatSyntaxKind(this.kind); } }, + __debugModifierFlags: { get(this: Node) { return formatModifierFlags(getModifierFlagsNoCache(this)); } }, + __debugTransformFlags: { get(this: Node) { return formatTransformFlags(this.transformFlags); } }, + __debugEmitFlags: { get(this: Node) { return formatEmitFlags(getEmitFlags(this)); } }, + __debugGetText: { value(this: Node, includeTrivia?: boolean) { if (nodeIsSynthesized(this)) return ""; const parseNode = getParseTreeNode(this); diff --git a/src/compiler/watch.ts b/src/compiler/watch.ts index 53692fe1e04..8e49bb71a15 100644 --- a/src/compiler/watch.ts +++ b/src/compiler/watch.ts @@ -230,7 +230,7 @@ namespace ts { function createWatchMode(rootFileNames: string[], compilerOptions: CompilerOptions, watchingHost?: WatchingSystemHost, configFileName?: string, configFileSpecs?: ConfigFileSpecs, configFileWildCardDirectories?: MapLike, optionsToExtendForConfigFile?: CompilerOptions) { let program: Program; - let needsReload: boolean; // true if the config file changed and needs to reload it from the disk + let reloadLevel: ConfigFileProgramReloadLevel; // level to indicate if the program needs to be reloaded from config file/just filenames etc let missingFilesMap: Map; // Map of file watchers for the missing files let watchedWildcardDirectories: Map; // map of watchers for the wild card directories in the config file let timerToUpdateProgram: any; // timer callback to recompile the program @@ -488,7 +488,7 @@ namespace ts { function scheduleProgramReload() { Debug.assert(!!configFileName); - needsReload = true; + reloadLevel = ConfigFileProgramReloadLevel.Full; scheduleProgramUpdate(); } @@ -496,17 +496,30 @@ namespace ts { timerToUpdateProgram = undefined; reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation)); - if (needsReload) { - reloadConfigFile(); + switch (reloadLevel) { + case ConfigFileProgramReloadLevel.Partial: + return reloadFileNamesFromConfigFile(); + case ConfigFileProgramReloadLevel.Full: + return reloadConfigFile(); + default: + return synchronizeProgram(); } - else { - synchronizeProgram(); + } + + function reloadFileNamesFromConfigFile() { + const result = getFileNamesFromConfigSpecs(configFileSpecs, getDirectoryPath(configFileName), compilerOptions, directoryStructureHost); + if (!configFileSpecs.filesSpecs && result.fileNames.length === 0) { + reportDiagnostic(getErrorForNoInputFiles(configFileSpecs, configFileName)); } + rootFileNames = result.fileNames; + + // Update the program + synchronizeProgram(); } function reloadConfigFile() { writeLog(`Reloading config file: ${configFileName}`); - needsReload = false; + reloadLevel = ConfigFileProgramReloadLevel.None; const cachedHost = directoryStructureHost as CachedDirectoryStructureHost; cachedHost.clearCache(); @@ -611,18 +624,14 @@ 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 (fileOrDirectoryPath !== directory && !isSupportedSourceFileName(fileOrDirectory, compilerOptions)) { + if (fileOrDirectoryPath !== directory && hasExtension(fileOrDirectoryPath) && !isSupportedSourceFileName(fileOrDirectory, compilerOptions)) { writeLog(`Project: ${configFileName} Detected file add/remove of non supported extension: ${fileOrDirectory}`); return; } // Reload is pending, do the reload - if (!needsReload) { - const result = getFileNamesFromConfigSpecs(configFileSpecs, getDirectoryPath(configFileName), compilerOptions, directoryStructureHost); - if (!configFileSpecs.filesSpecs && result.fileNames.length === 0) { - reportDiagnostic(getErrorForNoInputFiles(configFileSpecs, configFileName)); - } - rootFileNames = result.fileNames; + if (reloadLevel !== ConfigFileProgramReloadLevel.Full) { + reloadLevel = ConfigFileProgramReloadLevel.Partial; // Schedule Update the program scheduleProgramUpdate(); diff --git a/src/compiler/watchUtilities.ts b/src/compiler/watchUtilities.ts index f39024d5a7c..0cf38f372d9 100644 --- a/src/compiler/watchUtilities.ts +++ b/src/compiler/watchUtilities.ts @@ -2,6 +2,14 @@ /* @internal */ namespace ts { + export enum ConfigFileProgramReloadLevel { + None, + /** Update the file name list from the disk */ + Partial, + /** Reload completely by re-reading contents of config file from disk and updating program */ + Full + } + /** * Updates the existing missing file watches with the new set of missing files after new program is created */ diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index c58accb657c..30c5e47949f 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -211,8 +211,8 @@ class CompilerBaselineRunner extends RunnerBase { this.emit = false; const opts = this.options.split(","); - for (let i = 0; i < opts.length; i++) { - switch (opts[i]) { + for (const opt of opts) { + switch (opt) { case "emit": this.emit = true; break; diff --git a/src/harness/externalCompileRunner.ts b/src/harness/externalCompileRunner.ts new file mode 100644 index 00000000000..9b8fc8c4fc5 --- /dev/null +++ b/src/harness/externalCompileRunner.ts @@ -0,0 +1,67 @@ +/// +/// +abstract class ExternalCompileRunnerBase extends RunnerBase { + abstract testDir: string; + public enumerateTestFiles() { + return Harness.IO.getDirectories(this.testDir); + } + /** Setup the runner's tests so that they are ready to be executed by the harness + * The first test should be a describe/it block that sets up the harness's compiler instance appropriately + */ + public initializeTests(): void { + // Read in and evaluate the test list + const testList = this.tests && this.tests.length ? this.tests : this.enumerateTestFiles(); + + describe(`${this.kind()} code samples`, () => { + for (const test of testList) { + this.runTest(test); + } + }); + } + private runTest(directoryName: string) { + describe(directoryName, () => { + const cp = require("child_process"); + const path = require("path"); + const fs = require("fs"); + + it("should build successfully", () => { + const cwd = path.join(__dirname, "../../", this.testDir, directoryName); + const timeout = 600000; // 600s = 10 minutes + if (fs.existsSync(path.join(cwd, "package.json"))) { + if (fs.existsSync(path.join(cwd, "package-lock.json"))) { + fs.unlinkSync(path.join(cwd, "package-lock.json")); + } + const stdio = isWorker ? "pipe" : "inherit"; + const install = cp.spawnSync(`npm`, ["i"], { cwd, timeout, shell: true, stdio }); + if (install.status !== 0) throw new Error(`NPM Install for ${directoryName} failed!`); + } + Harness.Baseline.runBaseline(`${this.kind()}/${directoryName}.log`, () => { + const result = cp.spawnSync(`node`, [path.join(__dirname, "tsc.js")], { cwd, timeout, shell: true }); + // tslint:disable-next-line:no-null-keyword + return result.status === 0 && !result.stdout.length && !result.stderr.length ? null : `Exit Code: ${result.status} +Standard output: +${result.stdout.toString().replace(/\r\n/g, "\n")} + + +Standard error: +${result.stderr.toString().replace(/\r\n/g, "\n")}`; + }); + }); + }); + } +} + +class UserCodeRunner extends ExternalCompileRunnerBase { + public readonly testDir = "tests/cases/user/"; + public kind(): TestRunnerKind { + return "user"; + } +} + +class DefinitelyTypedRunner extends ExternalCompileRunnerBase { + public readonly testDir = "../DefinitelyTyped/types/"; + public workingDirectory = this.testDir; + public kind(): TestRunnerKind { + return "dt"; + } +} diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 7ba4e94902d..c9aa1c6403d 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -126,8 +126,8 @@ namespace FourSlash { // 0 - cancelled // >0 - not cancelled // <0 - not cancelled and value denotes number of isCancellationRequested after which token become cancelled - private static readonly NotCanceled: number = -1; - private numberOfCallsBeforeCancellation: number = TestCancellationToken.NotCanceled; + private static readonly notCanceled = -1; + private numberOfCallsBeforeCancellation = TestCancellationToken.notCanceled; public isCancellationRequested(): boolean { if (this.numberOfCallsBeforeCancellation < 0) { @@ -148,7 +148,7 @@ namespace FourSlash { } public resetCancelled(): void { - this.numberOfCallsBeforeCancellation = TestCancellationToken.NotCanceled; + this.numberOfCallsBeforeCancellation = TestCancellationToken.notCanceled; } } @@ -221,11 +221,9 @@ namespace FourSlash { private addMatchedInputFile(referenceFilePath: string, extensions: ReadonlyArray) { const inputFiles = this.inputFiles; const languageServiceAdapterHost = this.languageServiceAdapterHost; - if (!extensions) { - tryAdd(referenceFilePath); - } - else { - tryAdd(referenceFilePath) || ts.forEach(extensions, ext => tryAdd(referenceFilePath + ext)); + const didAdd = tryAdd(referenceFilePath); + if (extensions && !didAdd) { + ts.forEach(extensions, ext => tryAdd(referenceFilePath + ext)); } function tryAdd(path: string) { @@ -314,7 +312,7 @@ namespace FourSlash { const languageServiceAdapter = this.getLanguageServiceAdapter(testType, this.cancellationToken, compilationOptions); this.languageServiceAdapterHost = languageServiceAdapter.getHost(); - this.languageService = languageServiceAdapter.getLanguageService(); + this.languageService = memoWrap(languageServiceAdapter.getLanguageService(), this); // Wrap the LS to cache some expensive operations certain tests call repeatedly if (startResolveFileRef) { // Add the entry-point file itself into the languageServiceShimHost @@ -381,6 +379,39 @@ namespace FourSlash { // Open the first file by default this.openFile(0); + + function memoWrap(ls: ts.LanguageService, target: TestState): ts.LanguageService { + const cacheableMembers: (keyof typeof ls)[] = [ + "getCompletionsAtPosition", + "getCompletionEntryDetails", + "getCompletionEntrySymbol", + "getQuickInfoAtPosition", + "getSignatureHelpItems", + "getReferencesAtPosition", + "getDocumentHighlights", + ]; + const proxy = {} as ts.LanguageService; + for (const k in ls) { + const key = k as keyof typeof ls; + if (cacheableMembers.indexOf(key) === -1) { + proxy[key] = (...args: any[]) => (ls[key] as Function)(...args); + continue; + } + const memo = Utils.memoize( + (_version: number, _active: string, _caret: number, _selectEnd: number, _marker: string, ...args: any[]) => (ls[key] as Function)(...args), + (...args) => args.join("|,|") + ); + proxy[key] = (...args: any[]) => memo( + target.languageServiceAdapterHost.getScriptInfo(target.activeFile.fileName).version, + target.activeFile.fileName, + target.currentCaretPosition, + target.selectionEnd, + target.lastKnownMarker, + ...args + ); + } + return proxy; + } } private getFileContent(fileName: string): string { @@ -437,6 +468,10 @@ namespace FourSlash { public select(startMarker: string, endMarker: string) { const start = this.getMarkerByName(startMarker), end = this.getMarkerByName(endMarker); + ts.Debug.assert(start.fileName === end.fileName); + if (this.activeFile.fileName !== start.fileName) { + this.openFile(start.fileName); + } this.goToPosition(start.position); this.selectionEnd = end.position; } @@ -448,9 +483,7 @@ namespace FourSlash { } // Opens a file given its 0-based index or fileName - public openFile(index: number, content?: string, scriptKindName?: string): void; - public openFile(name: string, content?: string, scriptKindName?: string): void; - public openFile(indexOrName: any, content?: string, scriptKindName?: string) { + public openFile(indexOrName: number | string, content?: string, scriptKindName?: string): void { const fileToOpen: FourSlashFile = this.findFile(indexOrName); fileToOpen.fileName = ts.normalizeSlashes(fileToOpen.fileName); this.activeFile = fileToOpen; @@ -531,15 +564,31 @@ namespace FourSlash { } for (const { start, length, messageText, file } of errors) { - Harness.IO.log(" from: " + showPosition(file, start) + - ", to: " + showPosition(file, start + length) + + Harness.IO.log(" " + this.formatRange(file, start, length) + ", message: " + ts.flattenDiagnosticMessageText(messageText, Harness.IO.newLine()) + "\n"); } + } - function showPosition(file: ts.SourceFile, pos: number) { + private formatRange(file: ts.SourceFile, start: number, length: number) { + if (file) { + return `from: ${this.formatLineAndCharacterOfPosition(file, start)}, to: ${this.formatLineAndCharacterOfPosition(file, start + length)}`; + } + return "global"; + } + + private formatLineAndCharacterOfPosition(file: ts.SourceFile, pos: number) { + if (file) { const { line, character } = ts.getLineAndCharacterOfPosition(file, pos); return `${line}:${character}`; } + return "global"; + } + + private formatPosition(file: ts.SourceFile, pos: number) { + if (file) { + return file.fileName + "@" + pos; + } + return "global"; } public verifyNoErrors() { @@ -549,7 +598,7 @@ namespace FourSlash { if (errors.length) { this.printErrorLog(/*expectErrors*/ false, errors); const error = errors[0]; - this.raiseError(`Found an error: ${error.file.fileName}@${error.start}: ${error.messageText}`); + this.raiseError(`Found an error: ${this.formatPosition(error.file, error.start)}: ${error.messageText}`); } }); } @@ -583,19 +632,23 @@ namespace FourSlash { } public verifyGoToDefinition(arg0: any, endMarkerNames?: string | string[]) { - this.verifyGoToX(arg0, endMarkerNames, () => this.getGoToDefinition()); + this.verifyGoToX(arg0, endMarkerNames, () => this.getGoToDefinitionAndBoundSpan()); } private getGoToDefinition(): ts.DefinitionInfo[] { return this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition); } + private getGoToDefinitionAndBoundSpan(): ts.DefinitionInfoAndBoundSpan { + return this.languageService.getDefinitionAndBoundSpan(this.activeFile.fileName, this.currentCaretPosition); + } + public verifyGoToType(arg0: any, endMarkerNames?: string | string[]) { this.verifyGoToX(arg0, endMarkerNames, () => this.languageService.getTypeDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition)); } - private verifyGoToX(arg0: any, endMarkerNames: string | string[] | undefined, getDefs: () => ts.DefinitionInfo[] | undefined) { + private verifyGoToX(arg0: any, endMarkerNames: string | string[] | undefined, getDefs: () => ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined) { if (endMarkerNames) { this.verifyGoToXPlain(arg0, endMarkerNames, getDefs); } @@ -615,7 +668,7 @@ namespace FourSlash { } } - private verifyGoToXPlain(startMarkerNames: string | string[], endMarkerNames: string | string[], getDefs: () => ts.DefinitionInfo[] | undefined) { + private verifyGoToXPlain(startMarkerNames: string | string[], endMarkerNames: string | string[], getDefs: () => ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined) { for (const start of toArray(startMarkerNames)) { this.verifyGoToXSingle(start, endMarkerNames, getDefs); } @@ -627,26 +680,57 @@ namespace FourSlash { } } - private verifyGoToXSingle(startMarkerName: string, endMarkerNames: string | string[], getDefs: () => ts.DefinitionInfo[] | undefined) { + private verifyGoToXSingle(startMarkerName: string, endMarkerNames: string | string[], getDefs: () => ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined) { this.goToMarker(startMarkerName); - this.verifyGoToXWorker(toArray(endMarkerNames), getDefs); + this.verifyGoToXWorker(toArray(endMarkerNames), getDefs, startMarkerName); } - private verifyGoToXWorker(endMarkers: string[], getDefs: () => ts.DefinitionInfo[] | undefined) { - const definitions = getDefs() || []; + private verifyGoToXWorker(endMarkers: string[], getDefs: () => ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined, startMarkerName?: string) { + const defs = getDefs(); + let definitions: ts.DefinitionInfo[] | ReadonlyArray; + let testName: string; + + if (!defs || Array.isArray(defs)) { + definitions = defs as ts.DefinitionInfo[] || []; + testName = "goToDefinitions"; + } + else { + this.verifyDefinitionTextSpan(defs, startMarkerName); + + definitions = defs.definitions; + testName = "goToDefinitionsAndBoundSpan"; + } if (endMarkers.length !== definitions.length) { - this.raiseError(`goToDefinitions failed - expected to find ${endMarkers.length} definitions but got ${definitions.length}`); + this.raiseError(`${testName} failed - expected to find ${endMarkers.length} definitions but got ${definitions.length}`); } ts.zipWith(endMarkers, definitions, (endMarker, definition, i) => { const marker = this.getMarkerByName(endMarker); if (marker.fileName !== definition.fileName || marker.position !== definition.textSpan.start) { - this.raiseError(`goToDefinition failed for definition ${endMarker} (${i}): expected ${marker.fileName} at ${marker.position}, got ${definition.fileName} at ${definition.textSpan.start}`); + this.raiseError(`${testName} failed for definition ${endMarker} (${i}): expected ${marker.fileName} at ${marker.position}, got ${definition.fileName} at ${definition.textSpan.start}`); } }); } + private verifyDefinitionTextSpan(defs: ts.DefinitionInfoAndBoundSpan, startMarkerName: string) { + const range = this.testData.ranges.find(range => this.markerName(range.marker) === startMarkerName); + + if (!range && !defs.textSpan) { + return; + } + + if (!range) { + this.raiseError(`goToDefinitionsAndBoundSpan failed - found a TextSpan ${JSON.stringify(defs.textSpan)} when it wasn't expected.`); + } + else if (defs.textSpan.start !== range.start || defs.textSpan.length !== range.end - range.start) { + const expected: ts.TextSpan = { + start: range.start, length: range.end - range.start + }; + this.raiseError(`goToDefinitionsAndBoundSpan failed - expected to find TextSpan ${JSON.stringify(expected)} but got ${JSON.stringify(defs.textSpan)}`); + } + } + public verifyGetEmitOutputForCurrentFile(expected: string): void { const emit = this.languageService.getEmitOutput(this.activeFile.fileName); if (emit.outputFiles.length !== 1) { @@ -783,8 +867,8 @@ namespace FourSlash { }); } - public verifyCompletionListContains(entryId: ts.Completions.CompletionEntryIdentifier, text?: string, documentation?: string, kind?: string, spanIndex?: number, hasAction?: boolean) { - const completions = this.getCompletionListAtCaret(); + public verifyCompletionListContains(entryId: ts.Completions.CompletionEntryIdentifier, text?: string, documentation?: string, kind?: string, spanIndex?: number, hasAction?: boolean, options?: ts.GetCompletionsAtPositionOptions) { + const completions = this.getCompletionListAtCaret(options); if (completions) { this.assertItemInCompletionList(completions.entries, entryId, text, documentation, kind, spanIndex, hasAction); } @@ -804,38 +888,35 @@ namespace FourSlash { * @param expectedKind the kind of symbol (see ScriptElementKind) * @param spanIndex the index of the range that the completion item's replacement text span should match */ - public verifyCompletionListDoesNotContain(entryId: ts.Completions.CompletionEntryIdentifier, expectedText?: string, expectedDocumentation?: string, expectedKind?: string, spanIndex?: number) { - const that = this; + public verifyCompletionListDoesNotContain(entryId: ts.Completions.CompletionEntryIdentifier, expectedText?: string, expectedDocumentation?: string, expectedKind?: string, spanIndex?: number, options?: ts.GetCompletionsAtPositionOptions) { let replacementSpan: ts.TextSpan; if (spanIndex !== undefined) { replacementSpan = this.getTextSpanForRangeAtIndex(spanIndex); } - function filterByTextOrDocumentation(entry: ts.CompletionEntry) { - const details = that.getCompletionEntryDetails(entry.name); - const documentation = details && ts.displayPartsToString(details.documentation); - const text = details && ts.displayPartsToString(details.displayParts); - - // If any of the expected values are undefined, assume that users don't - // care about them. - if (replacementSpan && !TestState.textSpansEqual(replacementSpan, entry.replacementSpan)) { - return false; - } - else if (expectedText && text !== expectedText) { - return false; - } - else if (expectedDocumentation && documentation !== expectedDocumentation) { - return false; - } - - return true; - } - - const completions = this.getCompletionListAtCaret(); + const completions = this.getCompletionListAtCaret(options); if (completions) { let filterCompletions = completions.entries.filter(e => e.name === entryId.name && e.source === entryId.source); filterCompletions = expectedKind ? filterCompletions.filter(e => e.kind === expectedKind) : filterCompletions; - filterCompletions = filterCompletions.filter(filterByTextOrDocumentation); + filterCompletions = filterCompletions.filter(entry => { + const details = this.getCompletionEntryDetails(entry.name); + const documentation = details && ts.displayPartsToString(details.documentation); + const text = details && ts.displayPartsToString(details.displayParts); + + // If any of the expected values are undefined, assume that users don't + // care about them. + if (replacementSpan && !TestState.textSpansEqual(replacementSpan, entry.replacementSpan)) { + return false; + } + else if (expectedText && text !== expectedText) { + return false; + } + else if (expectedDocumentation && documentation !== expectedDocumentation) { + return false; + } + + return true; + }); if (filterCompletions.length !== 0) { // After filtered using all present criterion, if there are still symbol left in the list // then these symbols must meet the criterion for Not supposed to be in the list. So we @@ -1126,11 +1207,11 @@ Actual: ${stringify(fullActual)}`); this.raiseError(`verifyReferencesAtPositionListContains failed - could not find the item: ${stringify(missingItem)} in the returned list: (${stringify(references)})`); } - private getCompletionListAtCaret() { - return this.languageService.getCompletionsAtPosition(this.activeFile.fileName, this.currentCaretPosition); + private getCompletionListAtCaret(options?: ts.GetCompletionsAtPositionOptions): ts.CompletionInfo { + return this.languageService.getCompletionsAtPosition(this.activeFile.fileName, this.currentCaretPosition, options); } - private getCompletionEntryDetails(entryName: string, source?: string) { + private getCompletionEntryDetails(entryName: string, source?: string): ts.CompletionEntryDetails { return this.languageService.getCompletionEntryDetails(this.activeFile.fileName, this.currentCaretPosition, entryName, this.formatCodeSettings, source); } @@ -1721,7 +1802,7 @@ Actual: ${stringify(fullActual)}`); } else if (prevChar === " " && /A-Za-z_/.test(ch)) { /* Completions */ - this.languageService.getCompletionsAtPosition(this.activeFile.fileName, offset); + this.languageService.getCompletionsAtPosition(this.activeFile.fileName, offset, { includeExternalModuleExports: false }); } if (i % checkCadence === 0) { @@ -2296,7 +2377,7 @@ Actual: ${stringify(fullActual)}`); public applyCodeActionFromCompletion(markerName: string, options: FourSlashInterface.VerifyCompletionActionOptions) { this.goToMarker(markerName); - const actualCompletion = this.getCompletionListAtCaret().entries.find(e => e.name === options.name && e.source === options.source); + const actualCompletion = this.getCompletionListAtCaret({ includeExternalModuleExports: true }).entries.find(e => e.name === options.name && e.source === options.source); if (!actualCompletion.hasAction) { this.raiseError(`Completion for ${options.name} does not have an associated action.`); @@ -3026,7 +3107,7 @@ Actual: ${stringify(fullActual)}`); this.raiseError(`Expected "${stringify({ entryId, text, documentation, kind })}" to be in list [${itemsString}]`); } - private findFile(indexOrName: any) { + private findFile(indexOrName: string | number) { let result: FourSlashFile; if (typeof indexOrName === "number") { const index = indexOrName; @@ -3678,9 +3759,7 @@ namespace FourSlashInterface { this.state.goToImplementation(); } - public position(position: number, fileIndex?: number): void; - public position(position: number, fileName?: string): void; - public position(position: number, fileNameOrIndex?: any): void { + public position(position: number, fileNameOrIndex?: string | number): void { if (fileNameOrIndex !== undefined) { this.file(fileNameOrIndex); } @@ -3690,9 +3769,7 @@ namespace FourSlashInterface { // Opens a file, given either its index as it // appears in the test source, or its filename // as specified in the test metadata - public file(index: number, content?: string, scriptKindName?: string): void; - public file(name: string, content?: string, scriptKindName?: string): void; - public file(indexOrName: any, content?: string, scriptKindName?: string): void { + public file(indexOrName: number | string, content?: string, scriptKindName?: string): void { this.state.openFile(indexOrName, content, scriptKindName); } @@ -3734,15 +3811,15 @@ namespace FourSlashInterface { // Verifies the completion list contains the specified symbol. The // completion list is brought up if necessary - public completionListContains(entryId: string | ts.Completions.CompletionEntryIdentifier, text?: string, documentation?: string, kind?: string, spanIndex?: number, hasAction?: boolean) { + public completionListContains(entryId: string | ts.Completions.CompletionEntryIdentifier, text?: string, documentation?: string, kind?: string, spanIndex?: number, hasAction?: boolean, options?: ts.GetCompletionsAtPositionOptions) { if (typeof entryId === "string") { entryId = { name: entryId, source: undefined }; } if (this.negative) { - this.state.verifyCompletionListDoesNotContain(entryId, text, documentation, kind, spanIndex); + this.state.verifyCompletionListDoesNotContain(entryId, text, documentation, kind, spanIndex, options); } else { - this.state.verifyCompletionListContains(entryId, text, documentation, kind, spanIndex, hasAction); + this.state.verifyCompletionListContains(entryId, text, documentation, kind, spanIndex, hasAction, options); } } @@ -3899,16 +3976,14 @@ namespace FourSlashInterface { this.state.verifyGoToDefinitionIs(endMarkers); } - public goToDefinition(startMarkerName: string | string[], endMarkerName: string | string[]): void; - public goToDefinition(startsAndEnds: [string | string[], string | string[]][]): void; - public goToDefinition(startsAndEnds: { [startMarkerName: string]: string | string[] }): void; + public goToDefinition(startMarkerName: string | string[], endMarkerName: string | string[], range?: FourSlash.Range): void; + public goToDefinition(startsAndEnds: [string | string[], string | string[]][] | { [startMarkerName: string]: string | string[] }): void; public goToDefinition(arg0: any, endMarkerName?: string | string[]) { this.state.verifyGoToDefinition(arg0, endMarkerName); } public goToType(startMarkerName: string | string[], endMarkerName: string | string[]): void; - public goToType(startsAndEnds: [string | string[], string | string[]][]): void; - public goToType(startsAndEnds: { [startMarkerName: string]: string | string[] }): void; + public goToType(startsAndEnds: [string | string[], string | string[]][] | { [startMarkerName: string]: string | string[] }): void; public goToType(arg0: any, endMarkerName?: string | string[]) { this.state.verifyGoToType(arg0, endMarkerName); } diff --git a/src/harness/harness.ts b/src/harness/harness.ts index c6caeff0dd9..8a3202b88be 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -479,7 +479,7 @@ namespace Utils { } namespace Harness { - export interface IO { + export interface Io { newLine(): string; getCurrentDirectory(): string; useCaseSensitiveFileNames(): boolean; @@ -502,7 +502,7 @@ namespace Harness { tryEnableSourceMapsForHost?(): void; getEnvironmentVariable?(name: string): string; } - export let IO: IO; + export let IO: Io; // harness always uses one kind of new line // But note that `parseTestData` in `fourslash.ts` uses "\n" @@ -555,8 +555,7 @@ namespace Harness { try { fs.unlinkSync(path); } - catch (e) { - } + catch { /*ignore*/ } } export function directoryExists(path: string): boolean { @@ -575,14 +574,13 @@ namespace Harness { function filesInFolder(folder: string): string[] { let paths: string[] = []; - const files = fs.readdirSync(folder); - for (let i = 0; i < files.length; i++) { - const pathToFile = pathModule.join(folder, files[i]); + for (const file of fs.readdirSync(folder)) { + const pathToFile = pathModule.join(folder, file); const stat = fs.statSync(pathToFile); if (options.recursive && stat.isDirectory()) { paths = paths.concat(filesInFolder(pathToFile)); } - else if (stat.isFile() && (!spec || files[i].match(spec))) { + else if (stat.isFile() && (!spec || file.match(spec))) { paths.push(pathToFile); } } @@ -616,7 +614,7 @@ namespace Harness { namespace Http { function waitForXHR(xhr: XMLHttpRequest) { - while (xhr.readyState !== 4) { } + while (xhr.readyState !== 4) { } // tslint:disable-line no-empty return { status: xhr.status, responseText: xhr.responseText }; } @@ -784,9 +782,15 @@ namespace Harness { ? IO.newLine() + `//# sourceURL=${IO.resolvePath(tcServicesFileName)}` : ""); - export interface SourceMapEmitterCallback { - (emittedFile: string, emittedLine: number, emittedColumn: number, sourceFile: string, sourceLine: number, sourceColumn: number, sourceName: string): void; - } + export type SourceMapEmitterCallback = ( + emittedFile: string, + emittedLine: number, + emittedColumn: number, + sourceFile: string, + sourceLine: number, + sourceColumn: number, + sourceName: string, + ) => void; // Settings export let userSpecifiedRoot = ""; @@ -1108,11 +1112,11 @@ namespace Harness { case "string": return value; case "number": { - const number = parseInt(value, 10); - if (isNaN(number)) { + const numverValue = parseInt(value, 10); + if (isNaN(numverValue)) { throw new Error(`Value must be a number, got: ${JSON.stringify(value)}`); } - return number; + return numverValue; } // If not a primitive, the possible types are specified in what is effectively a map of options. case "list": @@ -1319,7 +1323,7 @@ namespace Harness { export const diagnosticSummaryMarker = "__diagnosticSummary"; export const globalErrorsMarker = "__globalErrors"; export function *iterateErrorBaseline(inputFiles: ReadonlyArray, diagnostics: ReadonlyArray, pretty?: boolean): IterableIterator<[string, string, number]> { - diagnostics = diagnostics.slice().sort(ts.compareDiagnostics); + 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 let totalErrorsReportedInNonLibraryFiles = 0; @@ -1575,10 +1579,8 @@ namespace Harness { // Preserve legacy behavior if (lastIndexWritten === undefined) { - for (let i = 0; i < codeLines.length; i++) { - const currentCodeLine = codeLines[i]; - typeLines += currentCodeLine + "\r\n"; - typeLines += "No type information for this code."; + for (const codeLine of codeLines) { + typeLines += codeLine + "\r\nNo type information for this code."; } } else { @@ -1704,7 +1706,7 @@ namespace Harness { export function *iterateOutputs(outputFiles: Harness.Compiler.GeneratedFile[]): IterableIterator<[string, string]> { // Collect, test, and sort the fileNames - outputFiles.sort((a, b) => ts.compareStrings(cleanName(a.fileName), cleanName(b.fileName))); + outputFiles.sort((a, b) => ts.compareStringsCaseSensitive(cleanName(a.fileName), cleanName(b.fileName))); const dupeCase = ts.createMap(); // Yield them for (const outputFile of outputFiles) { @@ -1864,8 +1866,7 @@ namespace Harness { let currentFileName: any = undefined; let refs: string[] = []; - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; + for (const line of lines) { const testMetaData = optionRegex.exec(line); if (testMetaData) { // Comment line, check for global/file @options and record them @@ -1962,7 +1963,7 @@ namespace Harness { /** Support class for baseline files */ export namespace Baseline { - const NoContent = ""; + const noContent = ""; export interface BaselineOptions { Subfolder?: string; @@ -2021,7 +2022,7 @@ namespace Harness { /* tslint:disable:no-null-keyword */ if (actual === null) { /* tslint:enable:no-null-keyword */ - actual = NoContent; + actual = noContent; } let expected = ""; @@ -2058,13 +2059,13 @@ namespace Harness { IO.deleteFile(actualFileName); } - const encoded_actual = Utils.encodeString(actual); - if (expected !== encoded_actual) { - if (actual === NoContent) { + const encodedActual = Utils.encodeString(actual); + if (expected !== encodedActual) { + if (actual === noContent) { IO.writeFile(actualFileName + ".delete", ""); } else { - IO.writeFile(actualFileName, encoded_actual); + IO.writeFile(actualFileName, encodedActual); } throw new Error(`The baseline file ${relativeFileName} has changed.`); } @@ -2145,8 +2146,8 @@ namespace Harness { return filePath.indexOf(Harness.libFolder) === 0; } - export function getDefaultLibraryFile(io: Harness.IO): Harness.Compiler.TestFile { - const libFile = Harness.userSpecifiedRoot + Harness.libFolder + Harness.Compiler.defaultLibFileName; + export function getDefaultLibraryFile(filePath: string, io: Harness.Io): Harness.Compiler.TestFile { + const libFile = Harness.userSpecifiedRoot + Harness.libFolder + ts.getBaseFileName(ts.normalizeSlashes(filePath)); return { unitName: libFile, content: io.readFile(libFile) }; } diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 64ef1b552f5..d4b5a9c2a16 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -108,7 +108,7 @@ namespace Harness.LanguageService { } class DefaultHostCancellationToken implements ts.HostCancellationToken { - public static readonly Instance = new DefaultHostCancellationToken(); + public static readonly instance = new DefaultHostCancellationToken(); public isCancellationRequested() { return false; @@ -126,7 +126,7 @@ namespace Harness.LanguageService { public typesRegistry: ts.Map | undefined; protected virtualFileSystem: Utils.VirtualFileSystem = new Utils.VirtualFileSystem(virtualFileSystemRoot, /*useCaseSensitiveFilenames*/false); - constructor(protected cancellationToken = DefaultHostCancellationToken.Instance, + constructor(protected cancellationToken = DefaultHostCancellationToken.instance, protected settings = ts.getDefaultCompilerOptions()) { } @@ -166,8 +166,7 @@ namespace Harness.LanguageService { throw new Error("No script with name '" + fileName + "'"); } - public openFile(_fileName: string, _content?: string, _scriptKindName?: string): void { - } + public openFile(_fileName: string, _content?: string, _scriptKindName?: string): void { /*overridden*/ } /** * @param line 0 based index @@ -237,9 +236,9 @@ namespace Harness.LanguageService { } - log(_: string): void { } - trace(_: string): void { } - error(_: string): void { } + log = ts.noop; + trace = ts.noop; + error = ts.noop; } export class NativeLanguageServiceAdapter implements LanguageServiceAdapter { @@ -413,11 +412,11 @@ namespace Harness.LanguageService { getEncodedSemanticClassifications(fileName: string, span: ts.TextSpan): ts.Classifications { return unwrapJSONCallResult(this.shim.getEncodedSemanticClassifications(fileName, span.start, span.length)); } - getCompletionsAtPosition(fileName: string, position: number): ts.CompletionInfo { - return unwrapJSONCallResult(this.shim.getCompletionsAtPosition(fileName, position)); + getCompletionsAtPosition(fileName: string, position: number, options: ts.GetCompletionsAtPositionOptions | undefined): ts.CompletionInfo { + return unwrapJSONCallResult(this.shim.getCompletionsAtPosition(fileName, position, options)); } - getCompletionEntryDetails(fileName: string, position: number, entryName: string, options: ts.FormatCodeOptions): ts.CompletionEntryDetails { - return unwrapJSONCallResult(this.shim.getCompletionEntryDetails(fileName, position, entryName, JSON.stringify(options))); + getCompletionEntryDetails(fileName: string, position: number, entryName: string, options: ts.FormatCodeOptions | undefined, source: string | undefined): ts.CompletionEntryDetails { + return unwrapJSONCallResult(this.shim.getCompletionEntryDetails(fileName, position, entryName, JSON.stringify(options), source)); } getCompletionEntrySymbol(): ts.Symbol { throw new Error("getCompletionEntrySymbol not implemented across the shim layer."); @@ -443,6 +442,9 @@ namespace Harness.LanguageService { getDefinitionAtPosition(fileName: string, position: number): ts.DefinitionInfo[] { return unwrapJSONCallResult(this.shim.getDefinitionAtPosition(fileName, position)); } + getDefinitionAndBoundSpan(fileName: string, position: number): ts.DefinitionInfoAndBoundSpan { + return unwrapJSONCallResult(this.shim.getDefinitionAndBoundSpan(fileName, position)); + } getTypeDefinitionAtPosition(fileName: string, position: number): ts.DefinitionInfo[] { return unwrapJSONCallResult(this.shim.getTypeDefinitionAtPosition(fileName, position)); } @@ -492,7 +494,7 @@ namespace Harness.LanguageService { 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): ts.TextInsertion { + getDocCommentTemplateAtPosition(fileName: string, position: number): ts.TextInsertion | undefined { return unwrapJSONCallResult(this.shim.getDocCommentTemplateAtPosition(fileName, position)); } isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean { @@ -541,9 +543,9 @@ namespace Harness.LanguageService { getClassifier(): ts.Classifier { return new ClassifierShimProxy(this.factory.createClassifierShim(this.host)); } getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { let shimResult: { - referencedFiles: ts.IFileReference[]; - typeReferenceDirectives: ts.IFileReference[]; - importedFiles: ts.IFileReference[]; + referencedFiles: ts.ShimsFileReference[]; + typeReferenceDirectives: ts.ShimsFileReference[]; + importedFiles: ts.ShimsFileReference[]; isLibFile: boolean; }; @@ -593,13 +595,8 @@ namespace Harness.LanguageService { super(cancellationToken, settings); } - onMessage(): void { - - } - - writeMessage(): void { - - } + onMessage = ts.noop; + writeMessage = ts.noop; setClient(client: ts.server.SessionClient) { this.client = client; @@ -625,13 +622,8 @@ namespace Harness.LanguageService { this.newLine = this.host.getNewLine(); } - onMessage(): void { - - } - - writeMessage(_message: string): void { - } - + onMessage = ts.noop; + writeMessage = ts.noop; // overridden write(message: string): void { this.writeMessage(message); } @@ -645,8 +637,7 @@ namespace Harness.LanguageService { return snapshot && snapshot.getText(0, snapshot.getLength()); } - writeFile(): void { - } + writeFile = ts.noop; resolvePath(path: string): string { return path; @@ -665,8 +656,7 @@ namespace Harness.LanguageService { return ""; } - exit(): void { - } + exit = ts.noop; createDirectory(_directoryName: string): void { return ts.notImplemented(); @@ -694,8 +684,7 @@ namespace Harness.LanguageService { return { close: ts.noop }; } - close(): void { - } + close = ts.noop; info(message: string): void { this.host.log(message); @@ -754,6 +743,7 @@ namespace Harness.LanguageService { create(info: ts.server.PluginCreateInfo) { const proxy = makeDefaultProxy(info); const langSvc: any = info.languageService; + // tslint:disable-next-line only-arrow-functions proxy.getQuickInfoAtPosition = function () { const parts = langSvc.getQuickInfoAtPosition.apply(langSvc, arguments); if (parts.displayParts.length > 0) { @@ -786,7 +776,7 @@ namespace Harness.LanguageService { module: () => ({ create(info: ts.server.PluginCreateInfo) { const proxy = makeDefaultProxy(info); - proxy.getSemanticDiagnostics = function (filename: string) { + proxy.getSemanticDiagnostics = filename => { const prev = info.languageService.getSemanticDiagnostics(filename); const sourceFile: ts.SourceFile = info.languageService.getSourceFile(filename); prev.push({ @@ -812,11 +802,12 @@ namespace Harness.LanguageService { }; } - function makeDefaultProxy(info: ts.server.PluginCreateInfo) { + function makeDefaultProxy(info: ts.server.PluginCreateInfo): ts.LanguageService { // tslint:disable-next-line:no-null-keyword const proxy = Object.create(/*prototype*/ null); const langSvc: any = info.languageService; for (const k of Object.keys(langSvc)) { + // tslint:disable-next-line only-arrow-functions proxy[k] = function () { return langSvc[k].apply(langSvc, arguments); }; diff --git a/src/harness/loggedIO.ts b/src/harness/loggedIO.ts index fcc163e77f3..37e8dddb3d7 100644 --- a/src/harness/loggedIO.ts +++ b/src/harness/loggedIO.ts @@ -14,19 +14,19 @@ interface FileInformation { interface FindFileResult { } -interface IOLogFile { +interface IoLogFile { path: string; codepage: number; result?: FileInformation; } -interface IOLog { +interface IoLog { timestamp: string; arguments: string[]; executingPath: string; currentDirectory: string; useCustomLibraryFile?: boolean; - filesRead: IOLogFile[]; + filesRead: IoLogFile[]; filesWritten: { path: string; contents?: string; @@ -80,16 +80,16 @@ interface IOLog { interface PlaybackControl { startReplayFromFile(logFileName: string): void; startReplayFromString(logContents: string): void; - startReplayFromData(log: IOLog): void; + startReplayFromData(log: IoLog): void; endReplay(): void; startRecord(logFileName: string): void; endRecord(): void; } namespace Playback { - let recordLog: IOLog = undefined; - let replayLog: IOLog = undefined; - let replayFilesRead: ts.Map | undefined = undefined; + let recordLog: IoLog = undefined; + let replayLog: IoLog = undefined; + let replayFilesRead: ts.Map | undefined = undefined; let recordLogFileNameBase = ""; interface Memoized { @@ -110,11 +110,11 @@ namespace Playback { return run; } - export interface PlaybackIO extends Harness.IO, PlaybackControl { } + export interface PlaybackIO extends Harness.Io, PlaybackControl { } export interface PlaybackSystem extends ts.System, PlaybackControl { } - function createEmptyLog(): IOLog { + function createEmptyLog(): IoLog { return { timestamp: (new Date()).toString(), arguments: [], @@ -134,7 +134,7 @@ namespace Playback { }; } - export function newStyleLogIntoOldStyleLog(log: IOLog, host: ts.System | Harness.IO, baseName: string) { + export function newStyleLogIntoOldStyleLog(log: IoLog, host: ts.System | Harness.Io, baseName: string) { for (const file of log.filesAppended) { if (file.contentsPath) { file.contents = host.readFile(ts.combinePaths(baseName, file.contentsPath)); @@ -167,7 +167,7 @@ namespace Playback { 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) { @@ -210,8 +210,8 @@ namespace Playback { } function initWrapper(wrapper: PlaybackSystem, underlying: ts.System): void; - function initWrapper(wrapper: PlaybackIO, underlying: Harness.IO): void; - function initWrapper(wrapper: PlaybackSystem | PlaybackIO, underlying: ts.System | Harness.IO): void { + function initWrapper(wrapper: PlaybackIO, underlying: Harness.Io): void; + function initWrapper(wrapper: PlaybackSystem | PlaybackIO, underlying: ts.System | Harness.Io): void { ts.forEach(Object.keys(underlying), prop => { (wrapper)[prop] = (underlying)[prop]; }); @@ -249,13 +249,33 @@ namespace Playback { wrapper.endRecord = () => { if (recordLog !== undefined) { let i = 0; - const fn = () => recordLogFileNameBase + i; - while (underlying.fileExists(ts.combinePaths(fn(), "test.json"))) i++; - underlying.writeFile(ts.combinePaths(fn(), "test.json"), JSON.stringify(oldStyleLogIntoNewStyleLog(recordLog, (path, string) => underlying.writeFile(path, string), fn()), null, 4)); // tslint:disable-line:no-null-keyword + const getBase = () => recordLogFileNameBase + i; + while (underlying.fileExists(ts.combinePaths(getBase(), "test.json"))) i++; + const newLog = oldStyleLogIntoNewStyleLog(recordLog, (path, str) => underlying.writeFile(path, str), getBase()); + underlying.writeFile(ts.combinePaths(getBase(), "test.json"), JSON.stringify(newLog, null, 4)); // tslint:disable-line:no-null-keyword + const syntheticTsconfig = generateTsconfig(newLog); + if (syntheticTsconfig) { + underlying.writeFile(ts.combinePaths(getBase(), "tsconfig.json"), JSON.stringify(syntheticTsconfig, null, 4)); // tslint:disable-line:no-null-keyword + } recordLog = undefined; } }; + function generateTsconfig(newLog: IoLog): undefined | { compilerOptions: ts.CompilerOptions, files: string[] } { + if (newLog.filesRead.some(file => /tsconfig.+json$/.test(file.path))) { + return; + } + const files = []; + for (const file of newLog.filesRead) { + if (file.result.contentsPath && + Harness.isDefaultLibraryFile(file.result.contentsPath) && + /\.[tj]s$/.test(file.result.contentsPath)) { + files.push(file.result.contentsPath); + } + } + return { compilerOptions: ts.parseCommandLine(newLog.arguments).options, files }; + } + wrapper.fileExists = recordReplay(wrapper.fileExists, underlying)( path => callAndRecord(underlying.fileExists(path), recordLog.fileExists, { path }), memoize(path => { @@ -346,6 +366,7 @@ namespace Playback { function recordReplay(original: T, underlying: any) { function createWrapper(record: T, replay: T): T { + // tslint:disable-next-line only-arrow-functions return (function () { if (replayLog !== undefined) { return replay.apply(undefined, arguments); @@ -406,7 +427,7 @@ namespace Playback { // console.log("Swallowed write operation during replay: " + name); } - export function wrapIO(underlying: Harness.IO): PlaybackIO { + export function wrapIO(underlying: Harness.Io): PlaybackIO { const wrapper: PlaybackIO = {}; initWrapper(wrapper, underlying); diff --git a/src/harness/parallel/host.ts b/src/harness/parallel/host.ts index bf218c1b3a1..e278d267e1f 100644 --- a/src/harness/parallel/host.ts +++ b/src/harness/parallel/host.ts @@ -77,18 +77,18 @@ namespace Harness.Parallel.Host { console.log("Discovering runner-based tests..."); const discoverStart = +(new Date()); const { statSync }: { statSync(path: string): { size: number }; } = require("fs"); + const path: { join: (...args: string[]) => string } = require("path"); for (const runner of runners) { - const files = runner.enumerateTestFiles(); - for (const file of files) { + for (const file of runner.enumerateTestFiles()) { let size: number; if (!perfData) { try { - size = statSync(file).size; + size = statSync(path.join(runner.workingDirectory, file)).size; } catch { // May be a directory try { - size = Harness.IO.listFiles(file, /.*/g, { recursive: true }).reduce((acc, elem) => acc + statSync(elem).size, 0); + size = Harness.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 @@ -274,15 +274,15 @@ namespace Harness.Parallel.Host { function completeBar() { const isPartitionFail = failingFiles !== 0; const summaryColor = isPartitionFail ? "fail" : "green"; - const summarySymbol = isPartitionFail ? Base.symbols.err : Base.symbols.ok; + const summarySymbol = isPartitionFail ? base.symbols.err : base.symbols.ok; const summaryTests = (isPartitionFail ? totalPassing + "/" + (errorResults.length + totalPassing) : totalPassing) + " passing"; const summaryDuration = "(" + ms(duration) + ")"; - const savedUseColors = Base.useColors; - Base.useColors = !noColors; + const savedUseColors = base.useColors; + base.useColors = !noColors; const summary = color(summaryColor, summarySymbol + " " + summaryTests) + " " + color("light", summaryDuration); - Base.useColors = savedUseColors; + base.useColors = savedUseColors; updateProgress(1, summary); } @@ -307,22 +307,21 @@ namespace Harness.Parallel.Host { completeBar(); progressBars.disable(); - const reporter = new Base(); + const reporter = new base(); const stats = reporter.stats; const failures = reporter.failures; stats.passes = totalPassing; stats.failures = errorResults.length; stats.tests = totalPassing + errorResults.length; stats.duration = duration; - for (let j = 0; j < errorResults.length; j++) { - const failure = errorResults[j]; + for (const failure of errorResults) { failures.push(makeMochaTest(failure)); } if (noColors) { - const savedUseColors = Base.useColors; - Base.useColors = false; + const savedUseColors = base.useColors; + base.useColors = false; reporter.epilogue(); - Base.useColors = savedUseColors; + base.useColors = savedUseColors; } else { reporter.epilogue(); @@ -353,8 +352,8 @@ namespace Harness.Parallel.Host { return; } - let Mocha: any; - let Base: any; + let mocha: any; + let base: any; let color: any; let cursor: any; let readline: any; @@ -395,10 +394,10 @@ namespace Harness.Parallel.Host { } function initializeProgressBarsDependencies() { - Mocha = require("mocha"); - Base = Mocha.reporters.Base; - color = Base.color; - cursor = Base.cursor; + mocha = require("mocha"); + base = mocha.reporters.Base; + color = base.color; + cursor = base.cursor; readline = require("readline"); os = require("os"); tty = require("tty"); @@ -415,8 +414,8 @@ namespace Harness.Parallel.Host { const open = options.open || "["; const close = options.close || "]"; const complete = options.complete || "▬"; - const incomplete = options.incomplete || Base.symbols.dot; - const maxWidth = Base.window.width - open.length - close.length - 34; + const incomplete = options.incomplete || base.symbols.dot; + const maxWidth = base.window.width - open.length - close.length - 34; const width = minMax(options.width || maxWidth, 10, maxWidth); this._options = { open, diff --git a/src/harness/parallel/worker.ts b/src/harness/parallel/worker.ts index c32b9660a39..953ed5aeb21 100644 --- a/src/harness/parallel/worker.ts +++ b/src/harness/parallel/worker.ts @@ -57,7 +57,9 @@ namespace Harness.Parallel.Worker { return cleanup(); } try { - beforeFunc && beforeFunc(); + if (beforeFunc) { + beforeFunc(); + } } catch (e) { errors.push({ error: `Error executing before function: ${e.message}`, stack: e.stack, name: [...namestack] }); @@ -69,7 +71,9 @@ namespace Harness.Parallel.Worker { testList.forEach(({ name, callback, kind }) => executeCallback(name, callback, kind)); try { - afterFunc && afterFunc(); + if (afterFunc) { + afterFunc(); + } } catch (e) { errors.push({ error: `Error executing after function: ${e.message}`, stack: e.stack, name: [...namestack] }); diff --git a/src/harness/projectsRunner.ts b/src/harness/projectsRunner.ts index cc68f8625f4..c617cc7a0a3 100644 --- a/src/harness/projectsRunner.ts +++ b/src/harness/projectsRunner.ts @@ -140,12 +140,12 @@ class ProjectRunner extends RunnerBase { // Clean up source map data that will be used in baselining if (sourceMapData) { - for (let i = 0; i < sourceMapData.length; i++) { - for (let j = 0; j < sourceMapData[i].sourceMapSources.length; j++) { - sourceMapData[i].sourceMapSources[j] = cleanProjectUrl(sourceMapData[i].sourceMapSources[j]); + for (const data of sourceMapData) { + for (let j = 0; j < data.sourceMapSources.length; j++) { + data.sourceMapSources[j] = cleanProjectUrl(data.sourceMapSources[j]); } - sourceMapData[i].jsSourceMappingURL = cleanProjectUrl(sourceMapData[i].jsSourceMappingURL); - sourceMapData[i].sourceMapSourceRoot = cleanProjectUrl(sourceMapData[i].sourceMapSourceRoot); + data.jsSourceMappingURL = cleanProjectUrl(data.jsSourceMappingURL); + data.sourceMapSourceRoot = cleanProjectUrl(data.sourceMapSourceRoot); } } @@ -396,7 +396,7 @@ class ProjectRunner extends RunnerBase { }); // Dont allow config files since we are compiling existing source options - return compileProjectFiles(compilerResult.moduleKind, compilerResult.configFileSourceFiles, getInputFiles, getSourceFileText, writeFile, compilerResult.compilerOptions); + return compileProjectFiles(compilerResult.moduleKind, compilerResult.configFileSourceFiles, getInputFiles, getSourceFileText, /*writeFile*/ ts.noop, compilerResult.compilerOptions); function findOutputDtsFile(fileName: string) { return ts.forEach(compilerResult.outputFiles, outputFile => outputFile.emittedFileName === fileName ? outputFile : undefined); @@ -416,9 +416,6 @@ class ProjectRunner extends RunnerBase { } return undefined; } - - function writeFile() { - } } function getErrorsBaseline(compilerResult: CompileProjectFilesResult) { diff --git a/src/harness/runner.ts b/src/harness/runner.ts index db807b976bb..2bd098b742d 100644 --- a/src/harness/runner.ts +++ b/src/harness/runner.ts @@ -18,6 +18,7 @@ /// /// /// +/// /// /// @@ -26,8 +27,8 @@ let iterations = 1; function runTests(runners: RunnerBase[]) { for (let i = iterations; i > 0; i--) { - for (let j = 0; j < runners.length; j++) { - runners[j].initializeTests(); + for (const runner of runners) { + runner.initializeTests(); } } } @@ -59,6 +60,10 @@ function createRunner(kind: TestRunnerKind): RunnerBase { return new RWCRunner(); case "test262": return new Test262BaselineRunner(); + case "user": + return new UserCodeRunner(); + case "dt": + return new DefinitelyTypedRunner(); } ts.Debug.fail(`Unknown runner kind ${kind}`); } @@ -92,6 +97,7 @@ interface TestConfig { workerCount?: number; stackTraceLimit?: number | "full"; test?: string[]; + runners?: string[]; runUnitTests?: boolean; noColors?: boolean; } @@ -129,8 +135,9 @@ function handleTestConfig() { return true; } - if (testConfig.test && testConfig.test.length > 0) { - for (const option of testConfig.test) { + const runnerConfig = testConfig.runners || testConfig.test; + if (runnerConfig && runnerConfig.length > 0) { + for (const option of runnerConfig) { if (!option) { continue; } @@ -175,6 +182,12 @@ function handleTestConfig() { case "test262": runners.push(new Test262BaselineRunner()); break; + case "user": + runners.push(new UserCodeRunner()); + break; + case "dt": + runners.push(new DefinitelyTypedRunner()); + break; } } } @@ -196,6 +209,11 @@ function handleTestConfig() { runners.push(new FourSlashRunner(FourSlashTestType.ShimsWithPreprocess)); runners.push(new FourSlashRunner(FourSlashTestType.Server)); // runners.push(new GeneratedFourslashRunner()); + + // CRON-only tests + if (Utils.getExecutionEnvironment() !== Utils.ExecutionEnvironment.Browser && process.env.TRAVIS_EVENT_TYPE === "cron") { + runners.push(new UserCodeRunner()); + } } if (runUnitTests === undefined) { runUnitTests = runners.length !== 1; // Don't run unit tests when running only one runner if unit tests were not explicitly asked for @@ -207,6 +225,14 @@ function beginTests() { ts.Debug.enableDebugInfo(); } + // run tests in en-US by default. + let savedUILocale: string | undefined; + beforeEach(() => { + savedUILocale = ts.getUILocale(); + ts.setUILocale("en-US"); + }); + afterEach(() => ts.setUILocale(savedUILocale)); + runTests(runners); if (!runUnitTests) { @@ -215,8 +241,9 @@ function beginTests() { } } +let isWorker: boolean; function startTestEnvironment() { - const isWorker = handleTestConfig(); + isWorker = handleTestConfig(); if (Utils.getExecutionEnvironment() !== Utils.ExecutionEnvironment.Browser) { if (isWorker) { return Harness.Parallel.Worker.start(); diff --git a/src/harness/runnerbase.ts b/src/harness/runnerbase.ts index d50604803ed..80532d30b6f 100644 --- a/src/harness/runnerbase.ts +++ b/src/harness/runnerbase.ts @@ -1,13 +1,11 @@ /// -type TestRunnerKind = CompilerTestKind | FourslashTestKind | "project" | "rwc" | "test262"; +type TestRunnerKind = CompilerTestKind | FourslashTestKind | "project" | "rwc" | "test262" | "user" | "dt"; type CompilerTestKind = "conformance" | "compiler"; type FourslashTestKind = "fourslash" | "fourslash-shims" | "fourslash-shims-pp" | "fourslash-server"; abstract class RunnerBase { - constructor() { } - // contains the tests to run public tests: string[] = []; @@ -24,6 +22,9 @@ abstract class RunnerBase { abstract enumerateTestFiles(): string[]; + /** The working directory where tests are found. Needed for batch testing where the input path will differ from the output path inside baselines */ + public workingDirectory = ""; + /** Setup the runner's tests so that they are ready to be executed by the harness * The first test should be a describe/it block that sets up the harness's compiler instance appropriately */ diff --git a/src/harness/rwcRunner.ts b/src/harness/rwcRunner.ts index 2b4fc7b24e4..ef7a371b0c4 100644 --- a/src/harness/rwcRunner.ts +++ b/src/harness/rwcRunner.ts @@ -6,7 +6,7 @@ /* tslint:disable:no-null-keyword */ namespace RWC { - function runWithIOLog(ioLog: IOLog, fn: (oldIO: Harness.IO) => void) { + function runWithIOLog(ioLog: IoLog, fn: (oldIO: Harness.Io) => void) { const oldIO = Harness.IO; const wrappedIO = Playback.wrapIO(oldIO); @@ -58,7 +58,7 @@ namespace RWC { this.timeout(800000); // Allow long timeouts for RWC compilations let opts: ts.ParsedCommandLine; - const ioLog: IOLog = Playback.newStyleLogIntoOldStyleLog(JSON.parse(Harness.IO.readFile(`internal/cases/rwc/${jsonPath}/test.json`)), Harness.IO, `internal/cases/rwc/${baseName}`); + const ioLog: 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, () => { @@ -131,13 +131,14 @@ namespace RWC { } else { // set the flag to put default library to the beginning of the list - inputFiles.unshift(Harness.getDefaultLibraryFile(oldIO)); + inputFiles.unshift(Harness.getDefaultLibraryFile(fileRead.path, oldIO)); } } } } // do not use lib since we already read it in above + opts.options.lib = undefined; opts.options.noLib = true; // Emit the results @@ -245,10 +246,8 @@ class RWCRunner extends RunnerBase { */ public initializeTests(): void { // Read in and evaluate the test list - const testList = this.tests && this.tests.length ? this.tests : this.enumerateTestFiles(); - - for (let i = 0; i < testList.length; i++) { - this.runTest(testList[i]); + for (const test of this.tests && this.tests.length ? this.tests : this.enumerateTestFiles()) { + this.runTest(test); } } diff --git a/src/harness/sourceMapRecorder.ts b/src/harness/sourceMapRecorder.ts index de068706fbe..606d4e67acd 100644 --- a/src/harness/sourceMapRecorder.ts +++ b/src/harness/sourceMapRecorder.ts @@ -386,9 +386,9 @@ namespace Harness.SourceMapRecorder { if (currentSpan.decodeErrors) { // If there are decode errors, write - for (let i = 0; i < currentSpan.decodeErrors.length; i++) { + for (const decodeError of currentSpan.decodeErrors) { writeSourceMapIndent(prevEmittedCol, markerIds[index]); - sourceMapRecorder.WriteLine(currentSpan.decodeErrors[i]); + sourceMapRecorder.WriteLine(decodeError); } } @@ -442,8 +442,7 @@ namespace Harness.SourceMapRecorder { let prevSourceFile: ts.SourceFile; SourceMapSpanWriter.initializeSourceMapSpanWriter(sourceMapRecorder, sourceMapData, jsFiles[i]); - for (let j = 0; j < sourceMapData.sourceMapDecodedMappings.length; j++) { - const decodedSourceMapping = sourceMapData.sourceMapDecodedMappings[j]; + for (const decodedSourceMapping of sourceMapData.sourceMapDecodedMappings) { const currentSourceFile = program.getSourceFile(sourceMapData.inputSourceFileNames[decodedSourceMapping.sourceIndex]); if (currentSourceFile !== prevSourceFile) { SourceMapSpanWriter.recordNewSourceFileSpan(decodedSourceMapping, currentSourceFile.text); diff --git a/src/harness/tsconfig.json b/src/harness/tsconfig.json index 18baeb67c82..db38b95ba6a 100644 --- a/src/harness/tsconfig.json +++ b/src/harness/tsconfig.json @@ -60,20 +60,11 @@ "../services/jsTyping.ts", "../services/formatting/formatting.ts", "../services/formatting/formattingContext.ts", - "../services/formatting/formattingRequestKind.ts", "../services/formatting/formattingScanner.ts", - "../services/formatting/references.ts", "../services/formatting/rule.ts", - "../services/formatting/ruleAction.ts", - "../services/formatting/ruleDescriptor.ts", - "../services/formatting/ruleFlag.ts", - "../services/formatting/ruleOperation.ts", - "../services/formatting/ruleOperationContext.ts", "../services/formatting/rules.ts", "../services/formatting/rulesMap.ts", - "../services/formatting/rulesProvider.ts", "../services/formatting/smartIndenter.ts", - "../services/formatting/tokenRange.ts", "../services/codeFixProvider.ts", "../services/codefixes/fixes.ts", "../services/codefixes/helpers.ts", @@ -92,6 +83,7 @@ "projectsRunner.ts", "loggedIO.ts", "rwcRunner.ts", + "externalCompileRunner.ts", "test262Runner.ts", "./parallel/shared.ts", "./parallel/host.ts", diff --git a/src/harness/typeWriter.ts b/src/harness/typeWriter.ts index af626f1e548..17eda776bda 100644 --- a/src/harness/typeWriter.ts +++ b/src/harness/typeWriter.ts @@ -52,7 +52,7 @@ class TypeWriterWalker { } private *visitNode(node: ts.Node, isSymbolWalk: boolean): IterableIterator { - if (ts.isPartOfExpression(node) || node.kind === ts.SyntaxKind.Identifier) { + if (ts.isExpressionNode(node) || node.kind === ts.SyntaxKind.Identifier) { const result = this.writeTypeOrSymbol(node, isSymbolWalk); if (result) { yield result; diff --git a/src/harness/unittests/commandLineParsing.ts b/src/harness/unittests/commandLineParsing.ts index 01a208aa330..18e867cb9ea 100644 --- a/src/harness/unittests/commandLineParsing.ts +++ b/src/harness/unittests/commandLineParsing.ts @@ -60,7 +60,7 @@ namespace ts { assertParseResult(["--lib", "es5,invalidOption", "0.ts"], { errors: [{ - messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'esnext', 'dom', 'dom.iterable', 'webworker', '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', 'esnext.asynciterable'.", + messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'esnext', 'dom', 'dom.iterable', 'webworker', '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', 'esnext.asynciterable'.", category: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.category, code: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.code, @@ -263,7 +263,7 @@ namespace ts { assertParseResult(["--lib", "es5,", "es7", "0.ts"], { errors: [{ - messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'esnext', 'dom', 'dom.iterable', 'webworker', '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', 'esnext.asynciterable'.", + messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'esnext', 'dom', 'dom.iterable', 'webworker', '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', 'esnext.asynciterable'.", category: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.category, code: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.code, @@ -283,7 +283,7 @@ namespace ts { assertParseResult(["--lib", "es5, ", "es7", "0.ts"], { errors: [{ - messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'esnext', 'dom', 'dom.iterable', 'webworker', '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', 'esnext.asynciterable'.", + messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'esnext', 'dom', 'dom.iterable', 'webworker', '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', 'esnext.asynciterable'.", category: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.category, code: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.code, diff --git a/src/harness/unittests/compileOnSave.ts b/src/harness/unittests/compileOnSave.ts index 7be6ab5b323..7ef3e2aa1af 100644 --- a/src/harness/unittests/compileOnSave.ts +++ b/src/harness/unittests/compileOnSave.ts @@ -13,8 +13,8 @@ namespace ts.projectSystem { describe("CompileOnSave affected list", () => { function sendAffectedFileRequestAndCheckResult(session: server.Session, request: server.protocol.Request, expectedFileList: { projectFileName: string, files: FileOrFolder[] }[]) { const response = session.executeCommand(request).response as server.protocol.CompileOnSaveAffectedFileListSingleProject[]; - const actualResult = response.sort((list1, list2) => compareStrings(list1.projectFileName, list2.projectFileName)); - expectedFileList = expectedFileList.sort((list1, list2) => compareStrings(list1.projectFileName, list2.projectFileName)); + const actualResult = response.sort((list1, list2) => ts.compareStringsCaseSensitive(list1.projectFileName, list2.projectFileName)); + expectedFileList = expectedFileList.sort((list1, list2) => ts.compareStringsCaseSensitive(list1.projectFileName, list2.projectFileName)); assert.equal(actualResult.length, expectedFileList.length, `Actual result project number is different from the expected project number`); @@ -627,8 +627,8 @@ namespace ts.projectSystem { const mapFileContent = host.readFile(expectedMapFileName); verifyContentHasString(mapFileContent, `"sources":["${inputFileName}"]`); - function verifyContentHasString(content: string, string: string) { - assert.isTrue(content.indexOf(string) !== -1, `Expected "${content}" to have "${string}"`); + function verifyContentHasString(content: string, str: string) { + assert.isTrue(stringContains(content, str), `Expected "${content}" to have "${str}"`); } }); }); diff --git a/src/harness/unittests/configurationExtension.ts b/src/harness/unittests/configurationExtension.ts index 0032505aba1..5a1b155fbcf 100644 --- a/src/harness/unittests/configurationExtension.ts +++ b/src/harness/unittests/configurationExtension.ts @@ -25,9 +25,9 @@ namespace ts { }, "/dev/configs/tests.json": { compilerOptions: { - "preserveConstEnums": true, - "removeComments": false, - "sourceMap": true + preserveConstEnums: true, + removeComments: false, + sourceMap: true }, exclude: [ "../tests/baselines", @@ -52,7 +52,7 @@ namespace ts { "/dev/missing.json": { extends: "./missing2", compilerOptions: { - "types": [] + types: [] } }, "/dev/failure.json": { diff --git a/src/harness/unittests/convertCompilerOptionsFromJson.ts b/src/harness/unittests/convertCompilerOptionsFromJson.ts index c55dee26dc4..3a73971d7a3 100644 --- a/src/harness/unittests/convertCompilerOptionsFromJson.ts +++ b/src/harness/unittests/convertCompilerOptionsFromJson.ts @@ -58,12 +58,12 @@ namespace ts { it("Convert correctly format tsconfig.json to compiler-options ", () => { assertCompilerOptions( { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": false, - "sourceMap": false, - "lib": ["es5", "es2015.core", "es2015.symbol"] + compilerOptions: { + module: "commonjs", + target: "es5", + noImplicitAny: false, + sourceMap: false, + lib: ["es5", "es2015.core", "es2015.symbol"] } }, "tsconfig.json", { @@ -82,13 +82,13 @@ namespace ts { it("Convert correctly format tsconfig.json with allowJs is false to compiler-options ", () => { assertCompilerOptions( { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": false, - "sourceMap": false, - "allowJs": false, - "lib": ["es5", "es2015.core", "es2015.symbol"] + compilerOptions: { + module: "commonjs", + target: "es5", + noImplicitAny: false, + sourceMap: false, + allowJs: false, + lib: ["es5", "es2015.core", "es2015.symbol"] } }, "tsconfig.json", { @@ -108,12 +108,12 @@ namespace ts { it("Convert incorrect option of jsx to compiler-options ", () => { assertCompilerOptions( { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": false, - "sourceMap": false, - "jsx": "" + compilerOptions: { + module: "commonjs", + target: "es5", + noImplicitAny: false, + sourceMap: false, + jsx: "" } }, "tsconfig.json", { @@ -138,11 +138,11 @@ namespace ts { it("Convert incorrect option of module to compiler-options ", () => { assertCompilerOptions( { - "compilerOptions": { - "module": "", - "target": "es5", - "noImplicitAny": false, - "sourceMap": false, + compilerOptions: { + module: "", + target: "es5", + noImplicitAny: false, + sourceMap: false, } }, "tsconfig.json", { @@ -166,11 +166,11 @@ namespace ts { it("Convert incorrect option of newLine to compiler-options ", () => { assertCompilerOptions( { - "compilerOptions": { - "newLine": "", - "target": "es5", - "noImplicitAny": false, - "sourceMap": false, + compilerOptions: { + newLine: "", + target: "es5", + noImplicitAny: false, + sourceMap: false, } }, "tsconfig.json", { @@ -194,10 +194,10 @@ namespace ts { it("Convert incorrect option of target to compiler-options ", () => { assertCompilerOptions( { - "compilerOptions": { - "target": "", - "noImplicitAny": false, - "sourceMap": false, + compilerOptions: { + target: "", + noImplicitAny: false, + sourceMap: false, } }, "tsconfig.json", { @@ -220,10 +220,10 @@ namespace ts { it("Convert incorrect option of module-resolution to compiler-options ", () => { assertCompilerOptions( { - "compilerOptions": { - "moduleResolution": "", - "noImplicitAny": false, - "sourceMap": false, + compilerOptions: { + moduleResolution: "", + noImplicitAny: false, + sourceMap: false, } }, "tsconfig.json", { @@ -246,12 +246,12 @@ namespace ts { it("Convert incorrect option of libs to compiler-options ", () => { assertCompilerOptions( { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": false, - "sourceMap": false, - "lib": ["es5", "es2015.core", "incorrectLib"] + compilerOptions: { + module: "commonjs", + target: "es5", + noImplicitAny: false, + sourceMap: false, + lib: ["es5", "es2015.core", "incorrectLib"] } }, "tsconfig.json", { @@ -266,7 +266,7 @@ namespace ts { file: undefined, start: 0, length: 0, - messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'esnext', 'dom', 'dom.iterable', 'webworker', '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', 'esnext.asynciterable'.", + messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'esnext', 'dom', 'dom.iterable', 'webworker', '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', 'esnext.asynciterable'.", code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category }] @@ -277,12 +277,12 @@ namespace ts { it("Convert empty string option of libs to compiler-options ", () => { assertCompilerOptions( { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": false, - "sourceMap": false, - "lib": ["es5", ""] + compilerOptions: { + module: "commonjs", + target: "es5", + noImplicitAny: false, + sourceMap: false, + lib: ["es5", ""] } }, "tsconfig.json", { @@ -297,7 +297,7 @@ namespace ts { file: undefined, start: 0, length: 0, - messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'esnext', 'dom', 'dom.iterable', 'webworker', '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', 'esnext.asynciterable'.", + messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'esnext', 'dom', 'dom.iterable', 'webworker', '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', 'esnext.asynciterable'.", code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category }] @@ -308,12 +308,12 @@ namespace ts { it("Convert empty string option of libs to compiler-options ", () => { assertCompilerOptions( { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": false, - "sourceMap": false, - "lib": [""] + compilerOptions: { + module: "commonjs", + target: "es5", + noImplicitAny: false, + sourceMap: false, + lib: [""] } }, "tsconfig.json", { @@ -328,7 +328,7 @@ namespace ts { file: undefined, start: 0, length: 0, - messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'esnext', 'dom', 'dom.iterable', 'webworker', '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', 'esnext.asynciterable'.", + messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'esnext', 'dom', 'dom.iterable', 'webworker', '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', 'esnext.asynciterable'.", code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category }] @@ -339,12 +339,12 @@ namespace ts { it("Convert trailing-whitespace string option of libs to compiler-options ", () => { assertCompilerOptions( { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": false, - "sourceMap": false, - "lib": [" "] + compilerOptions: { + module: "commonjs", + target: "es5", + noImplicitAny: false, + sourceMap: false, + lib: [" "] } }, "tsconfig.json", { @@ -359,7 +359,7 @@ namespace ts { file: undefined, start: 0, length: 0, - messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'esnext', 'dom', 'dom.iterable', 'webworker', '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', 'esnext.asynciterable'.", + messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'esnext', 'dom', 'dom.iterable', 'webworker', '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', 'esnext.asynciterable'.", code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category }] @@ -370,12 +370,12 @@ namespace ts { it("Convert empty option of libs to compiler-options ", () => { assertCompilerOptions( { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": false, - "sourceMap": false, - "lib": [] + compilerOptions: { + module: "commonjs", + target: "es5", + noImplicitAny: false, + sourceMap: false, + lib: [] } }, "tsconfig.json", { @@ -394,8 +394,8 @@ namespace ts { it("Convert incorrectly format tsconfig.json to compiler-options ", () => { assertCompilerOptions( { - "compilerOptions": { - "modu": "commonjs", + compilerOptions: { + modu: "commonjs", } }, "tsconfig.json", { @@ -421,16 +421,34 @@ namespace ts { ); }); + it("Convert negative numbers in tsconfig.json ", () => { + assertCompilerOptions( + { + compilerOptions: { + allowJs: true, + maxNodeModuleJsDepth: -1 + } + }, "tsconfig.json", + { + compilerOptions: { + allowJs: true, + maxNodeModuleJsDepth: -1 + }, + errors: [] + } + ); + }); + // jsconfig.json it("Convert correctly format jsconfig.json to compiler-options ", () => { assertCompilerOptions( { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": false, - "sourceMap": false, - "lib": ["es5", "es2015.core", "es2015.symbol"] + compilerOptions: { + module: "commonjs", + target: "es5", + noImplicitAny: false, + sourceMap: false, + lib: ["es5", "es2015.core", "es2015.symbol"] } }, "jsconfig.json", { @@ -453,13 +471,13 @@ namespace ts { it("Convert correctly format jsconfig.json with allowJs is false to compiler-options ", () => { assertCompilerOptions( { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": false, - "sourceMap": false, - "allowJs": false, - "lib": ["es5", "es2015.core", "es2015.symbol"] + compilerOptions: { + module: "commonjs", + target: "es5", + noImplicitAny: false, + sourceMap: false, + allowJs: false, + lib: ["es5", "es2015.core", "es2015.symbol"] } }, "jsconfig.json", { @@ -482,8 +500,8 @@ namespace ts { it("Convert incorrectly format jsconfig.json to compiler-options ", () => { assertCompilerOptions( { - "compilerOptions": { - "modu": "commonjs", + compilerOptions: { + modu: "commonjs", } }, "jsconfig.json", { diff --git a/src/harness/unittests/convertTypeAcquisitionFromJson.ts b/src/harness/unittests/convertTypeAcquisitionFromJson.ts index 5a367edebbb..be1ada10a97 100644 --- a/src/harness/unittests/convertTypeAcquisitionFromJson.ts +++ b/src/harness/unittests/convertTypeAcquisitionFromJson.ts @@ -55,11 +55,11 @@ namespace ts { it("Convert deprecated typingOptions.enableAutoDiscovery format tsconfig.json to typeAcquisition ", () => { assertTypeAcquisition( { - "typingOptions": + typingOptions: { - "enableAutoDiscovery": true, - "include": ["0.d.ts", "1.d.ts"], - "exclude": ["0.js", "1.js"] + enableAutoDiscovery: true, + include: ["0.d.ts", "1.d.ts"], + exclude: ["0.js", "1.js"] } }, "tsconfig.json", @@ -77,11 +77,11 @@ namespace ts { it("Convert correctly format tsconfig.json to typeAcquisition ", () => { assertTypeAcquisition( { - "typeAcquisition": + typeAcquisition: { - "enable": true, - "include": ["0.d.ts", "1.d.ts"], - "exclude": ["0.js", "1.js"] + enable: true, + include: ["0.d.ts", "1.d.ts"], + exclude: ["0.js", "1.js"] } }, "tsconfig.json", @@ -99,9 +99,9 @@ namespace ts { it("Convert incorrect format tsconfig.json to typeAcquisition ", () => { assertTypeAcquisition( { - "typeAcquisition": + typeAcquisition: { - "enableAutoDiscovy": true, + enableAutoDiscovy: true, } }, "tsconfig.json", { @@ -140,9 +140,9 @@ namespace ts { it("Convert tsconfig.json with only enable property to typeAcquisition ", () => { assertTypeAcquisition( { - "typeAcquisition": + typeAcquisition: { - "enable": true + enable: true } }, "tsconfig.json", { @@ -160,11 +160,11 @@ namespace ts { it("Convert jsconfig.json to typeAcquisition ", () => { assertTypeAcquisition( { - "typeAcquisition": + typeAcquisition: { - "enable": false, - "include": ["0.d.ts"], - "exclude": ["0.js"] + enable: false, + include: ["0.d.ts"], + exclude: ["0.js"] } }, "jsconfig.json", { @@ -194,9 +194,9 @@ namespace ts { it("Convert incorrect format jsconfig.json to typeAcquisition ", () => { assertTypeAcquisition( { - "typeAcquisition": + typeAcquisition: { - "enableAutoDiscovy": true, + enableAutoDiscovy: true, } }, "jsconfig.json", { @@ -222,9 +222,9 @@ namespace ts { it("Convert jsconfig.json with only enable property to typeAcquisition ", () => { assertTypeAcquisition( { - "typeAcquisition": + typeAcquisition: { - "enable": false + enable: false } }, "jsconfig.json", { diff --git a/src/harness/unittests/extractRanges.ts b/src/harness/unittests/extractRanges.ts index e8e9a918f0d..493c9639c3d 100644 --- a/src/harness/unittests/extractRanges.ts +++ b/src/harness/unittests/extractRanges.ts @@ -191,7 +191,7 @@ function f() { } `, [ - refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalReturnStatement.message + refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalReturnStatement.message ]); testExtractRangeFailed("extractRangeFailed2", @@ -210,7 +210,7 @@ function f() { } `, [ - refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalBreakOrContinueStatements.message + refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message ]); testExtractRangeFailed("extractRangeFailed3", @@ -229,7 +229,7 @@ function f() { } `, [ - refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalBreakOrContinueStatements.message + refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message ]); testExtractRangeFailed("extractRangeFailed4", @@ -248,7 +248,7 @@ function f() { } `, [ - refactor.extractSymbol.Messages.CannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange.message + refactor.extractSymbol.Messages.cannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange.message ]); testExtractRangeFailed("extractRangeFailed5", @@ -269,7 +269,7 @@ function f2() { } `, [ - refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalReturnStatement.message + refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalReturnStatement.message ]); testExtractRangeFailed("extractRangeFailed6", @@ -290,7 +290,7 @@ function f2() { } `, [ - refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalReturnStatement.message + refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalReturnStatement.message ]); testExtractRangeFailed("extractRangeFailed7", @@ -303,7 +303,7 @@ while (x) { } `, [ - refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalBreakOrContinueStatements.message + refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message ]); testExtractRangeFailed("extractRangeFailed8", @@ -316,13 +316,13 @@ switch (x) { } `, [ - refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalBreakOrContinueStatements.message + refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message ]); testExtractRangeFailed("extractRangeFailed9", `var x = ([#||]1 + 2);`, [ - refactor.extractSymbol.Messages.CannotExtractEmpty.message + refactor.extractSymbol.Messages.cannotExtractEmpty.message ]); testExtractRangeFailed("extractRangeFailed10", @@ -333,7 +333,7 @@ switch (x) { } `, [ - refactor.extractSymbol.Messages.CannotExtractRange.message + refactor.extractSymbol.Messages.cannotExtractRange.message ]); testExtractRangeFailed("extractRangeFailed11", @@ -350,21 +350,21 @@ switch (x) { } `, [ - refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalBreakOrContinueStatements.message + refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message ]); testExtractRangeFailed("extractRangeFailed12", `let [#|x|];`, [ - refactor.extractSymbol.Messages.StatementOrExpressionExpected.message + refactor.extractSymbol.Messages.statementOrExpressionExpected.message ]); testExtractRangeFailed("extractRangeFailed13", `[#|return;|]`, [ - refactor.extractSymbol.Messages.CannotExtractRange.message + refactor.extractSymbol.Messages.cannotExtractRange.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]); }); } \ No newline at end of file diff --git a/src/harness/unittests/extractTestHelpers.ts b/src/harness/unittests/extractTestHelpers.ts index b8974694cfe..a04f443c3c9 100644 --- a/src/harness/unittests/extractTestHelpers.ts +++ b/src/harness/unittests/extractTestHelpers.ts @@ -67,33 +67,27 @@ namespace ts { } export const newLineCharacter = "\n"; - export const getRuleProvider = memoize(getRuleProviderInternal); - function getRuleProviderInternal() { - const options = { - indentSize: 4, - tabSize: 4, - newLineCharacter, - convertTabsToSpaces: true, - indentStyle: ts.IndentStyle.Smart, - insertSpaceAfterConstructor: false, - insertSpaceAfterCommaDelimiter: true, - insertSpaceAfterSemicolonInForStatements: true, - insertSpaceBeforeAndAfterBinaryOperators: true, - insertSpaceAfterKeywordsInControlFlowStatements: true, - insertSpaceAfterFunctionKeywordForAnonymousFunctions: false, - insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false, - insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false, - insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true, - insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false, - insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false, - insertSpaceBeforeFunctionParenthesis: false, - placeOpenBraceOnNewLineForFunctions: false, - placeOpenBraceOnNewLineForControlBlocks: false, - }; - const rulesProvider = new formatting.RulesProvider(); - rulesProvider.ensureUpToDate(options); - return rulesProvider; - } + export const testFormatOptions: ts.FormatCodeSettings = { + indentSize: 4, + tabSize: 4, + newLineCharacter, + convertTabsToSpaces: true, + indentStyle: ts.IndentStyle.Smart, + insertSpaceAfterConstructor: false, + insertSpaceAfterCommaDelimiter: true, + insertSpaceAfterSemicolonInForStatements: true, + insertSpaceBeforeAndAfterBinaryOperators: true, + insertSpaceAfterKeywordsInControlFlowStatements: true, + insertSpaceAfterFunctionKeywordForAnonymousFunctions: false, + insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false, + insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false, + insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true, + insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false, + insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false, + insertSpaceBeforeFunctionParenthesis: false, + placeOpenBraceOnNewLineForFunctions: false, + placeOpenBraceOnNewLineForControlBlocks: false, + }; const notImplementedHost: LanguageServiceHost = { getCompilationSettings: notImplemented, @@ -126,14 +120,14 @@ namespace ts { const sourceFile = program.getSourceFile(path); const context: RefactorContext = { - cancellationToken: { throwIfCancellationRequested() { }, isCancellationRequested() { return false; } }, + cancellationToken: { throwIfCancellationRequested: noop, isCancellationRequested: returnFalse }, newLineCharacter, program, file: sourceFile, startPosition: selectionRange.start, endPosition: selectionRange.end, host: notImplementedHost, - rulesProvider: getRuleProvider() + formatContext: formatting.getFormatContext(testFormatOptions), }; const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromBounds(selectionRange.start, selectionRange.end)); assert.equal(rangeToExtract.errors, undefined, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText); @@ -190,14 +184,14 @@ namespace ts { const program = projectService.inferredProjects[0].getLanguageService().getProgram(); const sourceFile = program.getSourceFile(f.path); const context: RefactorContext = { - cancellationToken: { throwIfCancellationRequested() { }, isCancellationRequested() { return false; } }, + cancellationToken: { throwIfCancellationRequested: noop, isCancellationRequested: returnFalse }, newLineCharacter, program, file: sourceFile, startPosition: selectionRange.start, endPosition: selectionRange.end, host: notImplementedHost, - rulesProvider: getRuleProvider() + formatContext: formatting.getFormatContext(testFormatOptions), }; const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromBounds(selectionRange.start, selectionRange.end)); assert.isUndefined(rangeToExtract.errors, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText); diff --git a/src/harness/unittests/hostNewLineSupport.ts b/src/harness/unittests/hostNewLineSupport.ts index 9f6b09dfb72..95a05f101f7 100644 --- a/src/harness/unittests/hostNewLineSupport.ts +++ b/src/harness/unittests/hostNewLineSupport.ts @@ -5,10 +5,10 @@ namespace ts { function snapFor(path: string): IScriptSnapshot { if (path === "lib.d.ts") { return { - dispose() {}, + dispose: noop, getChangeRange() { return undefined; }, getLength() { return 0; }, - getText(_start, _end) { + getText() { return ""; } }; @@ -16,7 +16,7 @@ namespace ts { const result = forEach(files, f => f.unitName === path ? f : undefined); if (result) { return { - dispose() {}, + dispose: noop, getChangeRange() { return undefined; }, getLength() { return result.content.length; }, getText(start, end) { diff --git a/src/harness/unittests/incrementalParser.ts b/src/harness/unittests/incrementalParser.ts index fbd8a60da92..c71b89d3da6 100644 --- a/src/harness/unittests/incrementalParser.ts +++ b/src/harness/unittests/incrementalParser.ts @@ -591,7 +591,7 @@ module m3 { }\ const index = 0; const newTextAndChange = withInsert(oldText, index, "declare "); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 3); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); it("Insert function above arrow function with comment", () => { @@ -674,7 +674,7 @@ module m3 { }\ const oldText = ScriptSnapshot.fromString(source); const newTextAndChange = withInsert(oldText, 0, "{"); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 9); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 4); }); it("Removing block around function declarations", () => { @@ -683,7 +683,7 @@ module m3 { }\ const oldText = ScriptSnapshot.fromString(source); const newTextAndChange = withDelete(oldText, 0, "{".length); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 9); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 4); }); it("Moving methods from class to object literal", () => { diff --git a/src/harness/unittests/languageService.ts b/src/harness/unittests/languageService.ts index fd0a95c167f..1407a518617 100644 --- a/src/harness/unittests/languageService.ts +++ b/src/harness/unittests/languageService.ts @@ -45,7 +45,7 @@ export function Component(x: Config): any;` readDirectory: noop as any, }); const definitions = languageService.getDefinitionAtPosition("foo.ts", 160); // 160 is the latter `vueTemplateHtml` position - expect(definitions).to.exist; + expect(definitions).to.exist; // tslint:disable-line no-unused-expression }); }); } \ No newline at end of file diff --git a/src/harness/unittests/moduleResolution.ts b/src/harness/unittests/moduleResolution.ts index 32301d6dccf..de79ba06cf9 100644 --- a/src/harness/unittests/moduleResolution.ts +++ b/src/harness/unittests/moduleResolution.ts @@ -127,7 +127,7 @@ namespace ts { function test(hasDirectoryExists: boolean) { const containingFile = { name: containingFileName }; - const packageJson = { name: packageJsonFileName, content: JSON.stringify({ "typings": fieldRef }) }; + const packageJson = { name: packageJsonFileName, content: JSON.stringify({ typings: fieldRef }) }; const moduleFile = { name: moduleFileName }; const resolution = nodeModuleNameResolver(moduleName, containingFile.name, {}, createModuleResolutionHost(hasDirectoryExists, containingFile, packageJson, moduleFile)); checkResolvedModule(resolution.resolvedModule, createResolvedModule(moduleFile.name)); @@ -149,7 +149,7 @@ namespace ts { function test(hasDirectoryExists: boolean) { const containingFile = { name: "/a/b.ts" }; - const packageJson = { name: "/node_modules/b/package.json", content: JSON.stringify({ "typings": typings }) }; + const packageJson = { name: "/node_modules/b/package.json", content: JSON.stringify({ typings }) }; const moduleFile = { name: "/a/b.d.ts" }; const indexPath = "/node_modules/b/index.d.ts"; @@ -163,7 +163,7 @@ namespace ts { it("module name as directory - handle invalid 'typings'", () => { testTypingsIgnored(["a", "b"]); - testTypingsIgnored({ "a": "b" }); + testTypingsIgnored({ a: "b" }); testTypingsIgnored(/*typings*/ true); testTypingsIgnored(/*typings*/ null); // tslint:disable-line no-null-keyword testTypingsIgnored(/*typings*/ undefined); @@ -803,7 +803,7 @@ import b = require("./moduleB"); function test(hasDirectoryExists: boolean) { const file1: File = { name: "/root/folder1/file1.ts" }; - const file1_1: File = { name: "/root/folder1/file1_1/index.d.ts" }; + const file1_1: File = { name: "/root/folder1/file1_1/index.d.ts" }; // tslint:disable-line variable-name const file2: File = { name: "/root/generated/folder1/file2.ts" }; const file3: File = { name: "/root/generated/folder2/file3.ts" }; const host = createModuleResolutionHost(hasDirectoryExists, file1, file1_1, file2, file3); diff --git a/src/harness/unittests/printer.ts b/src/harness/unittests/printer.ts index 4aaddce5c00..ad60484d963 100644 --- a/src/harness/unittests/printer.ts +++ b/src/harness/unittests/printer.ts @@ -55,6 +55,7 @@ namespace ts { printsCorrectly("removeComments", { removeComments: true }, printer => printer.printFile(sourceFile)); // github #14948 + // tslint:disable-next-line no-invalid-template-strings printsCorrectly("templateLiteral", {}, printer => printer.printFile(createSourceFile("source.ts", "let greeting = `Hi ${name}, how are you?`;", ScriptTarget.ES2017))); // github #18071 diff --git a/src/harness/unittests/reuseProgramStructure.ts b/src/harness/unittests/reuseProgramStructure.ts index e0c0e6f80a8..fdccc8a7795 100644 --- a/src/harness/unittests/reuseProgramStructure.ts +++ b/src/harness/unittests/reuseProgramStructure.ts @@ -243,111 +243,111 @@ namespace ts { ]; it("successful if change does not affect imports", () => { - const program_1 = newProgram(files, ["a.ts"], { target }); - const program_2 = updateProgram(program_1, ["a.ts"], { target }, files => { + const program1 = newProgram(files, ["a.ts"], { target }); + const program2 = updateProgram(program1, ["a.ts"], { target }, files => { files[0].text = files[0].text.updateProgram("var x = 100"); }); - assert.equal(program_1.structureIsReused, StructureIsReused.Completely); - const program1Diagnostics = program_1.getSemanticDiagnostics(program_1.getSourceFile("a.ts")); - const program2Diagnostics = program_2.getSemanticDiagnostics(program_1.getSourceFile("a.ts")); + assert.equal(program1.structureIsReused, StructureIsReused.Completely); + const program1Diagnostics = program1.getSemanticDiagnostics(program1.getSourceFile("a.ts")); + const program2Diagnostics = program2.getSemanticDiagnostics(program1.getSourceFile("a.ts")); assert.equal(program1Diagnostics.length, program2Diagnostics.length); }); it("successful if change does not affect type reference directives", () => { - const program_1 = newProgram(files, ["a.ts"], { target }); - const program_2 = updateProgram(program_1, ["a.ts"], { target }, files => { + const program1 = newProgram(files, ["a.ts"], { target }); + const program2 = updateProgram(program1, ["a.ts"], { target }, files => { files[0].text = files[0].text.updateProgram("var x = 100"); }); - assert.equal(program_1.structureIsReused, StructureIsReused.Completely); - const program1Diagnostics = program_1.getSemanticDiagnostics(program_1.getSourceFile("a.ts")); - const program2Diagnostics = program_2.getSemanticDiagnostics(program_1.getSourceFile("a.ts")); + assert.equal(program1.structureIsReused, StructureIsReused.Completely); + const program1Diagnostics = program1.getSemanticDiagnostics(program1.getSourceFile("a.ts")); + const program2Diagnostics = program2.getSemanticDiagnostics(program1.getSourceFile("a.ts")); assert.equal(program1Diagnostics.length, program2Diagnostics.length); }); it("fails if change affects tripleslash references", () => { - const program_1 = newProgram(files, ["a.ts"], { target }); - updateProgram(program_1, ["a.ts"], { target }, files => { + const program1 = newProgram(files, ["a.ts"], { target }); + updateProgram(program1, ["a.ts"], { target }, files => { const newReferences = `/// /// `; files[0].text = files[0].text.updateReferences(newReferences); }); - assert.equal(program_1.structureIsReused, StructureIsReused.SafeModules); + assert.equal(program1.structureIsReused, StructureIsReused.SafeModules); }); it("fails if change affects type references", () => { - const program_1 = newProgram(files, ["a.ts"], { types: ["a"] }); - updateProgram(program_1, ["a.ts"], { types: ["b"] }, noop); - assert.equal(program_1.structureIsReused, StructureIsReused.Not); + const program1 = newProgram(files, ["a.ts"], { types: ["a"] }); + updateProgram(program1, ["a.ts"], { types: ["b"] }, noop); + assert.equal(program1.structureIsReused, StructureIsReused.Not); }); it("succeeds if change doesn't affect type references", () => { - const program_1 = newProgram(files, ["a.ts"], { types: ["a"] }); - updateProgram(program_1, ["a.ts"], { types: ["a"] }, noop); - assert.equal(program_1.structureIsReused, StructureIsReused.Completely); + const program1 = newProgram(files, ["a.ts"], { types: ["a"] }); + updateProgram(program1, ["a.ts"], { types: ["a"] }, noop); + assert.equal(program1.structureIsReused, StructureIsReused.Completely); }); it("fails if change affects imports", () => { - const program_1 = newProgram(files, ["a.ts"], { target }); - updateProgram(program_1, ["a.ts"], { target }, files => { + const program1 = newProgram(files, ["a.ts"], { target }); + updateProgram(program1, ["a.ts"], { target }, files => { files[2].text = files[2].text.updateImportsAndExports("import x from 'b'"); }); - assert.equal(program_1.structureIsReused, StructureIsReused.SafeModules); + assert.equal(program1.structureIsReused, StructureIsReused.SafeModules); }); it("fails if change affects type directives", () => { - const program_1 = newProgram(files, ["a.ts"], { target }); - updateProgram(program_1, ["a.ts"], { target }, files => { + const program1 = newProgram(files, ["a.ts"], { target }); + updateProgram(program1, ["a.ts"], { target }, files => { const newReferences = ` /// /// /// `; files[0].text = files[0].text.updateReferences(newReferences); }); - assert.equal(program_1.structureIsReused, StructureIsReused.SafeModules); + assert.equal(program1.structureIsReused, StructureIsReused.SafeModules); }); it("fails if module kind changes", () => { - const program_1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS }); - updateProgram(program_1, ["a.ts"], { target, module: ModuleKind.AMD }, noop); - assert.equal(program_1.structureIsReused, StructureIsReused.Not); + const program1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS }); + updateProgram(program1, ["a.ts"], { target, module: ModuleKind.AMD }, noop); + assert.equal(program1.structureIsReused, StructureIsReused.Not); }); it("fails if rootdir changes", () => { - const program_1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS, rootDir: "/a/b" }); - updateProgram(program_1, ["a.ts"], { target, module: ModuleKind.CommonJS, rootDir: "/a/c" }, noop); - assert.equal(program_1.structureIsReused, StructureIsReused.Not); + const program1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS, rootDir: "/a/b" }); + updateProgram(program1, ["a.ts"], { target, module: ModuleKind.CommonJS, rootDir: "/a/c" }, noop); + assert.equal(program1.structureIsReused, StructureIsReused.Not); }); it("fails if config path changes", () => { - const program_1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS, configFilePath: "/a/b/tsconfig.json" }); - updateProgram(program_1, ["a.ts"], { target, module: ModuleKind.CommonJS, configFilePath: "/a/c/tsconfig.json" }, noop); - assert.equal(program_1.structureIsReused, StructureIsReused.Not); + const program1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS, configFilePath: "/a/b/tsconfig.json" }); + updateProgram(program1, ["a.ts"], { target, module: ModuleKind.CommonJS, configFilePath: "/a/c/tsconfig.json" }, noop); + assert.equal(program1.structureIsReused, StructureIsReused.Not); }); it("succeeds if missing files remain missing", () => { const options: CompilerOptions = { target, noLib: true }; - const program_1 = newProgram(files, ["a.ts"], options); - assert.notDeepEqual(emptyArray, program_1.getMissingFilePaths()); + const program1 = newProgram(files, ["a.ts"], options); + assert.notDeepEqual(emptyArray, program1.getMissingFilePaths()); - const program_2 = updateProgram(program_1, ["a.ts"], options, noop); - assert.deepEqual(program_1.getMissingFilePaths(), program_2.getMissingFilePaths()); + const program2 = updateProgram(program1, ["a.ts"], options, noop); + assert.deepEqual(program1.getMissingFilePaths(), program2.getMissingFilePaths()); - assert.equal(StructureIsReused.Completely, program_1.structureIsReused); + assert.equal(StructureIsReused.Completely, program1.structureIsReused); }); it("fails if missing file is created", () => { const options: CompilerOptions = { target, noLib: true }; - const program_1 = newProgram(files, ["a.ts"], options); - assert.notDeepEqual(emptyArray, program_1.getMissingFilePaths()); + 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 program_2 = updateProgram(program_1, ["a.ts"], options, noop, newTexts); - assert.deepEqual(emptyArray, program_2.getMissingFilePaths()); + const program2 = updateProgram(program1, ["a.ts"], options, noop, newTexts); + assert.deepEqual(emptyArray, program2.getMissingFilePaths()); - assert.equal(StructureIsReused.Not, program_1.structureIsReused); + assert.equal(StructureIsReused.Not, program1.structureIsReused); }); it("resolution cache follows imports", () => { @@ -359,34 +359,34 @@ namespace ts { ]; const options: CompilerOptions = { target }; - const program_1 = newProgram(files, ["a.ts"], options); - checkResolvedModulesCache(program_1, "a.ts", createMapFromTemplate({ "b": createResolvedModule("b.ts") })); - checkResolvedModulesCache(program_1, "b.ts", /*expectedContent*/ undefined); + const program1 = newProgram(files, ["a.ts"], options); + checkResolvedModulesCache(program1, "a.ts", createMapFromTemplate({ b: createResolvedModule("b.ts") })); + checkResolvedModulesCache(program1, "b.ts", /*expectedContent*/ undefined); - const program_2 = updateProgram(program_1, ["a.ts"], options, files => { + const program2 = updateProgram(program1, ["a.ts"], options, files => { files[0].text = files[0].text.updateProgram("var x = 2"); }); - assert.equal(program_1.structureIsReused, StructureIsReused.Completely); + assert.equal(program1.structureIsReused, StructureIsReused.Completely); // content of resolution cache should not change - checkResolvedModulesCache(program_1, "a.ts", createMapFromTemplate({ "b": createResolvedModule("b.ts") })); - checkResolvedModulesCache(program_1, "b.ts", /*expectedContent*/ undefined); + checkResolvedModulesCache(program1, "a.ts", createMapFromTemplate({ b: createResolvedModule("b.ts") })); + checkResolvedModulesCache(program1, "b.ts", /*expectedContent*/ undefined); // imports has changed - program is not reused - const program_3 = updateProgram(program_2, ["a.ts"], options, files => { + const program3 = updateProgram(program2, ["a.ts"], options, files => { files[0].text = files[0].text.updateImportsAndExports(""); }); - assert.equal(program_2.structureIsReused, StructureIsReused.SafeModules); - checkResolvedModulesCache(program_3, "a.ts", /*expectedContent*/ undefined); + assert.equal(program2.structureIsReused, StructureIsReused.SafeModules); + checkResolvedModulesCache(program3, "a.ts", /*expectedContent*/ undefined); - const program_4 = updateProgram(program_3, ["a.ts"], options, files => { + const program4 = updateProgram(program3, ["a.ts"], options, files => { const newImports = `import x from 'b' import y from 'c' `; files[0].text = files[0].text.updateImportsAndExports(newImports); }); - assert.equal(program_3.structureIsReused, StructureIsReused.SafeModules); - checkResolvedModulesCache(program_4, "a.ts", createMapFromTemplate({ "b": createResolvedModule("b.ts"), "c": undefined })); + assert.equal(program3.structureIsReused, StructureIsReused.SafeModules); + checkResolvedModulesCache(program4, "a.ts", createMapFromTemplate({ b: createResolvedModule("b.ts"), c: undefined })); }); it("resolved type directives cache follows type directives", () => { @@ -396,35 +396,35 @@ namespace ts { ]; const options: CompilerOptions = { target, typeRoots: ["/types"] }; - const program_1 = newProgram(files, ["/a.ts"], options); - checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMapFromTemplate({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } })); - checkResolvedTypeDirectivesCache(program_1, "/types/typedefs/index.d.ts", /*expectedContent*/ undefined); + const program1 = newProgram(files, ["/a.ts"], options); + checkResolvedTypeDirectivesCache(program1, "/a.ts", createMapFromTemplate({ typedefs: { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } })); + checkResolvedTypeDirectivesCache(program1, "/types/typedefs/index.d.ts", /*expectedContent*/ undefined); - const program_2 = updateProgram(program_1, ["/a.ts"], options, files => { + const program2 = updateProgram(program1, ["/a.ts"], options, files => { files[0].text = files[0].text.updateProgram("var x = 2"); }); - assert.equal(program_1.structureIsReused, StructureIsReused.Completely); + assert.equal(program1.structureIsReused, StructureIsReused.Completely); // content of resolution cache should not change - checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMapFromTemplate({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } })); - checkResolvedTypeDirectivesCache(program_1, "/types/typedefs/index.d.ts", /*expectedContent*/ undefined); + checkResolvedTypeDirectivesCache(program1, "/a.ts", createMapFromTemplate({ 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 - const program_3 = updateProgram(program_2, ["/a.ts"], options, files => { + const program3 = updateProgram(program2, ["/a.ts"], options, files => { files[0].text = files[0].text.updateReferences(""); }); - assert.equal(program_2.structureIsReused, StructureIsReused.SafeModules); - checkResolvedTypeDirectivesCache(program_3, "/a.ts", /*expectedContent*/ undefined); + assert.equal(program2.structureIsReused, StructureIsReused.SafeModules); + checkResolvedTypeDirectivesCache(program3, "/a.ts", /*expectedContent*/ undefined); - updateProgram(program_3, ["/a.ts"], options, files => { + updateProgram(program3, ["/a.ts"], options, files => { const newReferences = `/// /// `; files[0].text = files[0].text.updateReferences(newReferences); }); - assert.equal(program_3.structureIsReused, StructureIsReused.SafeModules); - checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMapFromTemplate({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } })); + assert.equal(program3.structureIsReused, StructureIsReused.SafeModules); + checkResolvedTypeDirectivesCache(program1, "/a.ts", createMapFromTemplate({ typedefs: { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } })); }); it("fetches imports after npm install", () => { @@ -529,18 +529,18 @@ namespace ts { "======== Module name 'fs' was not resolved. ========", ], "should look for 'fs'"); - const program_2 = updateProgram(program, program.getRootFileNames(), options, f => { + const program2 = updateProgram(program, program.getRootFileNames(), options, f => { f[0].text = f[0].text.updateProgram("var x = 1;"); }); - assert.deepEqual(program_2.host.getTrace(), [ + assert.deepEqual(program2.host.getTrace(), [ "Module 'fs' was resolved as ambient module declared in '/a/b/node.d.ts' since this file was not modified." ], "should reuse 'fs' since node.d.ts was not changed"); - const program_3 = updateProgram(program_2, program_2.getRootFileNames(), options, f => { + const program3 = updateProgram(program2, program2.getRootFileNames(), options, f => { f[0].text = f[0].text.updateProgram("var y = 1;"); f[1].text = f[1].text.updateProgram("declare var process: any"); }); - assert.deepEqual(program_3.host.getTrace(), + assert.deepEqual(program3.host.getTrace(), [ "======== Resolving module 'fs' from '/a/b/app.ts'. ========", "Module resolution kind is not specified, using 'Classic'.", @@ -598,10 +598,10 @@ namespace ts { ]; const options: CompilerOptions = { target: ScriptTarget.ES2015, traceResolution: true, moduleResolution: ModuleResolutionKind.Classic }; - const program_1 = newProgram(files, files.map(f => f.name), options); + const program1 = newProgram(files, files.map(f => f.name), options); let expectedErrors = 0; { - assert.deepEqual(program_1.host.getTrace(), + assert.deepEqual(program1.host.getTrace(), [ "======== Resolving type reference directive 'typerefs1', containing file 'f1.ts', root directory 'node_modules/@types'. ========", "Resolving with primary search path 'node_modules/@types'.", @@ -626,22 +626,22 @@ namespace ts { "File 'f1.ts' exist - use it as a name resolution result.", "======== Module name './f1' was successfully resolved to 'f1.ts'. ========" ], - "program_1: execute module resolution normally."); + "program1: execute module resolution normally."); - const program_1Diagnostics = program_1.getSemanticDiagnostics(program_1.getSourceFile("f2.ts")); - assert.lengthOf(program_1Diagnostics, expectedErrors, `initial program should be well-formed`); + const program1Diagnostics = program1.getSemanticDiagnostics(program1.getSourceFile("f2.ts")); + assert.lengthOf(program1Diagnostics, expectedErrors, `initial program should be well-formed`); } const indexOfF1 = 6; - const program_2 = updateProgram(program_1, program_1.getRootFileNames(), options, f => { + const program2 = updateProgram(program1, program1.getRootFileNames(), options, f => { const newSourceText = f[indexOfF1].text.updateReferences(`/// ${newLine}/// `); f[indexOfF1] = { name: "f1.ts", text: newSourceText }; }); { - const program_2Diagnostics = program_2.getSemanticDiagnostics(program_2.getSourceFile("f2.ts")); - assert.lengthOf(program_2Diagnostics, expectedErrors, `removing no-default-lib shouldn't affect any types used.`); + const program2Diagnostics = program2.getSemanticDiagnostics(program2.getSourceFile("f2.ts")); + assert.lengthOf(program2Diagnostics, expectedErrors, `removing no-default-lib shouldn't affect any types used.`); - assert.deepEqual(program_2.host.getTrace(), [ + assert.deepEqual(program2.host.getTrace(), [ "======== Resolving type reference directive 'typerefs1', containing file 'f1.ts', root directory 'node_modules/@types'. ========", "Resolving with primary search path 'node_modules/@types'.", "File 'node_modules/@types/typerefs1/package.json' does not exist.", @@ -658,19 +658,19 @@ namespace ts { "======== Type reference directive 'typerefs2' was successfully resolved to 'node_modules/@types/typerefs2/index.d.ts', primary: true. ========", "Reusing resolution of module './b2' to file 'f2.ts' from old program.", "Reusing resolution of module './f1' to file 'f2.ts' from old program." - ], "program_2: reuse module resolutions in f2 since it is unchanged"); + ], "program2: reuse module resolutions in f2 since it is unchanged"); } - const program_3 = updateProgram(program_2, program_2.getRootFileNames(), options, f => { + const program3 = updateProgram(program2, program2.getRootFileNames(), options, f => { const newSourceText = f[indexOfF1].text.updateReferences(`/// `); f[indexOfF1] = { name: "f1.ts", text: newSourceText }; }); { - const program_3Diagnostics = program_3.getSemanticDiagnostics(program_3.getSourceFile("f2.ts")); - assert.lengthOf(program_3Diagnostics, expectedErrors, `typerefs2 was unused, so diagnostics should be unaffected.`); + const program3Diagnostics = program3.getSemanticDiagnostics(program3.getSourceFile("f2.ts")); + assert.lengthOf(program3Diagnostics, expectedErrors, `typerefs2 was unused, so diagnostics should be unaffected.`); - assert.deepEqual(program_3.host.getTrace(), [ + assert.deepEqual(program3.host.getTrace(), [ "======== Resolving module './b1' from 'f1.ts'. ========", "Explicitly specified module resolution kind: 'Classic'.", "File 'b1.ts' exist - use it as a name resolution result.", @@ -682,20 +682,20 @@ namespace ts { "======== Type reference directive 'typerefs2' was successfully resolved to 'node_modules/@types/typerefs2/index.d.ts', primary: true. ========", "Reusing resolution of module './b2' to file 'f2.ts' from old program.", "Reusing resolution of module './f1' to file 'f2.ts' from old program." - ], "program_3: reuse module resolutions in f2 since it is unchanged"); + ], "program3: reuse module resolutions in f2 since it is unchanged"); } - const program_4 = updateProgram(program_3, program_3.getRootFileNames(), options, f => { + const program4 = updateProgram(program3, program3.getRootFileNames(), options, f => { const newSourceText = f[indexOfF1].text.updateReferences(""); f[indexOfF1] = { name: "f1.ts", text: newSourceText }; }); { - const program_4Diagnostics = program_4.getSemanticDiagnostics(program_4.getSourceFile("f2.ts")); - assert.lengthOf(program_4Diagnostics, expectedErrors, `a1.ts was unused, so diagnostics should be unaffected.`); + const program4Diagnostics = program4.getSemanticDiagnostics(program4.getSourceFile("f2.ts")); + assert.lengthOf(program4Diagnostics, expectedErrors, `a1.ts was unused, so diagnostics should be unaffected.`); - assert.deepEqual(program_4.host.getTrace(), [ + assert.deepEqual(program4.host.getTrace(), [ "======== Resolving module './b1' from 'f1.ts'. ========", "Explicitly specified module resolution kind: 'Classic'.", "File 'b1.ts' exist - use it as a name resolution result.", @@ -710,16 +710,16 @@ namespace ts { ], "program_4: reuse module resolutions in f2 since it is unchanged"); } - const program_5 = updateProgram(program_4, program_4.getRootFileNames(), options, f => { + const program5 = updateProgram(program4, program4.getRootFileNames(), options, f => { const newSourceText = f[indexOfF1].text.updateImportsAndExports(`import { B } from './b1';`); f[indexOfF1] = { name: "f1.ts", text: newSourceText }; }); { - const program_5Diagnostics = program_5.getSemanticDiagnostics(program_5.getSourceFile("f2.ts")); - assert.lengthOf(program_5Diagnostics, ++expectedErrors, `import of BB in f1 fails. BB is of type any. Add one error`); + 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.deepEqual(program_5.host.getTrace(), [ + assert.deepEqual(program5.host.getTrace(), [ "======== Resolving module './b1' from 'f1.ts'. ========", "Explicitly specified module resolution kind: 'Classic'.", "File 'b1.ts' exist - use it as a name resolution result.", @@ -727,16 +727,16 @@ namespace ts { ], "program_5: exports do not affect program structure, so f2's resolutions are silently reused."); } - const program_6 = updateProgram(program_5, program_5.getRootFileNames(), options, f => { + const program6 = updateProgram(program5, program5.getRootFileNames(), options, f => { const newSourceText = f[indexOfF1].text.updateProgram(""); f[indexOfF1] = { name: "f1.ts", text: newSourceText }; }); { - const program_6Diagnostics = program_6.getSemanticDiagnostics(program_6.getSourceFile("f2.ts")); - assert.lengthOf(program_6Diagnostics, expectedErrors, `import of BB in f1 fails.`); + const program6Diagnostics = program6.getSemanticDiagnostics(program6.getSourceFile("f2.ts")); + assert.lengthOf(program6Diagnostics, expectedErrors, `import of BB in f1 fails.`); - assert.deepEqual(program_6.host.getTrace(), [ + assert.deepEqual(program6.host.getTrace(), [ "======== Resolving module './b1' from 'f1.ts'. ========", "Explicitly specified module resolution kind: 'Classic'.", "File 'b1.ts' exist - use it as a name resolution result.", @@ -751,16 +751,16 @@ namespace ts { ], "program_6: reuse module resolutions in f2 since it is unchanged"); } - const program_7 = updateProgram(program_6, program_6.getRootFileNames(), options, f => { + const program7 = updateProgram(program6, program6.getRootFileNames(), options, f => { const newSourceText = f[indexOfF1].text.updateImportsAndExports(""); f[indexOfF1] = { name: "f1.ts", text: newSourceText }; }); { - const program_7Diagnostics = program_7.getSemanticDiagnostics(program_7.getSourceFile("f2.ts")); - assert.lengthOf(program_7Diagnostics, expectedErrors, `removing import is noop with respect to program, so no change in diagnostics.`); + 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.deepEqual(program_7.host.getTrace(), [ + assert.deepEqual(program7.host.getTrace(), [ "======== Resolving type reference directive 'typerefs2', containing file 'f2.ts', root directory 'node_modules/@types'. ========", "Resolving with primary search path 'node_modules/@types'.", "File 'node_modules/@types/typerefs2/package.json' does not exist.", @@ -820,47 +820,47 @@ namespace ts { } it("No changes -> redirect not broken", () => { - const program_1 = createRedirectProgram(); + const program1 = createRedirectProgram(); - const program_2 = updateRedirectProgram(program_1, files => { + const program2 = updateRedirectProgram(program1, files => { updateProgramText(files, root, "const x = 1;"); }); - assert.equal(program_1.structureIsReused, StructureIsReused.Completely); - assert.deepEqual(program_2.getSemanticDiagnostics(), emptyArray); + assert.equal(program1.structureIsReused, StructureIsReused.Completely); + assert.deepEqual(program2.getSemanticDiagnostics(), emptyArray); }); it("Target changes -> redirect broken", () => { - const program_1 = createRedirectProgram(); - assert.deepEqual(program_1.getSemanticDiagnostics(), emptyArray); + const program1 = createRedirectProgram(); + assert.deepEqual(program1.getSemanticDiagnostics(), emptyArray); - const program_2 = updateRedirectProgram(program_1, files => { + const program2 = updateRedirectProgram(program1, files => { updateProgramText(files, axIndex, "export default class X { private x: number; private y: number; }"); updateProgramText(files, axPackage, JSON.stringify('{ name: "x", version: "1.2.4" }')); }); - assert.equal(program_1.structureIsReused, StructureIsReused.Not); - assert.lengthOf(program_2.getSemanticDiagnostics(), 1); + assert.equal(program1.structureIsReused, StructureIsReused.Not); + assert.lengthOf(program2.getSemanticDiagnostics(), 1); }); it("Underlying changes -> redirect broken", () => { - const program_1 = createRedirectProgram(); + const program1 = createRedirectProgram(); - const program_2 = updateRedirectProgram(program_1, files => { + const program2 = updateRedirectProgram(program1, files => { updateProgramText(files, bxIndex, "export default class X { private x: number; private y: number; }"); updateProgramText(files, bxPackage, JSON.stringify({ name: "x", version: "1.2.4" })); }); - assert.equal(program_1.structureIsReused, StructureIsReused.Not); - assert.lengthOf(program_2.getSemanticDiagnostics(), 1); + assert.equal(program1.structureIsReused, StructureIsReused.Not); + assert.lengthOf(program2.getSemanticDiagnostics(), 1); }); it("Previously duplicate packages -> program structure not reused", () => { - const program_1 = createRedirectProgram({ bVersion: "1.2.4", bText: "export = class X { private x: number; }" }); + const program1 = createRedirectProgram({ bVersion: "1.2.4", bText: "export = class X { private x: number; }" }); - const program_2 = updateRedirectProgram(program_1, files => { + const program2 = updateRedirectProgram(program1, files => { updateProgramText(files, bxIndex, "export default class X { private x: number; }"); updateProgramText(files, bxPackage, JSON.stringify({ name: "x", version: "1.2.3" })); }); - assert.equal(program_1.structureIsReused, StructureIsReused.Not); - assert.deepEqual(program_2.getSemanticDiagnostics(), []); + assert.equal(program1.structureIsReused, StructureIsReused.Not); + assert.deepEqual(program2.getSemanticDiagnostics(), []); }); }); }); diff --git a/src/harness/unittests/services/colorization.ts b/src/harness/unittests/services/colorization.ts index eb2606bb08e..17d4132e9e5 100644 --- a/src/harness/unittests/services/colorization.ts +++ b/src/harness/unittests/services/colorization.ts @@ -1,12 +1,14 @@ /// +// tslint:disable no-invalid-template-strings (lots of tests use quoted code) + interface ClassificationEntry { value: any; classification: ts.TokenClass; position?: number; } -describe("Colorization", function () { +describe("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 classifier = languageServiceAdapter.getClassifier(); @@ -55,8 +57,8 @@ describe("Colorization", function () { } } - describe("test getClassifications", function () { - it("Returns correct token classes", function () { + describe("test getClassifications", () => { + it("Returns correct token classes", () => { testLexicalClassification("var x: string = \"foo\"; //Hello", ts.EndOfLineState.None, keyword("var"), @@ -70,7 +72,7 @@ describe("Colorization", function () { punctuation(";")); }); - it("correctly classifies a comment after a divide operator", function () { + it("correctly classifies a comment after a divide operator", () => { testLexicalClassification("1 / 2 // comment", ts.EndOfLineState.None, numberLiteral("1"), @@ -80,7 +82,7 @@ describe("Colorization", function () { comment("// comment")); }); - it("correctly classifies a literal after a divide operator", function () { + it("correctly classifies a literal after a divide operator", () => { testLexicalClassification("1 / 2, 3 / 4", ts.EndOfLineState.None, numberLiteral("1"), @@ -92,131 +94,131 @@ describe("Colorization", function () { operator(",")); }); - it("correctly classifies a multi-line string with one backslash", function () { + it("correctly classifies a multi-line string with one backslash", () => { testLexicalClassification("'line1\\", ts.EndOfLineState.None, stringLiteral("'line1\\"), finalEndOfLineState(ts.EndOfLineState.InSingleQuoteStringLiteral)); }); - it("correctly classifies a multi-line string with three backslashes", function () { + it("correctly classifies a multi-line string with three backslashes", () => { testLexicalClassification("'line1\\\\\\", ts.EndOfLineState.None, stringLiteral("'line1\\\\\\"), finalEndOfLineState(ts.EndOfLineState.InSingleQuoteStringLiteral)); }); - it("correctly classifies an unterminated single-line string with no backslashes", function () { + it("correctly classifies an unterminated single-line string with no backslashes", () => { testLexicalClassification("'line1", ts.EndOfLineState.None, stringLiteral("'line1"), finalEndOfLineState(ts.EndOfLineState.None)); }); - it("correctly classifies an unterminated single-line string with two backslashes", function () { + it("correctly classifies an unterminated single-line string with two backslashes", () => { testLexicalClassification("'line1\\\\", ts.EndOfLineState.None, stringLiteral("'line1\\\\"), finalEndOfLineState(ts.EndOfLineState.None)); }); - it("correctly classifies an unterminated single-line string with four backslashes", function () { + it("correctly classifies an unterminated single-line string with four backslashes", () => { testLexicalClassification("'line1\\\\\\\\", ts.EndOfLineState.None, stringLiteral("'line1\\\\\\\\"), finalEndOfLineState(ts.EndOfLineState.None)); }); - it("correctly classifies the continuing line of a multi-line string ending in one backslash", function () { + it("correctly classifies the continuing line of a multi-line string ending in one backslash", () => { testLexicalClassification("\\", ts.EndOfLineState.InDoubleQuoteStringLiteral, stringLiteral("\\"), finalEndOfLineState(ts.EndOfLineState.InDoubleQuoteStringLiteral)); }); - it("correctly classifies the continuing line of a multi-line string ending in three backslashes", function () { + it("correctly classifies the continuing line of a multi-line string ending in three backslashes", () => { testLexicalClassification("\\", ts.EndOfLineState.InDoubleQuoteStringLiteral, stringLiteral("\\"), finalEndOfLineState(ts.EndOfLineState.InDoubleQuoteStringLiteral)); }); - it("correctly classifies the last line of an unterminated multi-line string ending in no backslashes", function () { + it("correctly classifies the last line of an unterminated multi-line string ending in no backslashes", () => { testLexicalClassification(" ", ts.EndOfLineState.InDoubleQuoteStringLiteral, stringLiteral(" "), finalEndOfLineState(ts.EndOfLineState.None)); }); - it("correctly classifies the last line of an unterminated multi-line string ending in two backslashes", function () { + it("correctly classifies the last line of an unterminated multi-line string ending in two backslashes", () => { testLexicalClassification("\\\\", ts.EndOfLineState.InDoubleQuoteStringLiteral, stringLiteral("\\\\"), finalEndOfLineState(ts.EndOfLineState.None)); }); - it("correctly classifies the last line of an unterminated multi-line string ending in four backslashes", function () { + it("correctly classifies the last line of an unterminated multi-line string ending in four backslashes", () => { testLexicalClassification("\\\\\\\\", ts.EndOfLineState.InDoubleQuoteStringLiteral, stringLiteral("\\\\\\\\"), finalEndOfLineState(ts.EndOfLineState.None)); }); - it("correctly classifies the last line of a multi-line string", function () { + it("correctly classifies the last line of a multi-line string", () => { testLexicalClassification("'", ts.EndOfLineState.InSingleQuoteStringLiteral, stringLiteral("'"), finalEndOfLineState(ts.EndOfLineState.None)); }); - it("correctly classifies an unterminated multiline comment", function () { + it("correctly classifies an unterminated multiline comment", () => { testLexicalClassification("/*", ts.EndOfLineState.None, comment("/*"), finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia)); }); - it("correctly classifies the termination of a multiline comment", function () { + it("correctly classifies the termination of a multiline comment", () => { testLexicalClassification(" */ ", ts.EndOfLineState.InMultiLineCommentTrivia, comment(" */"), finalEndOfLineState(ts.EndOfLineState.None)); }); - it("correctly classifies the continuation of a multiline comment", function () { + it("correctly classifies the continuation of a multiline comment", () => { 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 '/*/'", function () { + it("correctly classifies an unterminated multiline comment on a line ending in '/*/'", () => { testLexicalClassification(" /*/", ts.EndOfLineState.None, comment("/*/"), finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia)); }); - it("correctly classifies an unterminated multiline comment with trailing space", function () { + it("correctly classifies an unterminated multiline comment with trailing space", () => { testLexicalClassification("/* ", ts.EndOfLineState.None, comment("/* "), finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia)); }); - it("correctly classifies a keyword after a dot", function () { + it("correctly classifies a keyword after a dot", () => { testLexicalClassification("a.var", ts.EndOfLineState.None, identifier("var")); }); - it("correctly classifies a string literal after a dot", function () { + it("correctly classifies a string literal after a dot", () => { testLexicalClassification("a.\"var\"", ts.EndOfLineState.None, stringLiteral("\"var\"")); }); - it("correctly classifies a keyword after a dot separated by comment trivia", function () { + it("correctly classifies a keyword after a dot separated by comment trivia", () => { testLexicalClassification("a./*hello world*/ var", ts.EndOfLineState.None, identifier("a"), @@ -225,21 +227,21 @@ describe("Colorization", function () { identifier("var")); }); - it("classifies a property access with whitespace around the dot", function () { + it("classifies a property access with whitespace around the dot", () => { testLexicalClassification(" x .\tfoo ()", ts.EndOfLineState.None, identifier("x"), identifier("foo")); }); - it("classifies a keyword after a dot on previous line", function () { + it("classifies a keyword after a dot on previous line", () => { testLexicalClassification("var", ts.EndOfLineState.None, keyword("var"), finalEndOfLineState(ts.EndOfLineState.None)); }); - it("classifies multiple keywords properly", function () { + it("classifies multiple keywords properly", () => { testLexicalClassification("public static", ts.EndOfLineState.None, keyword("public"), @@ -353,7 +355,7 @@ describe("Colorization", function () { } }); - it("classifies partially written generics correctly.", function () { + it("classifies partially written generics correctly.", () => { testLexicalClassification("Foo { testLexicalClassification("for (var of of of) { }", ts.EndOfLineState.None, keyword("for"), diff --git a/src/harness/unittests/services/patternMatcher.ts b/src/harness/unittests/services/patternMatcher.ts index 728636e9af2..fef382e8a3b 100644 --- a/src/harness/unittests/services/patternMatcher.ts +++ b/src/harness/unittests/services/patternMatcher.ts @@ -1,7 +1,7 @@ /// -describe("PatternMatcher", function () { - describe("BreakIntoCharacterSpans", function () { +describe("PatternMatcher", () => { + describe("BreakIntoCharacterSpans", () => { it("EmptyIdentifier", () => { verifyBreakIntoCharacterSpans(""); }); @@ -55,7 +55,7 @@ describe("PatternMatcher", function () { }); }); - describe("BreakIntoWordSpans", function () { + describe("BreakIntoWordSpans", () => { it("VarbatimIdentifier", () => { verifyBreakIntoWordSpans("@int:", "int"); }); diff --git a/src/harness/unittests/services/preProcessFile.ts b/src/harness/unittests/services/preProcessFile.ts index 6e77c27e4a8..1e13bc3e345 100644 --- a/src/harness/unittests/services/preProcessFile.ts +++ b/src/harness/unittests/services/preProcessFile.ts @@ -1,6 +1,6 @@ /// -describe("PreProcessFile:", function () { +describe("PreProcessFile:", () => { function test(sourceText: string, readImportFile: boolean, detectJavaScriptImports: boolean, expectedPreProcess: ts.PreProcessedFileInfo): void { const resultPreProcess = ts.preProcessFile(sourceText, readImportFile, detectJavaScriptImports); @@ -31,8 +31,8 @@ describe("PreProcessFile:", function () { } } - describe("Test preProcessFiles,", function () { - it("Correctly return referenced files from triple slash", function () { + describe("Test preProcessFiles,", () => { + it("Correctly return referenced files from triple slash", () => { test("///" + "\n" + "///" + "\n" + "///" + "\n" + "///", /*readImportFile*/ true, /*detectJavaScriptImports*/ false, @@ -46,7 +46,7 @@ describe("PreProcessFile:", function () { }); }), - it("Do not return reference path because of invalid triple-slash syntax", function () { + it("Do not return reference path because of invalid triple-slash syntax", () => { test("///" + "\n" + "///" + "\n" + "///" + "\n" + "///", /*readImportFile*/ true, /*detectJavaScriptImports*/ false, @@ -59,7 +59,7 @@ describe("PreProcessFile:", function () { }); }), - it("Correctly return imported files", function () { + 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, @@ -73,7 +73,7 @@ describe("PreProcessFile:", function () { }); }), - it("Do not return imported files if readImportFiles argument is false", function () { + 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, @@ -86,7 +86,7 @@ describe("PreProcessFile:", function () { }); }), - it("Do not return import path because of invalid import syntax", function () { + 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, @@ -99,7 +99,7 @@ describe("PreProcessFile:", function () { }); }), - it("Correctly return referenced files and import files", function () { + 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, @@ -112,7 +112,7 @@ describe("PreProcessFile:", function () { }); }), - it("Correctly return referenced files and import files even with some invalid syntax", function () { + 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, @@ -125,7 +125,7 @@ describe("PreProcessFile:", function () { }); }); - it("Correctly return ES6 imports", function () { + it("Correctly return ES6 imports", () => { test("import * as ns from \"m1\";" + "\n" + "import def, * as ns from \"m2\";" + "\n" + "import def from \"m3\";" + "\n" + @@ -152,7 +152,7 @@ describe("PreProcessFile:", function () { }); }); - it("Correctly return ES6 exports", function () { + it("Correctly return ES6 exports", () => { test("export * from \"m1\";" + "\n" + "export {a} from \"m2\";" + "\n" + "export {a as A} from \"m3\";" + "\n" + @@ -192,7 +192,7 @@ describe("PreProcessFile:", function () { }); }); - it("Correctly handles export import declarations", function () { + it("Correctly handles export import declarations", () => { test("export import a = require(\"m1\");", /*readImportFile*/ true, /*detectJavaScriptImports*/ false, @@ -206,7 +206,7 @@ describe("PreProcessFile:", function () { isLibFile: false }); }); - it("Correctly handles export require calls in JavaScript files", function () { + it("Correctly handles export require calls in JavaScript files", () => { test(` export import a = require("m1"); var x = require('m2'); @@ -228,7 +228,7 @@ describe("PreProcessFile:", function () { isLibFile: false }); }); - it("Correctly handles dependency lists in define([deplist]) calls in JavaScript files", function () { + it("Correctly handles dependency lists in define([deplist]) calls in JavaScript files", () => { test(` define(["mod1", "mod2"], (m1, m2) => { }); @@ -246,7 +246,7 @@ describe("PreProcessFile:", function () { isLibFile: false }); }); - it("Correctly handles dependency lists in define(modName, [deplist]) calls in JavaScript files", function () { + it("Correctly handles dependency lists in define(modName, [deplist]) calls in JavaScript files", () => { test(` define("mod", ["mod1", "mod2"], (m1, m2) => { }); @@ -278,7 +278,7 @@ describe("PreProcessFile:", function () { referencedFiles: [], typeReferenceDirectives: [], importedFiles: [ - { "fileName": "../Observable", "pos": 28, "end": 41 } + { fileName: "../Observable", pos: 28, end: 41 } ], ambientExternalModules: undefined, isLibFile: false @@ -298,8 +298,8 @@ describe("PreProcessFile:", function () { referencedFiles: [], typeReferenceDirectives: [], importedFiles: [ - { "fileName": "m", "pos": 123, "end": 124 }, - { "fileName": "../Observable", "pos": 28, "end": 41 } + { fileName: "m", pos: 123, end: 124 }, + { fileName: "../Observable", pos: 28, end: 41 } ], ambientExternalModules: undefined, isLibFile: false @@ -319,8 +319,8 @@ describe("PreProcessFile:", function () { referencedFiles: [], typeReferenceDirectives: [], importedFiles: [ - { "fileName": "m", "pos": 123, "end": 124 }, - { "fileName": "../Observable", "pos": 28, "end": 41 } + { fileName: "m", pos: 123, end: 124 }, + { fileName: "../Observable", pos: 28, end: 41 } ], ambientExternalModules: undefined, isLibFile: false @@ -340,7 +340,7 @@ describe("PreProcessFile:", function () { referencedFiles: [], typeReferenceDirectives: [], importedFiles: [ - { "fileName": "../Observable", "pos": 28, "end": 41 } + { fileName: "../Observable", pos: 28, end: 41 } ], ambientExternalModules: undefined, isLibFile: false @@ -360,7 +360,7 @@ describe("PreProcessFile:", function () { referencedFiles: [], typeReferenceDirectives: [], importedFiles: [ - { "fileName": "../Observable", "pos": 28, "end": 41 } + { fileName: "../Observable", pos: 28, end: 41 } ], ambientExternalModules: undefined, isLibFile: false @@ -379,7 +379,7 @@ describe("PreProcessFile:", function () { referencedFiles: [], typeReferenceDirectives: [], importedFiles: [ - { "fileName": "../Observable", "pos": 28, "end": 41 } + { fileName: "../Observable", pos: 28, end: 41 } ], ambientExternalModules: undefined, isLibFile: false @@ -400,8 +400,8 @@ describe("PreProcessFile:", function () { referencedFiles: [], typeReferenceDirectives: [], importedFiles: [ - { "fileName": "m2", "pos": 65, "end": 67 }, - { "fileName": "augmentation", "pos": 102, "end": 114 } + { fileName: "m2", pos: 65, end: 67 }, + { fileName: "augmentation", pos: 102, end: 114 } ], ambientExternalModules: ["m1"], isLibFile: false @@ -424,8 +424,8 @@ describe("PreProcessFile:", function () { referencedFiles: [], typeReferenceDirectives: [], importedFiles: [ - { "fileName": "m2", "pos": 127, "end": 129 }, - { "fileName": "augmentation", "pos": 164, "end": 176 } + { fileName: "m2", pos: 127, end: 129 }, + { fileName: "augmentation", pos: 164, end: 176 } ], ambientExternalModules: ["m1"], isLibFile: false @@ -442,12 +442,12 @@ describe("PreProcessFile:", function () { /*detectJavaScriptImports*/ false, { referencedFiles: [ - { "pos": 34, "end": 35, "fileName": "a" }, - { "pos": 112, "end": 114, "fileName": "a2" } + { pos: 34, end: 35, fileName: "a" }, + { pos: 112, end: 114, fileName: "a2" } ], typeReferenceDirectives: [ - { "pos": 73, "end": 75, "fileName": "a1" }, - { "pos": 152, "end": 154, "fileName": "a3" } + { pos: 73, end: 75, fileName: "a1" }, + { pos: 152, end: 154, fileName: "a3" } ], importedFiles: [], ambientExternalModules: undefined, diff --git a/src/harness/unittests/session.ts b/src/harness/unittests/session.ts index 3d9f782b2e0..871d4a37b9a 100644 --- a/src/harness/unittests/session.ts +++ b/src/harness/unittests/session.ts @@ -128,7 +128,7 @@ namespace ts.server { body: undefined }); }); - it ("should handle literal types in request", () => { + it("should handle literal types in request", () => { const configureRequest: protocol.ConfigureRequest = { command: CommandNames.Configure, seq: 0, @@ -186,6 +186,8 @@ namespace ts.server { CommandNames.Configure, CommandNames.Definition, CommandNames.DefinitionFull, + CommandNames.DefinitionAndBoundSpan, + CommandNames.DefinitionAndBoundSpanFull, CommandNames.Implementation, CommandNames.ImplementationFull, CommandNames.Exit, @@ -315,7 +317,7 @@ namespace ts.server { session.send = Session.prototype.send; assert(session.send); - expect(session.send(msg)).to.not.exist; + expect(session.send(msg)).to.not.exist; // tslint:disable-line no-unused-expression expect(lastWrittenToHost).to.equal(resultMsg); }); }); @@ -352,7 +354,7 @@ namespace ts.server { session.addProtocolHandler(command, () => resp); expect(() => session.addProtocolHandler(command, () => resp)) - .to.throw(`Protocol handler already exists for command "${command}"`); + .to.throw(`Protocol handler already exists for command "${command}"`); }); }); @@ -522,14 +524,14 @@ namespace ts.server { }); }); it("has access to the project service", () => { - class ServiceSession extends TestSession { + // tslint:disable-next-line no-unused-expression + new class extends TestSession { constructor() { super(); assert(this.projectService); expect(this.projectService).to.be.instanceOf(ProjectService); } - } - new ServiceSession(); + }(); }); }); diff --git a/src/harness/unittests/textChanges.ts b/src/harness/unittests/textChanges.ts index c37e50a2565..ed571b37399 100644 --- a/src/harness/unittests/textChanges.ts +++ b/src/harness/unittests/textChanges.ts @@ -23,60 +23,8 @@ namespace ts { const printerOptions = { newLine: NewLineKind.LineFeed }; const newLineCharacter = getNewLineCharacter(printerOptions); - const getRuleProviderDefault = memoize(() => { - const options = { - indentSize: 4, - tabSize: 4, - newLineCharacter, - convertTabsToSpaces: true, - indentStyle: ts.IndentStyle.Smart, - insertSpaceAfterConstructor: false, - insertSpaceAfterCommaDelimiter: true, - insertSpaceAfterSemicolonInForStatements: true, - insertSpaceBeforeAndAfterBinaryOperators: true, - insertSpaceAfterKeywordsInControlFlowStatements: true, - insertSpaceAfterFunctionKeywordForAnonymousFunctions: false, - insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false, - insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false, - insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true, - insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false, - insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false, - insertSpaceBeforeFunctionParenthesis: false, - placeOpenBraceOnNewLineForFunctions: false, - placeOpenBraceOnNewLineForControlBlocks: false, - }; - const rulesProvider = new formatting.RulesProvider(); - rulesProvider.ensureUpToDate(options); - return rulesProvider; - }); - const getRuleProviderNewlineBrace = memoize(() => { - const options = { - indentSize: 4, - tabSize: 4, - newLineCharacter, - convertTabsToSpaces: true, - indentStyle: ts.IndentStyle.Smart, - insertSpaceAfterConstructor: false, - insertSpaceAfterCommaDelimiter: true, - insertSpaceAfterSemicolonInForStatements: true, - insertSpaceBeforeAndAfterBinaryOperators: true, - insertSpaceAfterKeywordsInControlFlowStatements: true, - insertSpaceAfterFunctionKeywordForAnonymousFunctions: false, - insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false, - insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false, - insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true, - insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false, - insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false, - insertSpaceBeforeFunctionParenthesis: false, - placeOpenBraceOnNewLineForFunctions: true, - placeOpenBraceOnNewLineForControlBlocks: false, - }; - const rulesProvider = new formatting.RulesProvider(); - rulesProvider.ensureUpToDate(options); - return rulesProvider; - }); - function getRuleProvider(placeOpenBraceOnNewLineForFunctions: boolean) { - return placeOpenBraceOnNewLineForFunctions ? getRuleProviderNewlineBrace() : getRuleProviderDefault(); + function getRuleProvider(placeOpenBraceOnNewLineForFunctions: boolean): formatting.FormatContext { + return formatting.getFormatContext(placeOpenBraceOnNewLineForFunctions ? { ...testFormatOptions, placeOpenBraceOnNewLineForFunctions: true } : testFormatOptions); } // validate that positions that were recovered from the printed text actually match positions that will be created if the same text is parsed. @@ -122,9 +70,9 @@ namespace ts { { const text = ` -namespace M +namespace M { - namespace M2 + namespace M2 { function foo() { // comment 1 @@ -572,7 +520,7 @@ const x = 1;`; } { const text = ` -const x = 1, +const x = 1, y = 2;`; runSingleFileTest("insertNodeInListAfter6", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), createVariableDeclaration("z", /*type*/ undefined, createLiteral(1))); @@ -583,7 +531,7 @@ const x = 1, } { const text = ` -const /*x*/ x = 1, +const /*x*/ x = 1, /*y*/ y = 2;`; runSingleFileTest("insertNodeInListAfter8", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), createVariableDeclaration("z", /*type*/ undefined, createLiteral(1))); diff --git a/src/harness/unittests/transform.ts b/src/harness/unittests/transform.ts index bcdca3e3b60..a39249bb225 100644 --- a/src/harness/unittests/transform.ts +++ b/src/harness/unittests/transform.ts @@ -20,6 +20,15 @@ namespace ts { }; return (file: ts.SourceFile) => file; } + function replaceNumberWith2(context: ts.TransformationContext) { + function visitor(node: Node): Node { + if (isNumericLiteral(node)) { + return createNumericLiteral("2"); + } + return visitEachChild(node, visitor, context); + } + return (file: ts.SourceFile) => visitNode(file, visitor); + } function replaceIdentifiersNamedOldNameWithNewName(context: ts.TransformationContext) { const previousOnSubstituteNode = context.onSubstituteNode; @@ -101,6 +110,20 @@ namespace ts { }).outputText; }); + testBaseline("transformTypesInExportDefault", () => { + return ts.transpileModule(` + export default (foo: string) => { return 1; } + `, { + transformers: { + before: [replaceNumberWith2], + }, + compilerOptions: { + target: ts.ScriptTarget.ESNext, + newLine: NewLineKind.CarriageReturnLineFeed, + } + }).outputText; + }); + testBaseline("synthesizedClassAndNamespaceCombination", () => { return ts.transpileModule("", { transformers: { @@ -169,6 +192,38 @@ namespace ts { }; } }); + + // https://github.com/Microsoft/TypeScript/issues/19618 + testBaseline("transformAddImportStar", () => { + return ts.transpileModule("", { + transformers: { + before: [transformAddImportStar], + }, + compilerOptions: { + target: ts.ScriptTarget.ES5, + module: ts.ModuleKind.System, + newLine: NewLineKind.CarriageReturnLineFeed, + } + }).outputText; + + function transformAddImportStar(_context: ts.TransformationContext) { + return (sourceFile: ts.SourceFile): ts.SourceFile => { + return visitNode(sourceFile); + }; + function visitNode(sf: ts.SourceFile) { + // produce `import * as i0 from './comp'; + const importStar = ts.createImportDeclaration( + /*decorators*/ undefined, + /*modifiers*/ undefined, + /*importClause*/ ts.createImportClause( + /*name*/ undefined, + ts.createNamespaceImport(ts.createIdentifier("i0")) + ), + /*moduleSpecifier*/ ts.createLiteral("./comp1")); + return ts.updateSourceFileNode(sf, [importStar]); + } + } + }); }); } diff --git a/src/harness/unittests/transpile.ts b/src/harness/unittests/transpile.ts index 16bef6500f2..7c4af8be167 100644 --- a/src/harness/unittests/transpile.ts +++ b/src/harness/unittests/transpile.ts @@ -149,21 +149,21 @@ var x = 0;`, { `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);`, { - 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);`, { - 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", diff --git a/src/harness/unittests/tscWatchMode.ts b/src/harness/unittests/tscWatchMode.ts index c5aba73f2ac..fc80a6f39ef 100644 --- a/src/harness/unittests/tscWatchMode.ts +++ b/src/harness/unittests/tscWatchMode.ts @@ -710,12 +710,12 @@ namespace ts.tscWatch { path: "/src/tsconfig.json", content: JSON.stringify( { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": true, - "sourceMap": false, - "lib": [ + compilerOptions: { + module: "commonjs", + target: "es5", + noImplicitAny: true, + sourceMap: false, + lib: [ "es5" ] } @@ -725,12 +725,12 @@ namespace ts.tscWatch { path: config1.path, content: JSON.stringify( { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": true, - "sourceMap": false, - "lib": [ + compilerOptions: { + module: "commonjs", + target: "es5", + noImplicitAny: true, + sourceMap: false, + lib: [ "es5", "es2015.promise" ] @@ -1963,12 +1963,12 @@ declare module "fs" { const configFile: FileOrFolder = { path: "/a/rootFolder/project/tsconfig.json", content: JSON.stringify({ - "compilerOptions": { - "module": "none", - "allowJs": true, - "outDir": "Static/scripts/" + compilerOptions: { + module: "none", + allowJs: true, + outDir: "Static/scripts/" }, - "include": [ + include: [ "Scripts/**/*" ], }) @@ -1988,7 +1988,7 @@ declare module "fs" { checkProgramActualFiles(watch(), mapDefined(files, f => f === configFile ? undefined : f.path)); file1.content = "var zz30 = 100;"; - host.reloadFS(files, /*invokeDirectoryWatcherInsteadOfFileChanged*/ true); + host.reloadFS(files, { invokeDirectoryWatcherInsteadOfFileChanged: true }); host.runQueuedTimeoutCallbacks(); checkProgramActualFiles(watch(), mapDefined(files, f => f === configFile ? undefined : f.path)); diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index 5b6c36d071f..018934e9d7d 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -85,8 +85,7 @@ namespace ts.projectSystem { assert.equal(this.postExecActions.length, expectedCount, `Expected ${expectedCount} post install actions`); } - onProjectClosed() { - } + onProjectClosed = noop; attach(projectService: server.ProjectService) { this.projectService = projectService; @@ -437,6 +436,50 @@ namespace ts.projectSystem { verifyDiagnostics(actual, []); } + function assertEvent(actualOutput: string, expectedEvent: protocol.Event, host: TestServerHost) { + assert.equal(actualOutput, server.formatMessage(expectedEvent, nullLogger, Utils.byteLength, host.newLine)); + } + + function checkErrorMessage(host: TestServerHost, eventName: "syntaxDiag" | "semanticDiag", diagnostics: protocol.DiagnosticEventBody) { + const outputs = host.getOutput(); + assert.isTrue(outputs.length >= 1, outputs.toString()); + const event: protocol.Event = { + seq: 0, + type: "event", + event: eventName, + body: diagnostics + }; + assertEvent(outputs[0], event, host); + } + + function checkCompleteEvent(host: TestServerHost, numberOfCurrentEvents: number, expectedSequenceId: number) { + const outputs = host.getOutput(); + assert.equal(outputs.length, numberOfCurrentEvents, outputs.toString()); + const event: protocol.RequestCompletedEvent = { + seq: 0, + type: "event", + event: "requestCompleted", + body: { + request_seq: expectedSequenceId + } + }; + assertEvent(outputs[numberOfCurrentEvents - 1], event, host); + } + + function checkProjectUpdatedInBackgroundEvent(host: TestServerHost, openFiles: string[]) { + const outputs = host.getOutput(); + assert.equal(outputs.length, 1, outputs.toString()); + const event: protocol.ProjectsUpdatedInBackgroundEvent = { + seq: 0, + type: "event", + event: "projectsUpdatedInBackground", + body: { + openFiles + } + }; + assertEvent(outputs[0], event, host); + } + describe("tsserverProjectSystem", () => { const commonFile1: FileOrFolder = { path: "/a/b/commonFile1.ts", @@ -1248,13 +1291,13 @@ 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); + const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 2, { includeExternalModuleExports: false }); // 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'"); service.closeClientFile(f2.path); - const completions2 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 2); + const completions2 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 2, { includeExternalModuleExports: false }); // 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'"); @@ -1280,11 +1323,11 @@ 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); + const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 0, { includeExternalModuleExports: false }); 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); + const completions2 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 0, { includeExternalModuleExports: false }); 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, ""); @@ -1865,7 +1908,7 @@ namespace ts.projectSystem { // Specify .html extension as mixed content const extraFileExtensions = [{ extension: ".html", scriptKind: ScriptKind.JS, isMixedContent: true }]; const configureHostRequest = makeSessionRequest(CommandNames.Configure, { extraFileExtensions }); - session.executeCommand(configureHostRequest).response; + session.executeCommand(configureHostRequest); // The configured project should now be updated to include html file checkNumberOfProjects(projectService, { configuredProjects: 1 }); @@ -1884,7 +1927,7 @@ 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); + let completions = project.getLanguageService().getCompletionsAtPosition(file1.path, 1, { includeExternalModuleExports: false }); assert(completions && completions.entries[0].name === "hello", `expected entry hello to be in completion list`); // Close HTML file @@ -1898,7 +1941,7 @@ namespace ts.projectSystem { checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path, config.path]); // Check identifiers defined in HTML content are not available in .ts file - completions = project.getLanguageService().getCompletionsAtPosition(file1.path, 5); + completions = project.getLanguageService().getCompletionsAtPosition(file1.path, 5, { includeExternalModuleExports: false }); assert(completions && completions.entries[0].name !== "hello", `unexpected hello entry in completion list`); }); @@ -1924,7 +1967,7 @@ namespace ts.projectSystem { // 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 }); - session.executeCommand(configureHostRequest).response; + session.executeCommand(configureHostRequest); openFilesForSession([file1], session); let projectService = session.getProjectService(); @@ -1943,7 +1986,7 @@ namespace ts.projectSystem { host = createServerHost([file1, file2, config2, libFile], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") }); session = createSession(host); - session.executeCommand(configureHostRequest).response; + session.executeCommand(configureHostRequest); openFilesForSession([file1], session); projectService = session.getProjectService(); @@ -1962,7 +2005,7 @@ namespace ts.projectSystem { host = createServerHost([file1, file2, config3, libFile], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") }); session = createSession(host); - session.executeCommand(configureHostRequest).response; + session.executeCommand(configureHostRequest); openFilesForSession([file1], session); projectService = session.getProjectService(); @@ -1981,7 +2024,7 @@ namespace ts.projectSystem { host = createServerHost([file1, file2, config4, libFile], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") }); session = createSession(host); - session.executeCommand(configureHostRequest).response; + session.executeCommand(configureHostRequest); openFilesForSession([file1], session); projectService = session.getProjectService(); @@ -2000,7 +2043,7 @@ namespace ts.projectSystem { host = createServerHost([file1, file2, config5, libFile], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") }); session = createSession(host); - session.executeCommand(configureHostRequest).response; + session.executeCommand(configureHostRequest); openFilesForSession([file1], session); projectService = session.getProjectService(); @@ -2602,7 +2645,7 @@ namespace ts.projectSystem { projectFileName, rootFiles: [toExternalFile(site.path), toExternalFile(configFile.path)], options: { allowJs: false }, - typeAcquisition: { "include": [] } + typeAcquisition: { include: [] } }; projectService.openExternalProjects([externalProject]); @@ -2762,6 +2805,7 @@ namespace ts.projectSystem { watchedRecursiveDirectories.push(`${root}/a/b/src`, `${root}/a/b/node_modules`); checkWatchedDirectories(host, watchedRecursiveDirectories, /*recursive*/ true); }); + }); describe("Proper errors", () => { @@ -2783,6 +2827,139 @@ namespace ts.projectSystem { const project = projectService.findProject(corruptedConfig.path); checkProjectRootFiles(project, [file1.path]); }); + + describe("when opening new file that doesnt exist on disk yet", () => { + function verifyNonExistentFile(useProjectRoot: boolean) { + const host = createServerHost([libFile]); + let hasError = false; + const errLogger: server.Logger = { + close: noop, + hasLevel: () => true, + loggingEnabled: () => true, + perftrc: noop, + info: noop, + msg: (_s, type) => { + if (type === server.Msg.Err) { + hasError = true; + } + }, + startGroup: noop, + endGroup: noop, + getLogFileName: (): string => undefined + }; + const session = createSession(host, { canUseEvents: true, logger: errLogger, useInferredProjectPerProjectRoot: true }); + + const folderPath = "/user/someuser/projects/someFolder"; + const projectService = session.getProjectService(); + const untitledFile = "untitled:Untitled-1"; + session.executeCommandSeq({ + command: server.CommandNames.Open, + arguments: { + file: untitledFile, + fileContent: "", + scriptKindName: "JS", + projectRootPath: useProjectRoot ? folderPath : undefined + } + }); + checkNumberOfProjects(projectService, { inferredProjects: 1 }); + const infoForUntitledAtProjectRoot = projectService.getScriptInfoForPath(`${folderPath.toLowerCase()}/${untitledFile.toLowerCase()}` as Path); + const infoForUnitiledAtRoot = projectService.getScriptInfoForPath(`/${untitledFile.toLowerCase()}` as Path); + if (useProjectRoot) { + assert.isDefined(infoForUntitledAtProjectRoot); + assert.isUndefined(infoForUnitiledAtRoot); + } + else { + assert.isDefined(infoForUnitiledAtRoot); + assert.isUndefined(infoForUntitledAtProjectRoot); + } + host.checkTimeoutQueueLength(2); + + const newTimeoutId = host.getNextTimeoutId(); + const expectedSequenceId = session.getNextSeq(); + session.executeCommandSeq({ + command: server.CommandNames.Geterr, + arguments: { + delay: 0, + files: [untitledFile] + } + }); + host.checkTimeoutQueueLength(3); + + // Run the last one = get error request + host.runQueuedTimeoutCallbacks(newTimeoutId); + + assert.isFalse(hasError); + host.checkTimeoutQueueLength(2); + checkErrorMessage(host, "syntaxDiag", { file: untitledFile, diagnostics: [] }); + host.clearOutput(); + + host.runQueuedImmediateCallbacks(); + assert.isFalse(hasError); + checkErrorMessage(host, "semanticDiag", { file: untitledFile, diagnostics: [] }); + + checkCompleteEvent(host, 2, expectedSequenceId); + } + + it("has projectRoot", () => { + verifyNonExistentFile(/*useProjectRoot*/ true); + }); + + it("does not have projectRoot", () => { + verifyNonExistentFile(/*useProjectRoot*/ false); + }); + }); + + it("folder rename updates project structure and reports no errors", () => { + const projectDir = "/a/b/projects/myproject"; + const app: FileOrFolder = { + path: `${projectDir}/bar/app.ts`, + content: "class Bar implements foo.Foo { getFoo() { return ''; } get2() { return 1; } }" + }; + const foo: FileOrFolder = { + path: `${projectDir}/foo/foo.ts`, + content: "declare namespace foo { interface Foo { get2(): number; getFoo(): string; } }" + }; + const configFile: FileOrFolder = { + path: `${projectDir}/tsconfig.json`, + content: JSON.stringify({ compilerOptions: { module: "none", targer: "es5" }, exclude: ["node_modules"] }) + }; + const host = createServerHost([app, foo, configFile]); + const session = createSession(host, { canUseEvents: true, }); + const projectService = session.getProjectService(); + + session.executeCommandSeq({ + command: server.CommandNames.Open, + arguments: { file: app.path, } + }); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); + assert.isDefined(projectService.configuredProjects.get(configFile.path)); + verifyErrorsInApp(); + + host.renameFolder(`${projectDir}/foo`, `${projectDir}/foo2`); + host.runQueuedTimeoutCallbacks(); + host.runQueuedTimeoutCallbacks(); + verifyErrorsInApp(); + + function verifyErrorsInApp() { + host.clearOutput(); + const expectedSequenceId = session.getNextSeq(); + session.executeCommandSeq({ + command: server.CommandNames.Geterr, + arguments: { + delay: 0, + files: [app.path] + } + }); + host.checkTimeoutQueueLengthAndRun(1); + checkErrorMessage(host, "syntaxDiag", { file: app.path, diagnostics: [] }); + host.clearOutput(); + + host.runQueuedImmediateCallbacks(); + checkErrorMessage(host, "semanticDiag", { file: app.path, diagnostics: [] }); + checkCompleteEvent(host, 2, expectedSequenceId); + host.clearOutput(); + } + }); }); describe("autoDiscovery", () => { @@ -3028,12 +3205,12 @@ namespace ts.projectSystem { path: "/src/tsconfig.json", content: JSON.stringify( { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": true, - "sourceMap": false, - "lib": [ + compilerOptions: { + module: "commonjs", + target: "es5", + noImplicitAny: true, + sourceMap: false, + lib: [ "es5" ] } @@ -3043,12 +3220,12 @@ namespace ts.projectSystem { path: config1.path, content: JSON.stringify( { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": true, - "sourceMap": false, - "lib": [ + compilerOptions: { + module: "commonjs", + target: "es5", + noImplicitAny: true, + sourceMap: false, + lib: [ "es5", "es2015.promise" ] @@ -3484,6 +3661,73 @@ namespace ts.projectSystem { diags = session.executeCommand(getErrRequest).response as server.protocol.Diagnostic[]; verifyNoDiagnostics(diags); }); + + it("npm install @types works", () => { + const folderPath = "/a/b/projects/temp"; + const file1: FileOrFolder = { + path: `${folderPath}/a.ts`, + content: 'import f = require("pad")' + }; + const files = [file1, libFile]; + const host = createServerHost(files); + const session = createSession(host, { canUseEvents: true }); + const service = session.getProjectService(); + session.executeCommandSeq({ + command: server.CommandNames.Open, + arguments: { + file: file1.path, + fileContent: file1.content, + scriptKindName: "TS", + projectRootPath: folderPath + } + }); + checkNumberOfProjects(service, { inferredProjects: 1 }); + host.clearOutput(); + const expectedSequenceId = session.getNextSeq(); + session.executeCommandSeq({ + command: server.CommandNames.Geterr, + arguments: { + delay: 0, + files: [file1.path] + } + }); + + host.checkTimeoutQueueLengthAndRun(1); + checkErrorMessage(host, "syntaxDiag", { file: file1.path, diagnostics: [] }); + host.clearOutput(); + + host.runQueuedImmediateCallbacks(); + const moduleNotFound = Diagnostics.Cannot_find_module_0; + const startOffset = file1.content.indexOf('"') + 1; + checkErrorMessage(host, "semanticDiag", { + file: file1.path, diagnostics: [{ + start: { line: 1, offset: startOffset }, + end: { line: 1, offset: startOffset + '"pad"'.length }, + text: formatStringFromArgs(moduleNotFound.message, ["pad"]), + code: moduleNotFound.code, + category: DiagnosticCategory[moduleNotFound.category].toLowerCase() + }] + }); + checkCompleteEvent(host, 2, expectedSequenceId); + host.clearOutput(); + + const padIndex: FileOrFolder = { + path: `${folderPath}/node_modules/@types/pad/index.d.ts`, + content: "export = pad;declare function pad(length: number, text: string, char ?: string): string;" + }; + files.push(padIndex); + host.reloadFS(files, { ignoreWatchInvokedWithTriggerAsFileCreate: true }); + host.runQueuedTimeoutCallbacks(); + checkProjectUpdatedInBackgroundEvent(host, [file1.path]); + host.clearOutput(); + + host.runQueuedTimeoutCallbacks(); + checkErrorMessage(host, "syntaxDiag", { file: file1.path, diagnostics: [] }); + host.clearOutput(); + + host.runQueuedImmediateCallbacks(); + checkErrorMessage(host, "semanticDiag", { file: file1.path, diagnostics: [] }); + }); }); describe("Configure file diagnostics events", () => { @@ -4564,7 +4808,7 @@ namespace ts.projectSystem { const host = createServerHost([f1, config]); const session = createSession(host, { canUseEvents: true, - eventHandler: () => { }, + eventHandler: noop, cancellationToken }); { @@ -4701,7 +4945,7 @@ namespace ts.projectSystem { const host = createServerHost([f1, config]); const session = createSession(host, { canUseEvents: true, - eventHandler: () => { }, + eventHandler: noop, cancellationToken, throttleWaitMilliseconds: 0 }); @@ -5330,31 +5574,31 @@ namespace ts.projectSystem { const tsconfigFile: FileOrFolder = { path: `${frontendDir}/tsconfig.json`, content: JSON.stringify({ - "compilerOptions": { - "strict": true, - "strictNullChecks": true, - "target": "es2016", - "module": "commonjs", - "moduleResolution": "node", - "sourceMap": true, - "noEmitOnError": true, - "experimentalDecorators": true, - "emitDecoratorMetadata": true, + compilerOptions: { + strict: true, + strictNullChecks: true, + target: "es2016", + module: "commonjs", + moduleResolution: "node", + sourceMap: true, + noEmitOnError: true, + experimentalDecorators: true, + emitDecoratorMetadata: true, types, - "noUnusedLocals": true, - "outDir": "./compiled", + noUnusedLocals: true, + outDir: "./compiled", typeRoots, - "baseUrl": ".", - "paths": { + baseUrl: ".", + paths: { "*": [ "types/*" ] } }, - "include": [ + include: [ "src/**/*" ], - "exclude": [ + exclude: [ "node_modules", "compiled" ] @@ -5479,66 +5723,66 @@ namespace ts.projectSystem { // Simulate npm install const filesAndFoldersToAdd: FileOrFolder[] = [ - { "path": "/a/b/node_modules" }, - { "path": "/a/b/node_modules/.staging/@types" }, - { "path": "/a/b/node_modules/.staging/lodash-b0733faa" }, - { "path": "/a/b/node_modules/.staging/@types/lodash-e56c4fe7" }, - { "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 \",\n \"contributors\": [\n {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n {\n \"name\": \"Paul Taylor\",\n \"email\": \"paul.e.taylor@me.com\"\n },\n {\n \"name\": \"Jeff Cross\",\n \"email\": \"crossj@google.com\"\n },\n {\n \"name\": \"Matthew Podwysocki\",\n \"email\": \"matthewp@microsoft.com\"\n },\n {\n \"name\": \"OJ Kwon\",\n \"email\": \"kwon.ohjoong@gmail.com\"\n },\n {\n \"name\": \"Andre Staltz\",\n \"email\": \"andre@staltz.com\"\n }\n ],\n \"license\": \"Apache-2.0\",\n \"bugs\": {\n \"url\": \"https://github.com/ReactiveX/RxJS/issues\"\n },\n \"homepage\": \"https://github.com/ReactiveX/RxJS\",\n \"devDependencies\": {\n \"babel-polyfill\": \"^6.23.0\",\n \"benchmark\": \"^2.1.0\",\n \"benchpress\": \"2.0.0-beta.1\",\n \"chai\": \"^3.5.0\",\n \"color\": \"^0.11.1\",\n \"colors\": \"1.1.2\",\n \"commitizen\": \"^2.8.6\",\n \"coveralls\": \"^2.11.13\",\n \"cz-conventional-changelog\": \"^1.2.0\",\n \"danger\": \"^1.1.0\",\n \"doctoc\": \"^1.0.0\",\n \"escape-string-regexp\": \"^1.0.5 \",\n \"esdoc\": \"^0.4.7\",\n \"eslint\": \"^3.8.0\",\n \"fs-extra\": \"^2.1.2\",\n \"get-folder-size\": \"^1.0.0\",\n \"glob\": \"^7.0.3\",\n \"gm\": \"^1.22.0\",\n \"google-closure-compiler-js\": \"^20170218.0.0\",\n \"gzip-size\": \"^3.0.0\",\n \"http-server\": \"^0.9.0\",\n \"husky\": \"^0.13.3\",\n \"lint-staged\": \"3.2.5\",\n \"lodash\": \"^4.15.0\",\n \"madge\": \"^1.4.3\",\n \"markdown-doctest\": \"^0.9.1\",\n \"minimist\": \"^1.2.0\",\n \"mkdirp\": \"^0.5.1\",\n \"mocha\": \"^3.0.2\",\n \"mocha-in-sauce\": \"0.0.1\",\n \"npm-run-all\": \"^4.0.2\",\n \"npm-scripts-info\": \"^0.3.4\",\n \"nyc\": \"^10.2.0\",\n \"opn-cli\": \"^3.1.0\",\n \"platform\": \"^1.3.1\",\n \"promise\": \"^7.1.1\",\n \"protractor\": \"^3.1.1\",\n \"rollup\": \"0.36.3\",\n \"rollup-plugin-inject\": \"^2.0.0\",\n \"rollup-plugin-node-resolve\": \"^2.0.0\",\n \"rx\": \"latest\",\n \"rxjs\": \"latest\",\n \"shx\": \"^0.2.2\",\n \"sinon\": \"^2.1.0\",\n \"sinon-chai\": \"^2.9.0\",\n \"source-map-support\": \"^0.4.0\",\n \"tslib\": \"^1.5.0\",\n \"tslint\": \"^4.4.2\",\n \"typescript\": \"~2.0.6\",\n \"typings\": \"^2.0.0\",\n \"validate-commit-msg\": \"^2.14.0\",\n \"watch\": \"^1.0.1\",\n \"webpack\": \"^1.13.1\",\n \"xmlhttprequest\": \"1.8.0\"\n },\n \"engines\": {\n \"npm\": \">=2.0.0\"\n },\n \"typings\": \"Rx.d.ts\",\n \"dependencies\": {\n \"symbol-observable\": \"^1.0.1\"\n }\n}" }, - { "path": "/a/b/node_modules/.staging/typescript-8493ea5d/package.json", "content": "{\n \"name\": \"typescript\",\n \"author\": \"Microsoft Corp.\",\n \"homepage\": \"http://typescriptlang.org/\",\n \"version\": \"2.4.2\",\n \"license\": \"Apache-2.0\",\n \"description\": \"TypeScript is a language for application scale JavaScript development\",\n \"keywords\": [\n \"TypeScript\",\n \"Microsoft\",\n \"compiler\",\n \"language\",\n \"javascript\"\n ],\n \"bugs\": {\n \"url\": \"https://github.com/Microsoft/TypeScript/issues\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/Microsoft/TypeScript.git\"\n },\n \"main\": \"./lib/typescript.js\",\n \"typings\": \"./lib/typescript.d.ts\",\n \"bin\": {\n \"tsc\": \"./bin/tsc\",\n \"tsserver\": \"./bin/tsserver\"\n },\n \"engines\": {\n \"node\": \">=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 \"tslint\": \"latest\",\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/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" }, + { path: "/a/b/node_modules/.staging/@types" }, + { path: "/a/b/node_modules/.staging/lodash-b0733faa" }, + { path: "/a/b/node_modules/.staging/@types/lodash-e56c4fe7" }, + { 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 \",\n \"contributors\": [\n {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n {\n \"name\": \"Paul Taylor\",\n \"email\": \"paul.e.taylor@me.com\"\n },\n {\n \"name\": \"Jeff Cross\",\n \"email\": \"crossj@google.com\"\n },\n {\n \"name\": \"Matthew Podwysocki\",\n \"email\": \"matthewp@microsoft.com\"\n },\n {\n \"name\": \"OJ Kwon\",\n \"email\": \"kwon.ohjoong@gmail.com\"\n },\n {\n \"name\": \"Andre Staltz\",\n \"email\": \"andre@staltz.com\"\n }\n ],\n \"license\": \"Apache-2.0\",\n \"bugs\": {\n \"url\": \"https://github.com/ReactiveX/RxJS/issues\"\n },\n \"homepage\": \"https://github.com/ReactiveX/RxJS\",\n \"devDependencies\": {\n \"babel-polyfill\": \"^6.23.0\",\n \"benchmark\": \"^2.1.0\",\n \"benchpress\": \"2.0.0-beta.1\",\n \"chai\": \"^3.5.0\",\n \"color\": \"^0.11.1\",\n \"colors\": \"1.1.2\",\n \"commitizen\": \"^2.8.6\",\n \"coveralls\": \"^2.11.13\",\n \"cz-conventional-changelog\": \"^1.2.0\",\n \"danger\": \"^1.1.0\",\n \"doctoc\": \"^1.0.0\",\n \"escape-string-regexp\": \"^1.0.5 \",\n \"esdoc\": \"^0.4.7\",\n \"eslint\": \"^3.8.0\",\n \"fs-extra\": \"^2.1.2\",\n \"get-folder-size\": \"^1.0.0\",\n \"glob\": \"^7.0.3\",\n \"gm\": \"^1.22.0\",\n \"google-closure-compiler-js\": \"^20170218.0.0\",\n \"gzip-size\": \"^3.0.0\",\n \"http-server\": \"^0.9.0\",\n \"husky\": \"^0.13.3\",\n \"lint-staged\": \"3.2.5\",\n \"lodash\": \"^4.15.0\",\n \"madge\": \"^1.4.3\",\n \"markdown-doctest\": \"^0.9.1\",\n \"minimist\": \"^1.2.0\",\n \"mkdirp\": \"^0.5.1\",\n \"mocha\": \"^3.0.2\",\n \"mocha-in-sauce\": \"0.0.1\",\n \"npm-run-all\": \"^4.0.2\",\n \"npm-scripts-info\": \"^0.3.4\",\n \"nyc\": \"^10.2.0\",\n \"opn-cli\": \"^3.1.0\",\n \"platform\": \"^1.3.1\",\n \"promise\": \"^7.1.1\",\n \"protractor\": \"^3.1.1\",\n \"rollup\": \"0.36.3\",\n \"rollup-plugin-inject\": \"^2.0.0\",\n \"rollup-plugin-node-resolve\": \"^2.0.0\",\n \"rx\": \"latest\",\n \"rxjs\": \"latest\",\n \"shx\": \"^0.2.2\",\n \"sinon\": \"^2.1.0\",\n \"sinon-chai\": \"^2.9.0\",\n \"source-map-support\": \"^0.4.0\",\n \"tslib\": \"^1.5.0\",\n \"tslint\": \"^4.4.2\",\n \"typescript\": \"~2.0.6\",\n \"typings\": \"^2.0.0\",\n \"validate-commit-msg\": \"^2.14.0\",\n \"watch\": \"^1.0.1\",\n \"webpack\": \"^1.13.1\",\n \"xmlhttprequest\": \"1.8.0\"\n },\n \"engines\": {\n \"npm\": \">=2.0.0\"\n },\n \"typings\": \"Rx.d.ts\",\n \"dependencies\": {\n \"symbol-observable\": \"^1.0.1\"\n }\n}" }, + { path: "/a/b/node_modules/.staging/typescript-8493ea5d/package.json", content: "{\n \"name\": \"typescript\",\n \"author\": \"Microsoft Corp.\",\n \"homepage\": \"http://typescriptlang.org/\",\n \"version\": \"2.4.2\",\n \"license\": \"Apache-2.0\",\n \"description\": \"TypeScript is a language for application scale JavaScript development\",\n \"keywords\": [\n \"TypeScript\",\n \"Microsoft\",\n \"compiler\",\n \"language\",\n \"javascript\"\n ],\n \"bugs\": {\n \"url\": \"https://github.com/Microsoft/TypeScript/issues\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/Microsoft/TypeScript.git\"\n },\n \"main\": \"./lib/typescript.js\",\n \"typings\": \"./lib/typescript.d.ts\",\n \"bin\": {\n \"tsc\": \"./bin/tsc\",\n \"tsserver\": \"./bin/tsserver\"\n },\n \"engines\": {\n \"node\": \">=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 \"tslint\": \"latest\",\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/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;" }, ].map(getRootedFileOrFolder); verifyAfterPartialOrCompleteNpmInstall(2); filesAndFoldersToAdd.push(...[ - { "path": "/a/b/node_modules/.staging/typescript-8493ea5d/lib" }, - { "path": "/a/b/node_modules/.staging/rxjs-22375c61/add/operator" }, - { "path": "/a/b/node_modules/.staging/@types/lodash-e56c4fe7/package.json", "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/typescript-8493ea5d/package.json.3017591594" } + { path: "/a/b/node_modules/.staging/typescript-8493ea5d/lib" }, + { path: "/a/b/node_modules/.staging/rxjs-22375c61/add/operator" }, + { path: "/a/b/node_modules/.staging/@types/lodash-e56c4fe7/package.json", 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/typescript-8493ea5d/package.json.3017591594" } ].map(getRootedFileOrFolder)); - // Since we didnt add any supported extension file, there wont be any timeout scheduled - verifyAfterPartialOrCompleteNpmInstall(0); + // Since we added/removed folder, scheduled project update + verifyAfterPartialOrCompleteNpmInstall(2); // Remove file "/a/b/node_modules/.staging/typescript-8493ea5d/package.json.3017591594" filesAndFoldersToAdd.length--; verifyAfterPartialOrCompleteNpmInstall(0); filesAndFoldersToAdd.push(...[ - { "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/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}" } ].map(getRootedFileOrFolder)); verifyAfterPartialOrCompleteNpmInstall(2); filesAndFoldersToAdd.push(...[ - { "path": "/a/b/node_modules/.staging/rxjs-22375c61/src/scheduler" }, - { "path": "/a/b/node_modules/.staging/rxjs-22375c61/src/util" }, - { "path": "/a/b/node_modules/.staging/rxjs-22375c61/symbol" }, - { "path": "/a/b/node_modules/.staging/rxjs-22375c61/testing" }, - { "path": "/a/b/node_modules/.staging/rxjs-22375c61/package.json.2252192041", "content": "{\n \"_args\": [\n [\n {\n \"raw\": \"rxjs@^5.4.2\",\n \"scope\": null,\n \"escapedName\": \"rxjs\",\n \"name\": \"rxjs\",\n \"rawSpec\": \"^5.4.2\",\n \"spec\": \">=5.4.2 <6.0.0\",\n \"type\": \"range\"\n },\n \"C:\\\\Users\\\\shkamat\\\\Desktop\\\\app\"\n ]\n ],\n \"_from\": \"rxjs@>=5.4.2 <6.0.0\",\n \"_id\": \"rxjs@5.4.3\",\n \"_inCache\": true,\n \"_location\": \"/rxjs\",\n \"_nodeVersion\": \"7.7.2\",\n \"_npmOperationalInternal\": {\n \"host\": \"s3://npm-registry-packages\",\n \"tmp\": \"tmp/rxjs-5.4.3.tgz_1502407898166_0.6800217325799167\"\n },\n \"_npmUser\": {\n \"name\": \"blesh\",\n \"email\": \"ben@benlesh.com\"\n },\n \"_npmVersion\": \"5.3.0\",\n \"_phantomChildren\": {},\n \"_requested\": {\n \"raw\": \"rxjs@^5.4.2\",\n \"scope\": null,\n \"escapedName\": \"rxjs\",\n \"name\": \"rxjs\",\n \"rawSpec\": \"^5.4.2\",\n \"spec\": \">=5.4.2 <6.0.0\",\n \"type\": \"range\"\n },\n \"_requiredBy\": [\n \"/\"\n ],\n \"_resolved\": \"https://registry.npmjs.org/rxjs/-/rxjs-5.4.3.tgz\",\n \"_shasum\": \"0758cddee6033d68e0fd53676f0f3596ce3d483f\",\n \"_shrinkwrap\": null,\n \"_spec\": \"rxjs@^5.4.2\",\n \"_where\": \"C:\\\\Users\\\\shkamat\\\\Desktop\\\\app\",\n \"author\": {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/ReactiveX/RxJS/issues\"\n },\n \"config\": {\n \"commitizen\": {\n \"path\": \"cz-conventional-changelog\"\n }\n },\n \"contributors\": [\n {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n {\n \"name\": \"Paul Taylor\",\n \"email\": \"paul.e.taylor@me.com\"\n },\n {\n \"name\": \"Jeff Cross\",\n \"email\": \"crossj@google.com\"\n },\n {\n \"name\": \"Matthew Podwysocki\",\n \"email\": \"matthewp@microsoft.com\"\n },\n {\n \"name\": \"OJ Kwon\",\n \"email\": \"kwon.ohjoong@gmail.com\"\n },\n {\n \"name\": \"Andre Staltz\",\n \"email\": \"andre@staltz.com\"\n }\n ],\n \"dependencies\": {\n \"symbol-observable\": \"^1.0.1\"\n },\n \"description\": \"Reactive Extensions for modern JavaScript\",\n \"devDependencies\": {\n \"babel-polyfill\": \"^6.23.0\",\n \"benchmark\": \"^2.1.0\",\n \"benchpress\": \"2.0.0-beta.1\",\n \"chai\": \"^3.5.0\",\n \"color\": \"^0.11.1\",\n \"colors\": \"1.1.2\",\n \"commitizen\": \"^2.8.6\",\n \"coveralls\": \"^2.11.13\",\n \"cz-conventional-changelog\": \"^1.2.0\",\n \"danger\": \"^1.1.0\",\n \"doctoc\": \"^1.0.0\",\n \"escape-string-regexp\": \"^1.0.5 \",\n \"esdoc\": \"^0.4.7\",\n \"eslint\": \"^3.8.0\",\n \"fs-extra\": \"^2.1.2\",\n \"get-folder-size\": \"^1.0.0\",\n \"glob\": \"^7.0.3\",\n \"gm\": \"^1.22.0\",\n \"google-closure-compiler-js\": \"^20170218.0.0\",\n \"gzip-size\": \"^3.0.0\",\n \"http-server\": \"^0.9.0\",\n \"husky\": \"^0.13.3\",\n \"lint-staged\": \"3.2.5\",\n \"lodash\": \"^4.15.0\",\n \"madge\": \"^1.4.3\",\n \"markdown-doctest\": \"^0.9.1\",\n \"minimist\": \"^1.2.0\",\n \"mkdirp\": \"^0.5.1\",\n \"mocha\": \"^3.0.2\",\n \"mocha-in-sauce\": \"0.0.1\",\n \"npm-run-all\": \"^4.0.2\",\n \"npm-scripts-info\": \"^0.3.4\",\n \"nyc\": \"^10.2.0\",\n \"opn-cli\": \"^3.1.0\",\n \"platform\": \"^1.3.1\",\n \"promise\": \"^7.1.1\",\n \"protractor\": \"^3.1.1\",\n \"rollup\": \"0.36.3\",\n \"rollup-plugin-inject\": \"^2.0.0\",\n \"rollup-plugin-node-resolve\": \"^2.0.0\",\n \"rx\": \"latest\",\n \"rxjs\": \"latest\",\n \"shx\": \"^0.2.2\",\n \"sinon\": \"^2.1.0\",\n \"sinon-chai\": \"^2.9.0\",\n \"source-map-support\": \"^0.4.0\",\n \"tslib\": \"^1.5.0\",\n \"tslint\": \"^4.4.2\",\n \"typescript\": \"~2.0.6\",\n \"typings\": \"^2.0.0\",\n \"validate-commit-msg\": \"^2.14.0\",\n \"watch\": \"^1.0.1\",\n \"webpack\": \"^1.13.1\",\n \"xmlhttprequest\": \"1.8.0\"\n },\n \"directories\": {},\n \"dist\": {\n \"integrity\": \"sha512-fSNi+y+P9ss+EZuV0GcIIqPUK07DEaMRUtLJvdcvMyFjc9dizuDjere+A4V7JrLGnm9iCc+nagV/4QdMTkqC4A==\",\n \"shasum\": \"0758cddee6033d68e0fd53676f0f3596ce3d483f\",\n \"tarball\": \"https://registry.npmjs.org/rxjs/-/rxjs-5.4.3.tgz\"\n },\n \"engines\": {\n \"npm\": \">=2.0.0\"\n },\n \"homepage\": \"https://github.com/ReactiveX/RxJS\",\n \"keywords\": [\n \"Rx\",\n \"RxJS\",\n \"ReactiveX\",\n \"ReactiveExtensions\",\n \"Streams\",\n \"Observables\",\n \"Observable\",\n \"Stream\",\n \"ES6\",\n \"ES2015\"\n ],\n \"license\": \"Apache-2.0\",\n \"lint-staged\": {\n \"*.@(js)\": [\n \"eslint --fix\",\n \"git add\"\n ],\n \"*.@(ts)\": [\n \"tslint --fix\",\n \"git add\"\n ]\n },\n \"main\": \"Rx.js\",\n \"maintainers\": [\n {\n \"name\": \"blesh\",\n \"email\": \"ben@benlesh.com\"\n }\n ],\n \"name\": \"rxjs\",\n \"optionalDependencies\": {},\n \"readme\": \"ERROR: No README data found!\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+ssh://git@github.com/ReactiveX/RxJS.git\"\n },\n \"scripts-info\": {\n \"info\": \"List available script\",\n \"build_all\": \"Build all packages (ES6, CJS, UMD) and generate packages\",\n \"build_cjs\": \"Build CJS package with clean up existing build, copy source into dist\",\n \"build_es6\": \"Build ES6 package with clean up existing build, copy source into dist\",\n \"build_closure_core\": \"Minify Global core build using closure compiler\",\n \"build_global\": \"Build Global package, then minify build\",\n \"build_perf\": \"Build CJS & Global build, run macro performance test\",\n \"build_test\": \"Build CJS package & test spec, execute mocha test runner\",\n \"build_cover\": \"Run lint to current code, build CJS & test spec, execute test coverage\",\n \"build_docs\": \"Build ES6 & global package, create documentation using it\",\n \"build_spec\": \"Build test specs\",\n \"check_circular_dependencies\": \"Check codebase has circular dependencies\",\n \"clean_spec\": \"Clean up existing test spec build output\",\n \"clean_dist_cjs\": \"Clean up existing CJS package output\",\n \"clean_dist_es6\": \"Clean up existing ES6 package output\",\n \"clean_dist_global\": \"Clean up existing Global package output\",\n \"commit\": \"Run git commit wizard\",\n \"compile_dist_cjs\": \"Compile codebase into CJS module\",\n \"compile_module_es6\": \"Compile codebase into ES6\",\n \"cover\": \"Execute test coverage\",\n \"lint_perf\": \"Run lint against performance test suite\",\n \"lint_spec\": \"Run lint against test spec\",\n \"lint_src\": \"Run lint against source\",\n \"lint\": \"Run lint against everything\",\n \"perf\": \"Run macro performance benchmark\",\n \"perf_micro\": \"Run micro performance benchmark\",\n \"test_mocha\": \"Execute mocha test runner against existing test spec build\",\n \"test_browser\": \"Execute mocha test runner on browser against existing test spec build\",\n \"test\": \"Clean up existing test spec build, build test spec and execute mocha test runner\",\n \"tests2png\": \"Generate marble diagram image from test spec\",\n \"watch\": \"Watch codebase, trigger compile when source code changes\"\n },\n \"typings\": \"Rx.d.ts\",\n \"version\": \"5.4.3\"\n}\n" } + { path: "/a/b/node_modules/.staging/rxjs-22375c61/src/scheduler" }, + { path: "/a/b/node_modules/.staging/rxjs-22375c61/src/util" }, + { path: "/a/b/node_modules/.staging/rxjs-22375c61/symbol" }, + { path: "/a/b/node_modules/.staging/rxjs-22375c61/testing" }, + { path: "/a/b/node_modules/.staging/rxjs-22375c61/package.json.2252192041", content: "{\n \"_args\": [\n [\n {\n \"raw\": \"rxjs@^5.4.2\",\n \"scope\": null,\n \"escapedName\": \"rxjs\",\n \"name\": \"rxjs\",\n \"rawSpec\": \"^5.4.2\",\n \"spec\": \">=5.4.2 <6.0.0\",\n \"type\": \"range\"\n },\n \"C:\\\\Users\\\\shkamat\\\\Desktop\\\\app\"\n ]\n ],\n \"_from\": \"rxjs@>=5.4.2 <6.0.0\",\n \"_id\": \"rxjs@5.4.3\",\n \"_inCache\": true,\n \"_location\": \"/rxjs\",\n \"_nodeVersion\": \"7.7.2\",\n \"_npmOperationalInternal\": {\n \"host\": \"s3://npm-registry-packages\",\n \"tmp\": \"tmp/rxjs-5.4.3.tgz_1502407898166_0.6800217325799167\"\n },\n \"_npmUser\": {\n \"name\": \"blesh\",\n \"email\": \"ben@benlesh.com\"\n },\n \"_npmVersion\": \"5.3.0\",\n \"_phantomChildren\": {},\n \"_requested\": {\n \"raw\": \"rxjs@^5.4.2\",\n \"scope\": null,\n \"escapedName\": \"rxjs\",\n \"name\": \"rxjs\",\n \"rawSpec\": \"^5.4.2\",\n \"spec\": \">=5.4.2 <6.0.0\",\n \"type\": \"range\"\n },\n \"_requiredBy\": [\n \"/\"\n ],\n \"_resolved\": \"https://registry.npmjs.org/rxjs/-/rxjs-5.4.3.tgz\",\n \"_shasum\": \"0758cddee6033d68e0fd53676f0f3596ce3d483f\",\n \"_shrinkwrap\": null,\n \"_spec\": \"rxjs@^5.4.2\",\n \"_where\": \"C:\\\\Users\\\\shkamat\\\\Desktop\\\\app\",\n \"author\": {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/ReactiveX/RxJS/issues\"\n },\n \"config\": {\n \"commitizen\": {\n \"path\": \"cz-conventional-changelog\"\n }\n },\n \"contributors\": [\n {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n {\n \"name\": \"Paul Taylor\",\n \"email\": \"paul.e.taylor@me.com\"\n },\n {\n \"name\": \"Jeff Cross\",\n \"email\": \"crossj@google.com\"\n },\n {\n \"name\": \"Matthew Podwysocki\",\n \"email\": \"matthewp@microsoft.com\"\n },\n {\n \"name\": \"OJ Kwon\",\n \"email\": \"kwon.ohjoong@gmail.com\"\n },\n {\n \"name\": \"Andre Staltz\",\n \"email\": \"andre@staltz.com\"\n }\n ],\n \"dependencies\": {\n \"symbol-observable\": \"^1.0.1\"\n },\n \"description\": \"Reactive Extensions for modern JavaScript\",\n \"devDependencies\": {\n \"babel-polyfill\": \"^6.23.0\",\n \"benchmark\": \"^2.1.0\",\n \"benchpress\": \"2.0.0-beta.1\",\n \"chai\": \"^3.5.0\",\n \"color\": \"^0.11.1\",\n \"colors\": \"1.1.2\",\n \"commitizen\": \"^2.8.6\",\n \"coveralls\": \"^2.11.13\",\n \"cz-conventional-changelog\": \"^1.2.0\",\n \"danger\": \"^1.1.0\",\n \"doctoc\": \"^1.0.0\",\n \"escape-string-regexp\": \"^1.0.5 \",\n \"esdoc\": \"^0.4.7\",\n \"eslint\": \"^3.8.0\",\n \"fs-extra\": \"^2.1.2\",\n \"get-folder-size\": \"^1.0.0\",\n \"glob\": \"^7.0.3\",\n \"gm\": \"^1.22.0\",\n \"google-closure-compiler-js\": \"^20170218.0.0\",\n \"gzip-size\": \"^3.0.0\",\n \"http-server\": \"^0.9.0\",\n \"husky\": \"^0.13.3\",\n \"lint-staged\": \"3.2.5\",\n \"lodash\": \"^4.15.0\",\n \"madge\": \"^1.4.3\",\n \"markdown-doctest\": \"^0.9.1\",\n \"minimist\": \"^1.2.0\",\n \"mkdirp\": \"^0.5.1\",\n \"mocha\": \"^3.0.2\",\n \"mocha-in-sauce\": \"0.0.1\",\n \"npm-run-all\": \"^4.0.2\",\n \"npm-scripts-info\": \"^0.3.4\",\n \"nyc\": \"^10.2.0\",\n \"opn-cli\": \"^3.1.0\",\n \"platform\": \"^1.3.1\",\n \"promise\": \"^7.1.1\",\n \"protractor\": \"^3.1.1\",\n \"rollup\": \"0.36.3\",\n \"rollup-plugin-inject\": \"^2.0.0\",\n \"rollup-plugin-node-resolve\": \"^2.0.0\",\n \"rx\": \"latest\",\n \"rxjs\": \"latest\",\n \"shx\": \"^0.2.2\",\n \"sinon\": \"^2.1.0\",\n \"sinon-chai\": \"^2.9.0\",\n \"source-map-support\": \"^0.4.0\",\n \"tslib\": \"^1.5.0\",\n \"tslint\": \"^4.4.2\",\n \"typescript\": \"~2.0.6\",\n \"typings\": \"^2.0.0\",\n \"validate-commit-msg\": \"^2.14.0\",\n \"watch\": \"^1.0.1\",\n \"webpack\": \"^1.13.1\",\n \"xmlhttprequest\": \"1.8.0\"\n },\n \"directories\": {},\n \"dist\": {\n \"integrity\": \"sha512-fSNi+y+P9ss+EZuV0GcIIqPUK07DEaMRUtLJvdcvMyFjc9dizuDjere+A4V7JrLGnm9iCc+nagV/4QdMTkqC4A==\",\n \"shasum\": \"0758cddee6033d68e0fd53676f0f3596ce3d483f\",\n \"tarball\": \"https://registry.npmjs.org/rxjs/-/rxjs-5.4.3.tgz\"\n },\n \"engines\": {\n \"npm\": \">=2.0.0\"\n },\n \"homepage\": \"https://github.com/ReactiveX/RxJS\",\n \"keywords\": [\n \"Rx\",\n \"RxJS\",\n \"ReactiveX\",\n \"ReactiveExtensions\",\n \"Streams\",\n \"Observables\",\n \"Observable\",\n \"Stream\",\n \"ES6\",\n \"ES2015\"\n ],\n \"license\": \"Apache-2.0\",\n \"lint-staged\": {\n \"*.@(js)\": [\n \"eslint --fix\",\n \"git add\"\n ],\n \"*.@(ts)\": [\n \"tslint --fix\",\n \"git add\"\n ]\n },\n \"main\": \"Rx.js\",\n \"maintainers\": [\n {\n \"name\": \"blesh\",\n \"email\": \"ben@benlesh.com\"\n }\n ],\n \"name\": \"rxjs\",\n \"optionalDependencies\": {},\n \"readme\": \"ERROR: No README data found!\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+ssh://git@github.com/ReactiveX/RxJS.git\"\n },\n \"scripts-info\": {\n \"info\": \"List available script\",\n \"build_all\": \"Build all packages (ES6, CJS, UMD) and generate packages\",\n \"build_cjs\": \"Build CJS package with clean up existing build, copy source into dist\",\n \"build_es6\": \"Build ES6 package with clean up existing build, copy source into dist\",\n \"build_closure_core\": \"Minify Global core build using closure compiler\",\n \"build_global\": \"Build Global package, then minify build\",\n \"build_perf\": \"Build CJS & Global build, run macro performance test\",\n \"build_test\": \"Build CJS package & test spec, execute mocha test runner\",\n \"build_cover\": \"Run lint to current code, build CJS & test spec, execute test coverage\",\n \"build_docs\": \"Build ES6 & global package, create documentation using it\",\n \"build_spec\": \"Build test specs\",\n \"check_circular_dependencies\": \"Check codebase has circular dependencies\",\n \"clean_spec\": \"Clean up existing test spec build output\",\n \"clean_dist_cjs\": \"Clean up existing CJS package output\",\n \"clean_dist_es6\": \"Clean up existing ES6 package output\",\n \"clean_dist_global\": \"Clean up existing Global package output\",\n \"commit\": \"Run git commit wizard\",\n \"compile_dist_cjs\": \"Compile codebase into CJS module\",\n \"compile_module_es6\": \"Compile codebase into ES6\",\n \"cover\": \"Execute test coverage\",\n \"lint_perf\": \"Run lint against performance test suite\",\n \"lint_spec\": \"Run lint against test spec\",\n \"lint_src\": \"Run lint against source\",\n \"lint\": \"Run lint against everything\",\n \"perf\": \"Run macro performance benchmark\",\n \"perf_micro\": \"Run micro performance benchmark\",\n \"test_mocha\": \"Execute mocha test runner against existing test spec build\",\n \"test_browser\": \"Execute mocha test runner on browser against existing test spec build\",\n \"test\": \"Clean up existing test spec build, build test spec and execute mocha test runner\",\n \"tests2png\": \"Generate marble diagram image from test spec\",\n \"watch\": \"Watch codebase, trigger compile when source code changes\"\n },\n \"typings\": \"Rx.d.ts\",\n \"version\": \"5.4.3\"\n}\n" } ].map(getRootedFileOrFolder)); - verifyAfterPartialOrCompleteNpmInstall(0); + verifyAfterPartialOrCompleteNpmInstall(2); // remove /a/b/node_modules/.staging/rxjs-22375c61/package.json.2252192041 filesAndFoldersToAdd.length--; // and add few more folders/files filesAndFoldersToAdd.push(...[ - { "path": "/a/b/node_modules/symbol-observable" }, - { "path": "/a/b/node_modules/@types" }, - { "path": "/a/b/node_modules/@types/lodash" }, - { "path": "/a/b/node_modules/lodash" }, - { "path": "/a/b/node_modules/rxjs" }, - { "path": "/a/b/node_modules/typescript" }, - { "path": "/a/b/node_modules/.bin" } + { path: "/a/b/node_modules/symbol-observable" }, + { path: "/a/b/node_modules/@types" }, + { path: "/a/b/node_modules/@types/lodash" }, + { path: "/a/b/node_modules/lodash" }, + { path: "/a/b/node_modules/rxjs" }, + { path: "/a/b/node_modules/typescript" }, + { path: "/a/b/node_modules/.bin" } ].map(getRootedFileOrFolder)); // From the type root update verifyAfterPartialOrCompleteNpmInstall(2); diff --git a/src/harness/unittests/typingsInstaller.ts b/src/harness/unittests/typingsInstaller.ts index 65d904940b3..e321fb1c99d 100644 --- a/src/harness/unittests/typingsInstaller.ts +++ b/src/harness/unittests/typingsInstaller.ts @@ -776,8 +776,8 @@ namespace ts.projectSystem { const bowerJson = { path: "/bower.json", content: JSON.stringify({ - "dependencies": { - "jquery": "^3.1.0" + dependencies: { + jquery: "^3.1.0" } }) }; @@ -1012,7 +1012,7 @@ namespace ts.projectSystem { const packageJson = { path: "/a/b/package.json", content: JSON.stringify({ - "dependencies": { + dependencies: { "; say ‘Hello from TypeScript!’ #": "0.0.x" } }) @@ -1095,7 +1095,7 @@ namespace ts.projectSystem { content: "" }; const host = createServerHost([f, node]); - const cache = createMapFromTemplate({ "node": node.path }); + const cache = createMapFromTemplate({ node: node.path }); const logger = trackingLogger(); const result = JsTyping.discoverTypings(host, logger.log, [f.path], getDirectoryPath(f.path), emptySafeList, cache, { enable: true }, ["fs", "bar"]); assert.deepEqual(logger.finish(), [ @@ -1145,7 +1145,7 @@ namespace ts.projectSystem { }; const packageFile = { path: "/a/package.json", - content: JSON.stringify({ dependencies: { "commander": "1.0.0" } }) + content: JSON.stringify({ dependencies: { commander: "1.0.0" } }) }; const cachePath = "/a/cache/"; const commander = { @@ -1195,7 +1195,7 @@ namespace ts.projectSystem { }; const packageFile = { path: "/a/package.json", - content: JSON.stringify({ dependencies: { "commander": "1.0.0" } }) + content: JSON.stringify({ dependencies: { commander: "1.0.0" } }) }; const cachePath = "/a/cache/"; const commander = { @@ -1247,7 +1247,7 @@ namespace ts.projectSystem { }; const packageFile = { path: "/a/package.json", - content: JSON.stringify({ dependencies: { "commander": "1.0.0" } }) + content: JSON.stringify({ dependencies: { commander: "1.0.0" } }) }; const cachePath = "/a/cache/"; const host = createServerHost([f1, packageFile]); diff --git a/src/harness/virtualFileSystemWithWatch.ts b/src/harness/virtualFileSystemWithWatch.ts index d6b1fc1a771..25581093f3d 100644 --- a/src/harness/virtualFileSystemWithWatch.ts +++ b/src/harness/virtualFileSystemWithWatch.ts @@ -182,6 +182,10 @@ interface Array {}` private map: TimeOutCallback[] = []; private nextId = 1; + getNextId() { + return this.nextId; + } + register(cb: (...args: any[]) => void, args: any[]) { const timeoutId = this.nextId; this.nextId++; @@ -203,7 +207,13 @@ interface Array {}` return n; } - invoke() { + invoke(invokeKey?: number) { + if (invokeKey) { + this.map[invokeKey](); + delete this.map[invokeKey]; + return; + } + // Note: invoking a callback may result in new callbacks been queued, // so do not clear the entire callback list regardless. Only remove the // ones we have invoked. @@ -226,6 +236,11 @@ interface Array {}` directoryName: string; } + export interface ReloadWatchInvokeOptions { + invokeDirectoryWatcherInsteadOfFileChanged: boolean; + ignoreWatchInvokedWithTriggerAsFileCreate: boolean; + } + export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost { args: string[] = []; @@ -270,7 +285,7 @@ interface Array {}` return s; } - reloadFS(fileOrFolderList: ReadonlyArray, invokeDirectoryWatcherInsteadOfFileChanged?: boolean) { + reloadFS(fileOrFolderList: ReadonlyArray, options?: Partial) { const mapNewLeaves = createMap(); const isNewFs = this.fs.size === 0; fileOrFolderList = fileOrFolderList.concat(this.withSafeList ? safeList : []); @@ -291,7 +306,7 @@ interface Array {}` // Update file if (currentEntry.content !== fileOrDirectory.content) { currentEntry.content = fileOrDirectory.content; - if (invokeDirectoryWatcherInsteadOfFileChanged) { + if (options && options.invokeDirectoryWatcherInsteadOfFileChanged) { this.invokeDirectoryWatcher(getDirectoryPath(currentEntry.fullPath), currentEntry.fullPath); } else { @@ -314,7 +329,7 @@ interface Array {}` } } else { - this.ensureFileOrFolder(fileOrDirectory); + this.ensureFileOrFolder(fileOrDirectory, options && options.ignoreWatchInvokedWithTriggerAsFileCreate); } } @@ -331,12 +346,45 @@ interface Array {}` } } - ensureFileOrFolder(fileOrDirectory: FileOrFolder) { + renameFolder(folderName: string, newFolderName: string) { + const fullPath = getNormalizedAbsolutePath(folderName, this.currentDirectory); + const path = this.toPath(fullPath); + const folder = this.fs.get(path) as Folder; + Debug.assert(!!folder); + + // Only remove the folder + this.removeFileOrFolder(folder, returnFalse, /*isRenaming*/ true); + + // Add updated folder with new folder name + const newFullPath = getNormalizedAbsolutePath(newFolderName, this.currentDirectory); + const newFolder = this.toFolder(newFullPath); + const newPath = newFolder.path; + const basePath = getDirectoryPath(path); + Debug.assert(basePath !== path); + Debug.assert(basePath === getDirectoryPath(newPath)); + const baseFolder = this.fs.get(basePath) as Folder; + this.addFileOrFolderInFolder(baseFolder, newFolder); + + // Invoke watches for files in the folder as deleted (from old path) + for (const entry of folder.entries) { + Debug.assert(isFile(entry)); + this.fs.delete(entry.path); + this.invokeFileWatcher(entry.fullPath, FileWatcherEventKind.Deleted); + + entry.fullPath = combinePaths(newFullPath, getBaseFileName(entry.fullPath)); + entry.path = this.toPath(entry.fullPath); + newFolder.entries.push(entry); + this.fs.set(entry.path, entry); + this.invokeFileWatcher(entry.fullPath, FileWatcherEventKind.Created); + } + } + + ensureFileOrFolder(fileOrDirectory: FileOrFolder, ignoreWatchInvokedWithTriggerAsFileCreate?: boolean) { if (isString(fileOrDirectory.content)) { const file = this.toFile(fileOrDirectory); Debug.assert(!this.fs.get(file.path)); const baseFolder = this.ensureFolder(getDirectoryPath(file.fullPath)); - this.addFileOrFolderInFolder(baseFolder, file); + this.addFileOrFolderInFolder(baseFolder, file, ignoreWatchInvokedWithTriggerAsFileCreate); } else { const fullPath = getNormalizedAbsolutePath(fileOrDirectory.path, this.currentDirectory); @@ -365,17 +413,20 @@ interface Array {}` return folder; } - private addFileOrFolderInFolder(folder: Folder, fileOrDirectory: File | Folder) { + private addFileOrFolderInFolder(folder: Folder, fileOrDirectory: File | Folder, ignoreWatch?: boolean) { folder.entries.push(fileOrDirectory); this.fs.set(fileOrDirectory.path, fileOrDirectory); + if (ignoreWatch) { + return; + } if (isFile(fileOrDirectory)) { this.invokeFileWatcher(fileOrDirectory.fullPath, FileWatcherEventKind.Created); } this.invokeDirectoryWatcher(folder.fullPath, fileOrDirectory.fullPath); } - private removeFileOrFolder(fileOrDirectory: File | Folder, isRemovableLeafFolder: (folder: Folder) => boolean) { + private removeFileOrFolder(fileOrDirectory: File | Folder, isRemovableLeafFolder: (folder: Folder) => boolean, isRenaming?: boolean) { const basePath = getDirectoryPath(fileOrDirectory.path); const baseFolder = this.fs.get(basePath) as Folder; if (basePath !== fileOrDirectory.path) { @@ -388,7 +439,7 @@ interface Array {}` this.invokeFileWatcher(fileOrDirectory.fullPath, FileWatcherEventKind.Deleted); } else { - Debug.assert(fileOrDirectory.entries.length === 0); + Debug.assert(fileOrDirectory.entries.length === 0 || isRenaming); const relativePath = this.getRelativePathToDirectory(fileOrDirectory.fullPath, fileOrDirectory.fullPath); // Invoke directory and recursive directory watcher for the folder // Here we arent invoking recursive directory watchers for the base folders @@ -545,6 +596,10 @@ interface Array {}` return this.timeoutCallbacks.register(callback, args); } + getNextTimeoutId() { + return this.timeoutCallbacks.getNextId(); + } + clearTimeout(timeoutId: any): void { this.timeoutCallbacks.unregister(timeoutId); } @@ -559,9 +614,9 @@ interface Array {}` assert.equal(callbacksCount, expected, `expected ${expected} timeout callbacks queued but found ${callbacksCount}.`); } - runQueuedTimeoutCallbacks() { + runQueuedTimeoutCallbacks(timeoutId?: number) { try { - this.timeoutCallbacks.invoke(); + this.timeoutCallbacks.invoke(timeoutId); } catch (e) { if (e.message === this.existMessage) { diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts index e4104715446..ec488bb069e 100644 --- a/src/lib/dom.generated.d.ts +++ b/src/lib/dom.generated.d.ts @@ -203,7 +203,7 @@ interface IDBIndexParameters { interface IDBObjectStoreParameters { autoIncrement?: boolean; - keyPath?: IDBKeyPath | null; + keyPath?: string | string[]; } interface IntersectionObserverEntryInit { @@ -773,7 +773,7 @@ interface RequestInit { body?: any; cache?: RequestCache; credentials?: RequestCredentials; - headers?: Headers | string[][]; + headers?: HeadersInit; integrity?: string; keepalive?: boolean; method?: string; @@ -785,7 +785,7 @@ interface RequestInit { } interface ResponseInit { - headers?: Headers | string[][]; + headers?: HeadersInit; status?: number; statusText?: string; } @@ -1255,10 +1255,10 @@ interface ApplicationCache extends EventTarget { readonly OBSOLETE: number; readonly UNCACHED: number; readonly UPDATEREADY: number; - addEventListener(type: K, listener: (this: ApplicationCache, ev: ApplicationCacheEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: ApplicationCache, ev: ApplicationCacheEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: ApplicationCache, ev: ApplicationCacheEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: ApplicationCache, ev: ApplicationCacheEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var ApplicationCache: { @@ -1314,10 +1314,10 @@ interface AudioBufferSourceNode extends AudioNode { readonly playbackRate: AudioParam; start(when?: number, offset?: number, duration?: number): void; stop(when?: number): void; - addEventListener(type: K, listener: (this: AudioBufferSourceNode, ev: AudioBufferSourceNodeEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: AudioBufferSourceNode, ev: AudioBufferSourceNodeEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: AudioBufferSourceNode, ev: AudioBufferSourceNodeEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: AudioBufferSourceNode, ev: AudioBufferSourceNodeEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var AudioBufferSourceNode: { @@ -1358,10 +1358,10 @@ interface AudioContextBase extends EventTarget { createWaveShaper(): WaveShaperNode; decodeAudioData(audioData: ArrayBuffer, successCallback?: DecodeSuccessCallback, errorCallback?: DecodeErrorCallback): Promise; resume(): Promise; - addEventListener(type: K, listener: (this: AudioContext, ev: AudioContextEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: AudioContext, ev: AudioContextEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: AudioContext, ev: AudioContextEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: AudioContext, ev: AudioContextEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } interface AudioContext extends AudioContextBase { @@ -1468,10 +1468,10 @@ interface AudioTrackList extends EventTarget { onremovetrack: (this: AudioTrackList, ev: TrackEvent) => any; getTrackById(id: string): AudioTrack | null; item(index: number): AudioTrack; - addEventListener(type: K, listener: (this: AudioTrackList, ev: AudioTrackListEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: AudioTrackList, ev: AudioTrackListEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: AudioTrackList, ev: AudioTrackListEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: AudioTrackList, ev: AudioTrackListEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; [index: number]: AudioTrack; } @@ -2386,10 +2386,10 @@ declare var CustomEvent: { interface DataCue extends TextTrackCue { data: ArrayBuffer; - addEventListener(type: K, listener: (this: DataCue, ev: TextTrackCueEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: DataCue, ev: TextTrackCueEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: DataCue, ev: TextTrackCueEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: DataCue, ev: TextTrackCueEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var DataCue: { @@ -3311,10 +3311,10 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven * @param content The text and HTML tags to write. */ writeln(...content: string[]): void; - addEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var Document: { @@ -3638,10 +3638,10 @@ interface Element extends Node, GlobalEventHandlers, ElementTraversal, NodeSelec insertAdjacentHTML(where: InsertPosition, html: string): void; insertAdjacentText(where: InsertPosition, text: string): void; attachShadow(shadowRootInitDict: ShadowRootInit): ShadowRoot; - addEventListener(type: K, listener: (this: Element, ev: ElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: Element, ev: ElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: Element, ev: ElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: Element, ev: ElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var Element: { @@ -3777,10 +3777,10 @@ interface FileReader extends EventTarget, MSBaseReader { readAsBinaryString(blob: Blob): void; readAsDataURL(blob: Blob): void; readAsText(blob: Blob, encoding?: string): void; - addEventListener(type: K, listener: (this: FileReader, ev: MSBaseReaderEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: FileReader, ev: MSBaseReaderEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: FileReader, ev: MSBaseReaderEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: FileReader, ev: MSBaseReaderEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var FileReader: { @@ -3901,7 +3901,7 @@ interface Headers { declare var Headers: { prototype: Headers; - new(init?: Headers | string[][] | object): Headers; + new(init?: HeadersInit): Headers; }; interface History { @@ -4012,10 +4012,10 @@ interface HTMLAnchorElement extends HTMLElement { * Returns a string representation of an object. */ toString(): string; - addEventListener(type: K, listener: (this: HTMLAnchorElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLAnchorElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLAnchorElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLAnchorElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLAnchorElement: { @@ -4088,10 +4088,10 @@ interface HTMLAppletElement extends HTMLElement { useMap: string; vspace: number; width: number; - addEventListener(type: K, listener: (this: HTMLAppletElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLAppletElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLAppletElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLAppletElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLAppletElement: { @@ -4158,10 +4158,10 @@ interface HTMLAreaElement extends HTMLElement { * Returns a string representation of an object. */ toString(): string; - addEventListener(type: K, listener: (this: HTMLAreaElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLAreaElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLAreaElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLAreaElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLAreaElement: { @@ -4178,10 +4178,10 @@ declare var HTMLAreasCollection: { }; interface HTMLAudioElement extends HTMLMediaElement { - addEventListener(type: K, listener: (this: HTMLAudioElement, ev: HTMLMediaElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLAudioElement, ev: HTMLMediaElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLAudioElement, ev: HTMLMediaElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLAudioElement, ev: HTMLMediaElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLAudioElement: { @@ -4198,10 +4198,10 @@ interface HTMLBaseElement extends HTMLElement { * Sets or retrieves the window or frame at which to target content. */ target: string; - addEventListener(type: K, listener: (this: HTMLBaseElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLBaseElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLBaseElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLBaseElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLBaseElement: { @@ -4218,10 +4218,10 @@ interface HTMLBaseFontElement extends HTMLElement, DOML2DeprecatedColorProperty * Sets or retrieves the font size of the object. */ size: number; - addEventListener(type: K, listener: (this: HTMLBaseFontElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLBaseFontElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLBaseFontElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLBaseFontElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLBaseFontElement: { @@ -4274,10 +4274,10 @@ interface HTMLBodyElement extends HTMLElement { onunload: (this: HTMLBodyElement, ev: Event) => any; text: any; vLink: any; - addEventListener(type: K, listener: (this: HTMLBodyElement, ev: HTMLBodyElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLBodyElement, ev: HTMLBodyElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLBodyElement, ev: HTMLBodyElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLBodyElement, ev: HTMLBodyElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLBodyElement: { @@ -4290,10 +4290,10 @@ interface HTMLBRElement extends HTMLElement { * Sets or retrieves the side on which floating objects are not to be positioned when any IHTMLBlockElement is inserted into the document. */ clear: string; - addEventListener(type: K, listener: (this: HTMLBRElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLBRElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLBRElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLBRElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLBRElement: { @@ -4365,10 +4365,10 @@ interface HTMLButtonElement extends HTMLElement { * @param error Sets a custom error message that is displayed when a form is submitted. */ setCustomValidity(error: string): void; - addEventListener(type: K, listener: (this: HTMLButtonElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLButtonElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLButtonElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLButtonElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLButtonElement: { @@ -4402,10 +4402,10 @@ interface HTMLCanvasElement extends HTMLElement { */ toDataURL(type?: string, ...args: any[]): string; toBlob(callback: (result: Blob | null) => void, type?: string, ...arguments: any[]): void; - addEventListener(type: K, listener: (this: HTMLCanvasElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLCanvasElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLCanvasElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLCanvasElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLCanvasElement: { @@ -4439,10 +4439,10 @@ declare var HTMLCollection: { interface HTMLDataElement extends HTMLElement { value: string; - addEventListener(type: K, listener: (this: HTMLDataElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLDataElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLDataElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLDataElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLDataElement: { @@ -4452,10 +4452,10 @@ declare var HTMLDataElement: { interface HTMLDataListElement extends HTMLElement { options: HTMLCollectionOf; - addEventListener(type: K, listener: (this: HTMLDataListElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLDataListElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLDataListElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLDataListElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLDataListElement: { @@ -4465,10 +4465,10 @@ declare var HTMLDataListElement: { interface HTMLDirectoryElement extends HTMLElement { compact: boolean; - addEventListener(type: K, listener: (this: HTMLDirectoryElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLDirectoryElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLDirectoryElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLDirectoryElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLDirectoryElement: { @@ -4485,10 +4485,10 @@ interface HTMLDivElement extends HTMLElement { * Sets or retrieves whether the browser automatically performs wordwrap. */ noWrap: boolean; - addEventListener(type: K, listener: (this: HTMLDivElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLDivElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLDivElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLDivElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLDivElement: { @@ -4498,10 +4498,10 @@ declare var HTMLDivElement: { interface HTMLDListElement extends HTMLElement { compact: boolean; - addEventListener(type: K, listener: (this: HTMLDListElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLDListElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLDListElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLDListElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLDListElement: { @@ -4510,10 +4510,10 @@ declare var HTMLDListElement: { }; interface HTMLDocument extends Document { - addEventListener(type: K, listener: (this: HTMLDocument, ev: DocumentEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLDocument, ev: DocumentEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLDocument, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLDocument, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLDocument: { @@ -4685,10 +4685,10 @@ interface HTMLElement extends Element { dragDrop(): boolean; focus(): void; msGetInputContext(): MSInputMethodContext; - addEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLElement: { @@ -4743,10 +4743,10 @@ interface HTMLEmbedElement extends HTMLElement, GetSVGDocument { * Sets or retrieves the width of the object. */ width: string; - addEventListener(type: K, listener: (this: HTMLEmbedElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLEmbedElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLEmbedElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLEmbedElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLEmbedElement: { @@ -4786,10 +4786,10 @@ interface HTMLFieldSetElement extends HTMLElement { * @param error Sets a custom error message that is displayed when a form is submitted. */ setCustomValidity(error: string): void; - addEventListener(type: K, listener: (this: HTMLFieldSetElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLFieldSetElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLFieldSetElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLFieldSetElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLFieldSetElement: { @@ -4802,10 +4802,10 @@ interface HTMLFontElement extends HTMLElement, DOML2DeprecatedColorProperty, DOM * Sets or retrieves the current typeface family. */ face: string; - addEventListener(type: K, listener: (this: HTMLFontElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLFontElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLFontElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLFontElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLFontElement: { @@ -4890,10 +4890,10 @@ interface HTMLFormElement extends HTMLElement { */ submit(): void; reportValidity(): boolean; - addEventListener(type: K, listener: (this: HTMLFormElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLFormElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLFormElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLFormElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; [name: string]: any; } @@ -4967,10 +4967,10 @@ interface HTMLFrameElement extends HTMLElement, GetSVGDocument { * Sets or retrieves the width of the object. */ width: string | number; - addEventListener(type: K, listener: (this: HTMLFrameElement, ev: HTMLFrameElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLFrameElement, ev: HTMLFrameElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLFrameElement, ev: HTMLFrameElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLFrameElement, ev: HTMLFrameElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLFrameElement: { @@ -5037,10 +5037,10 @@ interface HTMLFrameSetElement extends HTMLElement { * Sets or retrieves the frame heights of the object. */ rows: string; - addEventListener(type: K, listener: (this: HTMLFrameSetElement, ev: HTMLFrameSetElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLFrameSetElement, ev: HTMLFrameSetElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLFrameSetElement, ev: HTMLFrameSetElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLFrameSetElement, ev: HTMLFrameSetElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLFrameSetElement: { @@ -5050,10 +5050,10 @@ declare var HTMLFrameSetElement: { interface HTMLHeadElement extends HTMLElement { profile: string; - addEventListener(type: K, listener: (this: HTMLHeadElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLHeadElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLHeadElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLHeadElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLHeadElement: { @@ -5066,10 +5066,10 @@ interface HTMLHeadingElement extends HTMLElement { * Sets or retrieves a value that indicates the table alignment. */ align: string; - addEventListener(type: K, listener: (this: HTMLHeadingElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLHeadingElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLHeadingElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLHeadingElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLHeadingElement: { @@ -5090,10 +5090,10 @@ interface HTMLHRElement extends HTMLElement, DOML2DeprecatedColorProperty, DOML2 * Sets or retrieves the width of the object. */ width: number; - addEventListener(type: K, listener: (this: HTMLHRElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLHRElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLHRElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLHRElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLHRElement: { @@ -5106,10 +5106,10 @@ interface HTMLHtmlElement extends HTMLElement { * Sets or retrieves the DTD version that governs the current document. */ version: string; - addEventListener(type: K, listener: (this: HTMLHtmlElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLHtmlElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLHtmlElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLHtmlElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLHtmlElement: { @@ -5193,10 +5193,10 @@ interface HTMLIFrameElement extends HTMLElement, GetSVGDocument { * Sets or retrieves the width of the object. */ width: string; - addEventListener(type: K, listener: (this: HTMLIFrameElement, ev: HTMLIFrameElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLIFrameElement, ev: HTMLIFrameElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLIFrameElement, ev: HTMLIFrameElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLIFrameElement, ev: HTMLIFrameElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLIFrameElement: { @@ -5286,10 +5286,10 @@ interface HTMLImageElement extends HTMLElement { readonly x: number; readonly y: number; msGetAsCastingSource(): any; - addEventListener(type: K, listener: (this: HTMLImageElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLImageElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLImageElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLImageElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLImageElement: { @@ -5500,10 +5500,10 @@ interface HTMLInputElement extends HTMLElement { * @param n Value to increment the value by. */ stepUp(n?: number): void; - addEventListener(type: K, listener: (this: HTMLInputElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLInputElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLInputElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLInputElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLInputElement: { @@ -5520,10 +5520,10 @@ interface HTMLLabelElement extends HTMLElement { * Sets or retrieves the object to which the given label object is assigned. */ htmlFor: string; - addEventListener(type: K, listener: (this: HTMLLabelElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLLabelElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLLabelElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLLabelElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLLabelElement: { @@ -5540,10 +5540,10 @@ interface HTMLLegendElement extends HTMLElement { * Retrieves a reference to the form that the object is embedded in. */ readonly form: HTMLFormElement | null; - addEventListener(type: K, listener: (this: HTMLLegendElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLLegendElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLLegendElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLLegendElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLLegendElement: { @@ -5557,10 +5557,10 @@ interface HTMLLIElement extends HTMLElement { * Sets or retrieves the value of a list item. */ value: number; - addEventListener(type: K, listener: (this: HTMLLIElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLLIElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLLIElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLLIElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLLIElement: { @@ -5604,10 +5604,10 @@ interface HTMLLinkElement extends HTMLElement, LinkStyle { type: string; import?: Document; integrity: string; - addEventListener(type: K, listener: (this: HTMLLinkElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLLinkElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLLinkElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLLinkElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLLinkElement: { @@ -5624,10 +5624,10 @@ interface HTMLMapElement extends HTMLElement { * Sets or retrieves the name of the object. */ name: string; - addEventListener(type: K, listener: (this: HTMLMapElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLMapElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLMapElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLMapElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLMapElement: { @@ -5658,10 +5658,10 @@ interface HTMLMarqueeElement extends HTMLElement { width: string; start(): void; stop(): void; - addEventListener(type: K, listener: (this: HTMLMarqueeElement, ev: HTMLMarqueeElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLMarqueeElement, ev: HTMLMarqueeElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLMarqueeElement, ev: HTMLMarqueeElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLMarqueeElement, ev: HTMLMarqueeElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLMarqueeElement: { @@ -5842,10 +5842,10 @@ interface HTMLMediaElement extends HTMLElement { readonly NETWORK_IDLE: number; readonly NETWORK_LOADING: number; readonly NETWORK_NO_SOURCE: number; - addEventListener(type: K, listener: (this: HTMLMediaElement, ev: HTMLMediaElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLMediaElement, ev: HTMLMediaElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLMediaElement, ev: HTMLMediaElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLMediaElement, ev: HTMLMediaElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLMediaElement: { @@ -5865,10 +5865,10 @@ declare var HTMLMediaElement: { interface HTMLMenuElement extends HTMLElement { compact: boolean; type: string; - addEventListener(type: K, listener: (this: HTMLMenuElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLMenuElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLMenuElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLMenuElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLMenuElement: { @@ -5901,10 +5901,10 @@ interface HTMLMetaElement extends HTMLElement { * Sets or retrieves the URL property that will be loaded after the specified time has elapsed. */ url: string; - addEventListener(type: K, listener: (this: HTMLMetaElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLMetaElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLMetaElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLMetaElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLMetaElement: { @@ -5919,10 +5919,10 @@ interface HTMLMeterElement extends HTMLElement { min: number; optimum: number; value: number; - addEventListener(type: K, listener: (this: HTMLMeterElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLMeterElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLMeterElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLMeterElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLMeterElement: { @@ -5939,10 +5939,10 @@ interface HTMLModElement extends HTMLElement { * Sets or retrieves the date and time of a modification to the object. */ dateTime: string; - addEventListener(type: K, listener: (this: HTMLModElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLModElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLModElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLModElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLModElement: { @@ -6058,10 +6058,10 @@ interface HTMLObjectElement extends HTMLElement, GetSVGDocument { * @param error Sets a custom error message that is displayed when a form is submitted. */ setCustomValidity(error: string): void; - addEventListener(type: K, listener: (this: HTMLObjectElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLObjectElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLObjectElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLObjectElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLObjectElement: { @@ -6076,10 +6076,10 @@ interface HTMLOListElement extends HTMLElement { */ start: number; type: string; - addEventListener(type: K, listener: (this: HTMLOListElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLOListElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLOListElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLOListElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLOListElement: { @@ -6117,10 +6117,10 @@ interface HTMLOptGroupElement extends HTMLElement { * Sets or retrieves the value which is returned to the server when the form control is submitted. */ value: string; - addEventListener(type: K, listener: (this: HTMLOptGroupElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLOptGroupElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLOptGroupElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLOptGroupElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLOptGroupElement: { @@ -6158,10 +6158,10 @@ interface HTMLOptionElement extends HTMLElement { * Sets or retrieves the value which is returned to the server when the form control is submitted. */ value: string; - addEventListener(type: K, listener: (this: HTMLOptionElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLOptionElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLOptionElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLOptionElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLOptionElement: { @@ -6194,10 +6194,10 @@ interface HTMLOutputElement extends HTMLElement { checkValidity(): boolean; reportValidity(): boolean; setCustomValidity(error: string): void; - addEventListener(type: K, listener: (this: HTMLOutputElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLOutputElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLOutputElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLOutputElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLOutputElement: { @@ -6211,10 +6211,10 @@ interface HTMLParagraphElement extends HTMLElement { */ align: string; clear: string; - addEventListener(type: K, listener: (this: HTMLParagraphElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLParagraphElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLParagraphElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLParagraphElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLParagraphElement: { @@ -6239,10 +6239,10 @@ interface HTMLParamElement extends HTMLElement { * Sets or retrieves the data type of the value attribute. */ valueType: string; - addEventListener(type: K, listener: (this: HTMLParamElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLParamElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLParamElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLParamElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLParamElement: { @@ -6251,10 +6251,10 @@ declare var HTMLParamElement: { }; interface HTMLPictureElement extends HTMLElement { - addEventListener(type: K, listener: (this: HTMLPictureElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLPictureElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLPictureElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLPictureElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLPictureElement: { @@ -6267,10 +6267,10 @@ interface HTMLPreElement extends HTMLElement { * Sets or gets a value that you can use to implement your own width functionality for the object. */ width: number; - addEventListener(type: K, listener: (this: HTMLPreElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLPreElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLPreElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLPreElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLPreElement: { @@ -6295,10 +6295,10 @@ interface HTMLProgressElement extends HTMLElement { * Sets or gets the current value of a progress element. The value must be a non-negative number between 0 and the max value. */ value: number; - addEventListener(type: K, listener: (this: HTMLProgressElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLProgressElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLProgressElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLProgressElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLProgressElement: { @@ -6311,10 +6311,10 @@ interface HTMLQuoteElement extends HTMLElement { * Sets or retrieves reference information about the object. */ cite: string; - addEventListener(type: K, listener: (this: HTMLQuoteElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLQuoteElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLQuoteElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLQuoteElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLQuoteElement: { @@ -6354,10 +6354,10 @@ interface HTMLScriptElement extends HTMLElement { */ type: string; integrity: string; - addEventListener(type: K, listener: (this: HTMLScriptElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLScriptElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLScriptElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLScriptElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLScriptElement: { @@ -6452,10 +6452,10 @@ interface HTMLSelectElement extends HTMLElement { * @param error Sets a custom error message that is displayed when a form is submitted. */ setCustomValidity(error: string): void; - addEventListener(type: K, listener: (this: HTMLSelectElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLSelectElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLSelectElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLSelectElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; [name: string]: any; } @@ -6480,10 +6480,10 @@ interface HTMLSourceElement extends HTMLElement { * Gets or sets the MIME type of a media resource. */ type: string; - addEventListener(type: K, listener: (this: HTMLSourceElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLSourceElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLSourceElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLSourceElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLSourceElement: { @@ -6492,10 +6492,10 @@ declare var HTMLSourceElement: { }; interface HTMLSpanElement extends HTMLElement { - addEventListener(type: K, listener: (this: HTMLSpanElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLSpanElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLSpanElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLSpanElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLSpanElement: { @@ -6513,10 +6513,10 @@ interface HTMLStyleElement extends HTMLElement, LinkStyle { * Retrieves the CSS language in which the style sheet is written. */ type: string; - addEventListener(type: K, listener: (this: HTMLStyleElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLStyleElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLStyleElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLStyleElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLStyleElement: { @@ -6533,10 +6533,10 @@ interface HTMLTableCaptionElement extends HTMLElement { * Sets or retrieves whether the caption appears at the top or bottom of the table. */ vAlign: string; - addEventListener(type: K, listener: (this: HTMLTableCaptionElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLTableCaptionElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLTableCaptionElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLTableCaptionElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLTableCaptionElement: { @@ -6590,10 +6590,10 @@ interface HTMLTableCellElement extends HTMLElement, HTMLTableAlignment { * Sets or retrieves the width of the object. */ width: string; - addEventListener(type: K, listener: (this: HTMLTableCellElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLTableCellElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLTableCellElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLTableCellElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLTableCellElement: { @@ -6614,10 +6614,10 @@ interface HTMLTableColElement extends HTMLElement, HTMLTableAlignment { * Sets or retrieves the width of the object. */ width: any; - addEventListener(type: K, listener: (this: HTMLTableColElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLTableColElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLTableColElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLTableColElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLTableColElement: { @@ -6626,10 +6626,10 @@ declare var HTMLTableColElement: { }; interface HTMLTableDataCellElement extends HTMLTableCellElement { - addEventListener(type: K, listener: (this: HTMLTableDataCellElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLTableDataCellElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLTableDataCellElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLTableDataCellElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLTableDataCellElement: { @@ -6741,10 +6741,10 @@ interface HTMLTableElement extends HTMLElement { * @param index Number that specifies where to insert the row in the rows collection. The default value is -1, which appends the new row to the end of the rows collection. */ insertRow(index?: number): HTMLTableRowElement; - addEventListener(type: K, listener: (this: HTMLTableElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLTableElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLTableElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLTableElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLTableElement: { @@ -6757,10 +6757,10 @@ interface HTMLTableHeaderCellElement extends HTMLTableCellElement { * Sets or retrieves the group of cells in a table to which the object's information applies. */ scope: string; - addEventListener(type: K, listener: (this: HTMLTableHeaderCellElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLTableHeaderCellElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLTableHeaderCellElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLTableHeaderCellElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLTableHeaderCellElement: { @@ -6800,10 +6800,10 @@ interface HTMLTableRowElement extends HTMLElement, HTMLTableAlignment { * @param index Number that specifies where to insert the cell in the tr. The default value is -1, which appends the new cell to the end of the cells collection. */ insertCell(index?: number): HTMLTableDataCellElement; - addEventListener(type: K, listener: (this: HTMLTableRowElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLTableRowElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLTableRowElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLTableRowElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLTableRowElement: { @@ -6830,10 +6830,10 @@ interface HTMLTableSectionElement extends HTMLElement, HTMLTableAlignment { * @param index Number that specifies where to insert the row in the rows collection. The default value is -1, which appends the new row to the end of the rows collection. */ insertRow(index?: number): HTMLTableRowElement; - addEventListener(type: K, listener: (this: HTMLTableSectionElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLTableSectionElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLTableSectionElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLTableSectionElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLTableSectionElement: { @@ -6843,10 +6843,10 @@ declare var HTMLTableSectionElement: { interface HTMLTemplateElement extends HTMLElement { readonly content: DocumentFragment; - addEventListener(type: K, listener: (this: HTMLTemplateElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLTemplateElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLTemplateElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLTemplateElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLTemplateElement: { @@ -6952,10 +6952,10 @@ interface HTMLTextAreaElement extends HTMLElement { * @param end The offset into the text field for the end of the selection. */ setSelectionRange(start: number, end: number): void; - addEventListener(type: K, listener: (this: HTMLTextAreaElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLTextAreaElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLTextAreaElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLTextAreaElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLTextAreaElement: { @@ -6965,10 +6965,10 @@ declare var HTMLTextAreaElement: { interface HTMLTimeElement extends HTMLElement { dateTime: string; - addEventListener(type: K, listener: (this: HTMLTimeElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLTimeElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLTimeElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLTimeElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLTimeElement: { @@ -6981,10 +6981,10 @@ interface HTMLTitleElement extends HTMLElement { * Retrieves or sets the text of the object as a string. */ text: string; - addEventListener(type: K, listener: (this: HTMLTitleElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLTitleElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLTitleElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLTitleElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLTitleElement: { @@ -7004,10 +7004,10 @@ interface HTMLTrackElement extends HTMLElement { readonly LOADED: number; readonly LOADING: number; readonly NONE: number; - addEventListener(type: K, listener: (this: HTMLTrackElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLTrackElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLTrackElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLTrackElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLTrackElement: { @@ -7022,10 +7022,10 @@ declare var HTMLTrackElement: { interface HTMLUListElement extends HTMLElement { compact: boolean; type: string; - addEventListener(type: K, listener: (this: HTMLUListElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLUListElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLUListElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLUListElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLUListElement: { @@ -7034,10 +7034,10 @@ declare var HTMLUListElement: { }; interface HTMLUnknownElement extends HTMLElement { - addEventListener(type: K, listener: (this: HTMLUnknownElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLUnknownElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLUnknownElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLUnknownElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLUnknownElement: { @@ -7091,10 +7091,10 @@ interface HTMLVideoElement extends HTMLMediaElement { webkitEnterFullScreen(): void; webkitExitFullscreen(): void; webkitExitFullScreen(): void; - addEventListener(type: K, listener: (this: HTMLVideoElement, ev: HTMLVideoElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLVideoElement, ev: HTMLVideoElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: HTMLVideoElement, ev: HTMLVideoElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLVideoElement, ev: HTMLVideoElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var HTMLVideoElement: { @@ -7151,11 +7151,12 @@ interface IDBDatabase extends EventTarget { createObjectStore(name: string, optionalParameters?: IDBObjectStoreParameters): IDBObjectStore; deleteObjectStore(name: string): void; transaction(storeNames: string | string[], mode?: IDBTransactionMode): IDBTransaction; - addEventListener(type: "versionchange", listener: (ev: IDBVersionChangeEvent) => any, useCapture?: boolean): void; - addEventListener(type: K, listener: (this: IDBDatabase, ev: IDBDatabaseEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: IDBDatabase, ev: IDBDatabaseEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: "versionchange", listener: (this: IDBDatabase, ev: IDBVersionChangeEvent) => any, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: "versionchange", listener: (this: IDBDatabase, ev: IDBVersionChangeEvent) => any, options?: boolean | EventListenerOptions): void; + addEventListener(type: K, listener: (this: IDBDatabase, ev: IDBDatabaseEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: IDBDatabase, ev: IDBDatabaseEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var IDBDatabase: { @@ -7239,10 +7240,10 @@ interface IDBOpenDBRequestEventMap extends IDBRequestEventMap { interface IDBOpenDBRequest extends IDBRequest { onblocked: (this: IDBOpenDBRequest, ev: Event) => any; onupgradeneeded: (this: IDBOpenDBRequest, ev: IDBVersionChangeEvent) => any; - addEventListener(type: K, listener: (this: IDBOpenDBRequest, ev: IDBOpenDBRequestEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: IDBOpenDBRequest, ev: IDBOpenDBRequestEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: IDBOpenDBRequest, ev: IDBOpenDBRequestEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: IDBOpenDBRequest, ev: IDBOpenDBRequestEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var IDBOpenDBRequest: { @@ -7263,10 +7264,10 @@ interface IDBRequest extends EventTarget { readonly result: any; source: IDBObjectStore | IDBIndex | IDBCursor; readonly transaction: IDBTransaction; - addEventListener(type: K, listener: (this: IDBRequest, ev: IDBRequestEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: IDBRequest, ev: IDBRequestEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: IDBRequest, ev: IDBRequestEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: IDBRequest, ev: IDBRequestEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var IDBRequest: { @@ -7292,10 +7293,10 @@ interface IDBTransaction extends EventTarget { readonly READ_ONLY: string; readonly READ_WRITE: string; readonly VERSION_CHANGE: string; - addEventListener(type: K, listener: (this: IDBTransaction, ev: IDBTransactionEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: IDBTransaction, ev: IDBTransactionEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: IDBTransaction, ev: IDBTransactionEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: IDBTransaction, ev: IDBTransactionEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var IDBTransaction: { @@ -7464,10 +7465,10 @@ interface MediaDevices extends EventTarget { enumerateDevices(): Promise; getSupportedConstraints(): MediaTrackSupportedConstraints; getUserMedia(constraints: MediaStreamConstraints): Promise; - addEventListener(type: K, listener: (this: MediaDevices, ev: MediaDevicesEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: MediaDevices, ev: MediaDevicesEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: MediaDevices, ev: MediaDevicesEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: MediaDevices, ev: MediaDevicesEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var MediaDevices: { @@ -7638,10 +7639,10 @@ interface MediaStream extends EventTarget { getVideoTracks(): MediaStreamTrack[]; removeTrack(track: MediaStreamTrack): void; stop(): void; - addEventListener(type: K, listener: (this: MediaStream, ev: MediaStreamEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: MediaStream, ev: MediaStreamEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: MediaStream, ev: MediaStreamEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: MediaStream, ev: MediaStreamEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var MediaStream: { @@ -7712,10 +7713,10 @@ interface MediaStreamTrack extends EventTarget { getConstraints(): MediaTrackConstraints; getSettings(): MediaTrackSettings; stop(): void; - addEventListener(type: K, listener: (this: MediaStreamTrack, ev: MediaStreamTrackEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: MediaStreamTrack, ev: MediaStreamTrackEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: MediaStreamTrack, ev: MediaStreamTrackEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: MediaStreamTrack, ev: MediaStreamTrackEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var MediaStreamTrack: { @@ -7764,10 +7765,10 @@ interface MessagePort extends EventTarget { close(): void; postMessage(message?: any, transfer?: any[]): void; start(): void; - addEventListener(type: K, listener: (this: MessagePort, ev: MessagePortEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: MessagePort, ev: MessagePortEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: MessagePort, ev: MessagePortEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: MessagePort, ev: MessagePortEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var MessagePort: { @@ -7871,10 +7872,10 @@ interface MSAppAsyncOperation extends EventTarget { readonly COMPLETED: number; readonly ERROR: number; readonly STARTED: number; - addEventListener(type: K, listener: (this: MSAppAsyncOperation, ev: MSAppAsyncOperationEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: MSAppAsyncOperation, ev: MSAppAsyncOperationEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: MSAppAsyncOperation, ev: MSAppAsyncOperationEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: MSAppAsyncOperation, ev: MSAppAsyncOperationEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var MSAppAsyncOperation: { @@ -8029,10 +8030,10 @@ interface MSHTMLWebViewElement extends HTMLElement { navigateWithHttpRequestMessage(requestMessage: any): void; refresh(): void; stop(): void; - addEventListener(type: K, listener: (this: MSHTMLWebViewElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: MSHTMLWebViewElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: MSHTMLWebViewElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: MSHTMLWebViewElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var MSHTMLWebViewElement: { @@ -8057,10 +8058,10 @@ interface MSInputMethodContext extends EventTarget { getCompositionAlternatives(): string[]; hasComposition(): boolean; isCandidateWindowVisible(): boolean; - addEventListener(type: K, listener: (this: MSInputMethodContext, ev: MSInputMethodContextEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: MSInputMethodContext, ev: MSInputMethodContextEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: MSInputMethodContext, ev: MSInputMethodContextEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: MSInputMethodContext, ev: MSInputMethodContextEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var MSInputMethodContext: { @@ -8225,10 +8226,10 @@ interface MSStreamReader extends EventTarget, MSBaseReader { readAsBlob(stream: MSStream, size?: number): void; readAsDataURL(stream: MSStream, size?: number): void; readAsText(stream: MSStream, encoding?: string, size?: number): void; - addEventListener(type: K, listener: (this: MSStreamReader, ev: MSBaseReaderEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: MSStreamReader, ev: MSBaseReaderEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: MSStreamReader, ev: MSBaseReaderEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: MSStreamReader, ev: MSBaseReaderEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var MSStreamReader: { @@ -8256,10 +8257,10 @@ interface MSWebViewAsyncOperation extends EventTarget { readonly TYPE_CAPTURE_PREVIEW_TO_RANDOM_ACCESS_STREAM: number; readonly TYPE_CREATE_DATA_PACKAGE_FROM_SELECTION: number; readonly TYPE_INVOKE_SCRIPT: number; - addEventListener(type: K, listener: (this: MSWebViewAsyncOperation, ev: MSWebViewAsyncOperationEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: MSWebViewAsyncOperation, ev: MSWebViewAsyncOperationEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: MSWebViewAsyncOperation, ev: MSWebViewAsyncOperationEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: MSWebViewAsyncOperation, ev: MSWebViewAsyncOperationEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var MSWebViewAsyncOperation: { @@ -8549,10 +8550,10 @@ interface Notification extends EventTarget { readonly tag: string; readonly title: string; close(): void; - addEventListener(type: K, listener: (this: Notification, ev: NotificationEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: Notification, ev: NotificationEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: Notification, ev: NotificationEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: Notification, ev: NotificationEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var Notification: { @@ -8631,10 +8632,10 @@ interface OfflineAudioContext extends AudioContextBase { oncomplete: (this: OfflineAudioContext, ev: OfflineAudioCompletionEvent) => any; startRendering(): Promise; suspend(suspendTime: number): Promise; - addEventListener(type: K, listener: (this: OfflineAudioContext, ev: OfflineAudioContextEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: OfflineAudioContext, ev: OfflineAudioContextEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: OfflineAudioContext, ev: OfflineAudioContextEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: OfflineAudioContext, ev: OfflineAudioContextEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var OfflineAudioContext: { @@ -8654,10 +8655,10 @@ interface OscillatorNode extends AudioNode { setPeriodicWave(periodicWave: PeriodicWave): void; start(when?: number): void; stop(when?: number): void; - addEventListener(type: K, listener: (this: OscillatorNode, ev: OscillatorNodeEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: OscillatorNode, ev: OscillatorNodeEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: OscillatorNode, ev: OscillatorNodeEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: OscillatorNode, ev: OscillatorNodeEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var OscillatorNode: { @@ -8751,10 +8752,10 @@ interface PaymentRequest extends EventTarget { readonly shippingType: PaymentShippingType | null; abort(): Promise; show(): Promise; - addEventListener(type: K, listener: (this: PaymentRequest, ev: PaymentRequestEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: PaymentRequest, ev: PaymentRequestEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: PaymentRequest, ev: PaymentRequestEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: PaymentRequest, ev: PaymentRequestEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var PaymentRequest: { @@ -9260,10 +9261,10 @@ interface RTCDtlsTransport extends RTCStatsProvider { getRemoteParameters(): RTCDtlsParameters | null; start(remoteParameters: RTCDtlsParameters): void; stop(): void; - addEventListener(type: K, listener: (this: RTCDtlsTransport, ev: RTCDtlsTransportEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: RTCDtlsTransport, ev: RTCDtlsTransportEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: RTCDtlsTransport, ev: RTCDtlsTransportEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: RTCDtlsTransport, ev: RTCDtlsTransportEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var RTCDtlsTransport: { @@ -9292,10 +9293,10 @@ interface RTCDtmfSender extends EventTarget { readonly sender: RTCRtpSender; readonly toneBuffer: string; insertDTMF(tones: string, duration?: number, interToneGap?: number): void; - addEventListener(type: K, listener: (this: RTCDtmfSender, ev: RTCDtmfSenderEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: RTCDtmfSender, ev: RTCDtmfSenderEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: RTCDtmfSender, ev: RTCDtmfSenderEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: RTCDtmfSender, ev: RTCDtmfSenderEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var RTCDtmfSender: { @@ -9345,10 +9346,10 @@ interface RTCIceGatherer extends RTCStatsProvider { createAssociatedGatherer(): RTCIceGatherer; getLocalCandidates(): RTCIceCandidateDictionary[]; getLocalParameters(): RTCIceParameters; - addEventListener(type: K, listener: (this: RTCIceGatherer, ev: RTCIceGathererEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: RTCIceGatherer, ev: RTCIceGathererEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: RTCIceGatherer, ev: RTCIceGathererEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: RTCIceGatherer, ev: RTCIceGathererEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var RTCIceGatherer: { @@ -9385,10 +9386,10 @@ interface RTCIceTransport extends RTCStatsProvider { setRemoteCandidates(remoteCandidates: RTCIceCandidateDictionary[]): void; start(gatherer: RTCIceGatherer, remoteParameters: RTCIceParameters, role?: RTCIceRole): void; stop(): void; - addEventListener(type: K, listener: (this: RTCIceTransport, ev: RTCIceTransportEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: RTCIceTransport, ev: RTCIceTransportEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: RTCIceTransport, ev: RTCIceTransportEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: RTCIceTransport, ev: RTCIceTransportEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var RTCIceTransport: { @@ -9442,10 +9443,10 @@ interface RTCPeerConnection extends EventTarget { removeStream(stream: MediaStream): void; setLocalDescription(description: RTCSessionDescription, successCallback?: VoidFunction, failureCallback?: RTCPeerConnectionErrorCallback): Promise; setRemoteDescription(description: RTCSessionDescription, successCallback?: VoidFunction, failureCallback?: RTCPeerConnectionErrorCallback): Promise; - addEventListener(type: K, listener: (this: RTCPeerConnection, ev: RTCPeerConnectionEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: RTCPeerConnection, ev: RTCPeerConnectionEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: RTCPeerConnection, ev: RTCPeerConnectionEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: RTCPeerConnection, ev: RTCPeerConnectionEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var RTCPeerConnection: { @@ -9476,10 +9477,10 @@ interface RTCRtpReceiver extends RTCStatsProvider { requestSendCSRC(csrc: number): void; setTransport(transport: RTCDtlsTransport | RTCSrtpSdesTransport, rtcpTransport?: RTCDtlsTransport): void; stop(): void; - addEventListener(type: K, listener: (this: RTCRtpReceiver, ev: RTCRtpReceiverEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: RTCRtpReceiver, ev: RTCRtpReceiverEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: RTCRtpReceiver, ev: RTCRtpReceiverEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: RTCRtpReceiver, ev: RTCRtpReceiverEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var RTCRtpReceiver: { @@ -9503,10 +9504,10 @@ interface RTCRtpSender extends RTCStatsProvider { setTrack(track: MediaStreamTrack): void; setTransport(transport: RTCDtlsTransport | RTCSrtpSdesTransport, rtcpTransport?: RTCDtlsTransport): void; stop(): void; - addEventListener(type: K, listener: (this: RTCRtpSender, ev: RTCRtpSenderEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: RTCRtpSender, ev: RTCRtpSenderEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: RTCRtpSender, ev: RTCRtpSenderEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: RTCRtpSender, ev: RTCRtpSenderEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var RTCRtpSender: { @@ -9533,10 +9534,10 @@ interface RTCSrtpSdesTransportEventMap { interface RTCSrtpSdesTransport extends EventTarget { onerror: ((this: RTCSrtpSdesTransport, ev: Event) => any) | null; readonly transport: RTCIceTransport; - addEventListener(type: K, listener: (this: RTCSrtpSdesTransport, ev: RTCSrtpSdesTransportEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: RTCSrtpSdesTransport, ev: RTCSrtpSdesTransportEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: RTCSrtpSdesTransport, ev: RTCSrtpSdesTransportEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: RTCSrtpSdesTransport, ev: RTCSrtpSdesTransportEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var RTCSrtpSdesTransport: { @@ -9607,10 +9608,10 @@ interface Screen extends EventTarget { readonly width: number; msLockOrientation(orientations: string | string[]): boolean; msUnlockOrientation(): void; - addEventListener(type: K, listener: (this: Screen, ev: ScreenEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: Screen, ev: ScreenEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: Screen, ev: ScreenEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: Screen, ev: ScreenEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var Screen: { @@ -9635,10 +9636,10 @@ interface ScriptProcessorNodeEventMap { interface ScriptProcessorNode extends AudioNode { readonly bufferSize: number; onaudioprocess: (this: ScriptProcessorNode, ev: AudioProcessingEvent) => any; - addEventListener(type: K, listener: (this: ScriptProcessorNode, ev: ScriptProcessorNodeEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: ScriptProcessorNode, ev: ScriptProcessorNodeEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: ScriptProcessorNode, ev: ScriptProcessorNodeEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: ScriptProcessorNode, ev: ScriptProcessorNodeEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var ScriptProcessorNode: { @@ -9689,10 +9690,10 @@ interface ServiceWorker extends EventTarget, AbstractWorker { readonly scriptURL: USVString; readonly state: ServiceWorkerState; postMessage(message: any, transfer?: any[]): void; - addEventListener(type: K, listener: (this: ServiceWorker, ev: ServiceWorkerEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: ServiceWorker, ev: ServiceWorkerEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: ServiceWorker, ev: ServiceWorkerEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: ServiceWorker, ev: ServiceWorkerEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var ServiceWorker: { @@ -9713,10 +9714,10 @@ interface ServiceWorkerContainer extends EventTarget { getRegistration(): Promise; getRegistrations(): Promise; register(scriptURL: USVString, options?: RegistrationOptions): Promise; - addEventListener(type: K, listener: (this: ServiceWorkerContainer, ev: ServiceWorkerContainerEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: ServiceWorkerContainer, ev: ServiceWorkerContainerEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: ServiceWorkerContainer, ev: ServiceWorkerContainerEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: ServiceWorkerContainer, ev: ServiceWorkerContainerEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var ServiceWorkerContainer: { @@ -9753,10 +9754,10 @@ interface ServiceWorkerRegistration extends EventTarget { showNotification(title: string, options?: NotificationOptions): Promise; unregister(): Promise; update(): Promise; - addEventListener(type: K, listener: (this: ServiceWorkerRegistration, ev: ServiceWorkerRegistrationEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: ServiceWorkerRegistration, ev: ServiceWorkerRegistrationEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: ServiceWorkerRegistration, ev: ServiceWorkerRegistrationEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: ServiceWorkerRegistration, ev: ServiceWorkerRegistrationEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var ServiceWorkerRegistration: { @@ -9809,10 +9810,10 @@ interface SpeechSynthesis extends EventTarget { pause(): void; resume(): void; speak(utterance: SpeechSynthesisUtterance): void; - addEventListener(type: K, listener: (this: SpeechSynthesis, ev: SpeechSynthesisEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SpeechSynthesis, ev: SpeechSynthesisEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SpeechSynthesis, ev: SpeechSynthesisEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SpeechSynthesis, ev: SpeechSynthesisEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SpeechSynthesis: { @@ -9856,10 +9857,10 @@ interface SpeechSynthesisUtterance extends EventTarget { text: string; voice: SpeechSynthesisVoice; volume: number; - addEventListener(type: K, listener: (this: SpeechSynthesisUtterance, ev: SpeechSynthesisUtteranceEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SpeechSynthesisUtterance, ev: SpeechSynthesisUtteranceEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SpeechSynthesisUtterance, ev: SpeechSynthesisUtteranceEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SpeechSynthesisUtterance, ev: SpeechSynthesisUtteranceEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SpeechSynthesisUtterance: { @@ -9993,10 +9994,10 @@ declare var SubtleCrypto: { interface SVGAElement extends SVGGraphicsElement, SVGURIReference { readonly target: SVGAnimatedString; - addEventListener(type: K, listener: (this: SVGAElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGAElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGAElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGAElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGAElement: { @@ -10152,10 +10153,10 @@ interface SVGCircleElement extends SVGGraphicsElement { readonly cx: SVGAnimatedLength; readonly cy: SVGAnimatedLength; readonly r: SVGAnimatedLength; - addEventListener(type: K, listener: (this: SVGCircleElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGCircleElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGCircleElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGCircleElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGCircleElement: { @@ -10165,10 +10166,10 @@ declare var SVGCircleElement: { interface SVGClipPathElement extends SVGGraphicsElement, SVGUnitTypes { readonly clipPathUnits: SVGAnimatedEnumeration; - addEventListener(type: K, listener: (this: SVGClipPathElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGClipPathElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGClipPathElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGClipPathElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGClipPathElement: { @@ -10190,10 +10191,10 @@ interface SVGComponentTransferFunctionElement extends SVGElement { readonly SVG_FECOMPONENTTRANSFER_TYPE_LINEAR: number; readonly SVG_FECOMPONENTTRANSFER_TYPE_TABLE: number; readonly SVG_FECOMPONENTTRANSFER_TYPE_UNKNOWN: number; - addEventListener(type: K, listener: (this: SVGComponentTransferFunctionElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGComponentTransferFunctionElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGComponentTransferFunctionElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGComponentTransferFunctionElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGComponentTransferFunctionElement: { @@ -10208,10 +10209,10 @@ declare var SVGComponentTransferFunctionElement: { }; interface SVGDefsElement extends SVGGraphicsElement { - addEventListener(type: K, listener: (this: SVGDefsElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGDefsElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGDefsElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGDefsElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGDefsElement: { @@ -10220,10 +10221,10 @@ declare var SVGDefsElement: { }; interface SVGDescElement extends SVGElement { - addEventListener(type: K, listener: (this: SVGDescElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGDescElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGDescElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGDescElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGDescElement: { @@ -10260,10 +10261,10 @@ interface SVGElement extends Element { readonly style: CSSStyleDeclaration; readonly viewportElement: SVGElement; xmlbase: string; - addEventListener(type: K, listener: (this: SVGElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGElement: { @@ -10302,10 +10303,10 @@ interface SVGEllipseElement extends SVGGraphicsElement { readonly cy: SVGAnimatedLength; readonly rx: SVGAnimatedLength; readonly ry: SVGAnimatedLength; - addEventListener(type: K, listener: (this: SVGEllipseElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGEllipseElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGEllipseElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGEllipseElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGEllipseElement: { @@ -10334,10 +10335,10 @@ interface SVGFEBlendElement extends SVGElement, SVGFilterPrimitiveStandardAttrib readonly SVG_FEBLEND_MODE_SCREEN: number; readonly SVG_FEBLEND_MODE_SOFT_LIGHT: number; readonly SVG_FEBLEND_MODE_UNKNOWN: number; - addEventListener(type: K, listener: (this: SVGFEBlendElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFEBlendElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFEBlendElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFEBlendElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFEBlendElement: { @@ -10371,10 +10372,10 @@ interface SVGFEColorMatrixElement extends SVGElement, SVGFilterPrimitiveStandard readonly SVG_FECOLORMATRIX_TYPE_MATRIX: number; readonly SVG_FECOLORMATRIX_TYPE_SATURATE: number; readonly SVG_FECOLORMATRIX_TYPE_UNKNOWN: number; - addEventListener(type: K, listener: (this: SVGFEColorMatrixElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFEColorMatrixElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFEColorMatrixElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFEColorMatrixElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFEColorMatrixElement: { @@ -10389,10 +10390,10 @@ declare var SVGFEColorMatrixElement: { interface SVGFEComponentTransferElement extends SVGElement, SVGFilterPrimitiveStandardAttributes { readonly in1: SVGAnimatedString; - addEventListener(type: K, listener: (this: SVGFEComponentTransferElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFEComponentTransferElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFEComponentTransferElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFEComponentTransferElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFEComponentTransferElement: { @@ -10415,10 +10416,10 @@ interface SVGFECompositeElement extends SVGElement, SVGFilterPrimitiveStandardAt readonly SVG_FECOMPOSITE_OPERATOR_OVER: number; readonly SVG_FECOMPOSITE_OPERATOR_UNKNOWN: number; readonly SVG_FECOMPOSITE_OPERATOR_XOR: number; - addEventListener(type: K, listener: (this: SVGFECompositeElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFECompositeElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFECompositeElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFECompositeElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFECompositeElement: { @@ -10450,10 +10451,10 @@ interface SVGFEConvolveMatrixElement extends SVGElement, SVGFilterPrimitiveStand readonly SVG_EDGEMODE_NONE: number; readonly SVG_EDGEMODE_UNKNOWN: number; readonly SVG_EDGEMODE_WRAP: number; - addEventListener(type: K, listener: (this: SVGFEConvolveMatrixElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFEConvolveMatrixElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFEConvolveMatrixElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFEConvolveMatrixElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFEConvolveMatrixElement: { @@ -10471,10 +10472,10 @@ interface SVGFEDiffuseLightingElement extends SVGElement, SVGFilterPrimitiveStan readonly kernelUnitLengthX: SVGAnimatedNumber; readonly kernelUnitLengthY: SVGAnimatedNumber; readonly surfaceScale: SVGAnimatedNumber; - addEventListener(type: K, listener: (this: SVGFEDiffuseLightingElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFEDiffuseLightingElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFEDiffuseLightingElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFEDiffuseLightingElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFEDiffuseLightingElement: { @@ -10493,10 +10494,10 @@ interface SVGFEDisplacementMapElement extends SVGElement, SVGFilterPrimitiveStan readonly SVG_CHANNEL_G: number; readonly SVG_CHANNEL_R: number; readonly SVG_CHANNEL_UNKNOWN: number; - addEventListener(type: K, listener: (this: SVGFEDisplacementMapElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFEDisplacementMapElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFEDisplacementMapElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFEDisplacementMapElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFEDisplacementMapElement: { @@ -10512,10 +10513,10 @@ declare var SVGFEDisplacementMapElement: { interface SVGFEDistantLightElement extends SVGElement { readonly azimuth: SVGAnimatedNumber; readonly elevation: SVGAnimatedNumber; - addEventListener(type: K, listener: (this: SVGFEDistantLightElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFEDistantLightElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFEDistantLightElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFEDistantLightElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFEDistantLightElement: { @@ -10524,10 +10525,10 @@ declare var SVGFEDistantLightElement: { }; interface SVGFEFloodElement extends SVGElement, SVGFilterPrimitiveStandardAttributes { - addEventListener(type: K, listener: (this: SVGFEFloodElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFEFloodElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFEFloodElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFEFloodElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFEFloodElement: { @@ -10536,10 +10537,10 @@ declare var SVGFEFloodElement: { }; interface SVGFEFuncAElement extends SVGComponentTransferFunctionElement { - addEventListener(type: K, listener: (this: SVGFEFuncAElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFEFuncAElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFEFuncAElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFEFuncAElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFEFuncAElement: { @@ -10548,10 +10549,10 @@ declare var SVGFEFuncAElement: { }; interface SVGFEFuncBElement extends SVGComponentTransferFunctionElement { - addEventListener(type: K, listener: (this: SVGFEFuncBElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFEFuncBElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFEFuncBElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFEFuncBElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFEFuncBElement: { @@ -10560,10 +10561,10 @@ declare var SVGFEFuncBElement: { }; interface SVGFEFuncGElement extends SVGComponentTransferFunctionElement { - addEventListener(type: K, listener: (this: SVGFEFuncGElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFEFuncGElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFEFuncGElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFEFuncGElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFEFuncGElement: { @@ -10572,10 +10573,10 @@ declare var SVGFEFuncGElement: { }; interface SVGFEFuncRElement extends SVGComponentTransferFunctionElement { - addEventListener(type: K, listener: (this: SVGFEFuncRElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFEFuncRElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFEFuncRElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFEFuncRElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFEFuncRElement: { @@ -10588,10 +10589,10 @@ interface SVGFEGaussianBlurElement extends SVGElement, SVGFilterPrimitiveStandar readonly stdDeviationX: SVGAnimatedNumber; readonly stdDeviationY: SVGAnimatedNumber; setStdDeviation(stdDeviationX: number, stdDeviationY: number): void; - addEventListener(type: K, listener: (this: SVGFEGaussianBlurElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFEGaussianBlurElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFEGaussianBlurElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFEGaussianBlurElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFEGaussianBlurElement: { @@ -10601,10 +10602,10 @@ declare var SVGFEGaussianBlurElement: { interface SVGFEImageElement extends SVGElement, SVGFilterPrimitiveStandardAttributes, SVGURIReference { readonly preserveAspectRatio: SVGAnimatedPreserveAspectRatio; - addEventListener(type: K, listener: (this: SVGFEImageElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFEImageElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFEImageElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFEImageElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFEImageElement: { @@ -10613,10 +10614,10 @@ declare var SVGFEImageElement: { }; interface SVGFEMergeElement extends SVGElement, SVGFilterPrimitiveStandardAttributes { - addEventListener(type: K, listener: (this: SVGFEMergeElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFEMergeElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFEMergeElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFEMergeElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFEMergeElement: { @@ -10626,10 +10627,10 @@ declare var SVGFEMergeElement: { interface SVGFEMergeNodeElement extends SVGElement { readonly in1: SVGAnimatedString; - addEventListener(type: K, listener: (this: SVGFEMergeNodeElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFEMergeNodeElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFEMergeNodeElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFEMergeNodeElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFEMergeNodeElement: { @@ -10645,10 +10646,10 @@ interface SVGFEMorphologyElement extends SVGElement, SVGFilterPrimitiveStandardA readonly SVG_MORPHOLOGY_OPERATOR_DILATE: number; readonly SVG_MORPHOLOGY_OPERATOR_ERODE: number; readonly SVG_MORPHOLOGY_OPERATOR_UNKNOWN: number; - addEventListener(type: K, listener: (this: SVGFEMorphologyElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFEMorphologyElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFEMorphologyElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFEMorphologyElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFEMorphologyElement: { @@ -10663,10 +10664,10 @@ interface SVGFEOffsetElement extends SVGElement, SVGFilterPrimitiveStandardAttri readonly dx: SVGAnimatedNumber; readonly dy: SVGAnimatedNumber; readonly in1: SVGAnimatedString; - addEventListener(type: K, listener: (this: SVGFEOffsetElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFEOffsetElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFEOffsetElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFEOffsetElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFEOffsetElement: { @@ -10678,10 +10679,10 @@ interface SVGFEPointLightElement extends SVGElement { readonly x: SVGAnimatedNumber; readonly y: SVGAnimatedNumber; readonly z: SVGAnimatedNumber; - addEventListener(type: K, listener: (this: SVGFEPointLightElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFEPointLightElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFEPointLightElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFEPointLightElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFEPointLightElement: { @@ -10696,10 +10697,10 @@ interface SVGFESpecularLightingElement extends SVGElement, SVGFilterPrimitiveSta readonly specularConstant: SVGAnimatedNumber; readonly specularExponent: SVGAnimatedNumber; readonly surfaceScale: SVGAnimatedNumber; - addEventListener(type: K, listener: (this: SVGFESpecularLightingElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFESpecularLightingElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFESpecularLightingElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFESpecularLightingElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFESpecularLightingElement: { @@ -10716,10 +10717,10 @@ interface SVGFESpotLightElement extends SVGElement { readonly x: SVGAnimatedNumber; readonly y: SVGAnimatedNumber; readonly z: SVGAnimatedNumber; - addEventListener(type: K, listener: (this: SVGFESpotLightElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFESpotLightElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFESpotLightElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFESpotLightElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFESpotLightElement: { @@ -10729,10 +10730,10 @@ declare var SVGFESpotLightElement: { interface SVGFETileElement extends SVGElement, SVGFilterPrimitiveStandardAttributes { readonly in1: SVGAnimatedString; - addEventListener(type: K, listener: (this: SVGFETileElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFETileElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFETileElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFETileElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFETileElement: { @@ -10753,10 +10754,10 @@ interface SVGFETurbulenceElement extends SVGElement, SVGFilterPrimitiveStandardA readonly SVG_TURBULENCE_TYPE_FRACTALNOISE: number; readonly SVG_TURBULENCE_TYPE_TURBULENCE: number; readonly SVG_TURBULENCE_TYPE_UNKNOWN: number; - addEventListener(type: K, listener: (this: SVGFETurbulenceElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFETurbulenceElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFETurbulenceElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFETurbulenceElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFETurbulenceElement: { @@ -10780,10 +10781,10 @@ interface SVGFilterElement extends SVGElement, SVGUnitTypes, SVGURIReference { readonly x: SVGAnimatedLength; readonly y: SVGAnimatedLength; setFilterRes(filterResX: number, filterResY: number): void; - addEventListener(type: K, listener: (this: SVGFilterElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGFilterElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGFilterElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGFilterElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGFilterElement: { @@ -10796,10 +10797,10 @@ interface SVGForeignObjectElement extends SVGGraphicsElement { readonly width: SVGAnimatedLength; readonly x: SVGAnimatedLength; readonly y: SVGAnimatedLength; - addEventListener(type: K, listener: (this: SVGForeignObjectElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGForeignObjectElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGForeignObjectElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGForeignObjectElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGForeignObjectElement: { @@ -10808,10 +10809,10 @@ declare var SVGForeignObjectElement: { }; interface SVGGElement extends SVGGraphicsElement { - addEventListener(type: K, listener: (this: SVGGElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGGElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGGElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGGElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGGElement: { @@ -10827,10 +10828,10 @@ interface SVGGradientElement extends SVGElement, SVGUnitTypes, SVGURIReference { readonly SVG_SPREADMETHOD_REFLECT: number; readonly SVG_SPREADMETHOD_REPEAT: number; readonly SVG_SPREADMETHOD_UNKNOWN: number; - addEventListener(type: K, listener: (this: SVGGradientElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGGradientElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGGradientElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGGradientElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGGradientElement: { @@ -10850,10 +10851,10 @@ interface SVGGraphicsElement extends SVGElement, SVGTests { getCTM(): SVGMatrix; getScreenCTM(): SVGMatrix; getTransformToElement(element: SVGElement): SVGMatrix; - addEventListener(type: K, listener: (this: SVGGraphicsElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGGraphicsElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGGraphicsElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGGraphicsElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGGraphicsElement: { @@ -10867,10 +10868,10 @@ interface SVGImageElement extends SVGGraphicsElement, SVGURIReference { readonly width: SVGAnimatedLength; readonly x: SVGAnimatedLength; readonly y: SVGAnimatedLength; - addEventListener(type: K, listener: (this: SVGImageElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGImageElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGImageElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGImageElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGImageElement: { @@ -10935,10 +10936,10 @@ interface SVGLinearGradientElement extends SVGGradientElement { readonly x2: SVGAnimatedLength; readonly y1: SVGAnimatedLength; readonly y2: SVGAnimatedLength; - addEventListener(type: K, listener: (this: SVGLinearGradientElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGLinearGradientElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGLinearGradientElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGLinearGradientElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGLinearGradientElement: { @@ -10951,10 +10952,10 @@ interface SVGLineElement extends SVGGraphicsElement { readonly x2: SVGAnimatedLength; readonly y1: SVGAnimatedLength; readonly y2: SVGAnimatedLength; - addEventListener(type: K, listener: (this: SVGLineElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGLineElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGLineElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGLineElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGLineElement: { @@ -10978,10 +10979,10 @@ interface SVGMarkerElement extends SVGElement, SVGFitToViewBox { readonly SVG_MARKERUNITS_STROKEWIDTH: number; readonly SVG_MARKERUNITS_UNKNOWN: number; readonly SVG_MARKERUNITS_USERSPACEONUSE: number; - addEventListener(type: K, listener: (this: SVGMarkerElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGMarkerElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGMarkerElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGMarkerElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGMarkerElement: { @@ -11002,10 +11003,10 @@ interface SVGMaskElement extends SVGElement, SVGTests, SVGUnitTypes { readonly width: SVGAnimatedLength; readonly x: SVGAnimatedLength; readonly y: SVGAnimatedLength; - addEventListener(type: K, listener: (this: SVGMaskElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGMaskElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGMaskElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGMaskElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGMaskElement: { @@ -11039,10 +11040,10 @@ declare var SVGMatrix: { }; interface SVGMetadataElement extends SVGElement { - addEventListener(type: K, listener: (this: SVGMetadataElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGMetadataElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGMetadataElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGMetadataElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGMetadataElement: { @@ -11099,10 +11100,10 @@ interface SVGPathElement extends SVGGraphicsElement { getPathSegAtLength(distance: number): number; getPointAtLength(distance: number): SVGPoint; getTotalLength(): number; - addEventListener(type: K, listener: (this: SVGPathElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGPathElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGPathElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGPathElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGPathElement: { @@ -11394,10 +11395,10 @@ interface SVGPatternElement extends SVGElement, SVGTests, SVGUnitTypes, SVGFitTo readonly width: SVGAnimatedLength; readonly x: SVGAnimatedLength; readonly y: SVGAnimatedLength; - addEventListener(type: K, listener: (this: SVGPatternElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGPatternElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGPatternElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGPatternElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGPatternElement: { @@ -11433,10 +11434,10 @@ declare var SVGPointList: { }; interface SVGPolygonElement extends SVGGraphicsElement, SVGAnimatedPoints { - addEventListener(type: K, listener: (this: SVGPolygonElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGPolygonElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGPolygonElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGPolygonElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGPolygonElement: { @@ -11445,10 +11446,10 @@ declare var SVGPolygonElement: { }; interface SVGPolylineElement extends SVGGraphicsElement, SVGAnimatedPoints { - addEventListener(type: K, listener: (this: SVGPolylineElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGPolylineElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGPolylineElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGPolylineElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGPolylineElement: { @@ -11500,10 +11501,10 @@ interface SVGRadialGradientElement extends SVGGradientElement { readonly fx: SVGAnimatedLength; readonly fy: SVGAnimatedLength; readonly r: SVGAnimatedLength; - addEventListener(type: K, listener: (this: SVGRadialGradientElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGRadialGradientElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGRadialGradientElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGRadialGradientElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGRadialGradientElement: { @@ -11530,10 +11531,10 @@ interface SVGRectElement extends SVGGraphicsElement { readonly width: SVGAnimatedLength; readonly x: SVGAnimatedLength; readonly y: SVGAnimatedLength; - addEventListener(type: K, listener: (this: SVGRectElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGRectElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGRectElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGRectElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGRectElement: { @@ -11543,10 +11544,10 @@ declare var SVGRectElement: { interface SVGScriptElement extends SVGElement, SVGURIReference { type: string; - addEventListener(type: K, listener: (this: SVGScriptElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGScriptElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGScriptElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGScriptElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGScriptElement: { @@ -11556,10 +11557,10 @@ declare var SVGScriptElement: { interface SVGStopElement extends SVGElement { readonly offset: SVGAnimatedNumber; - addEventListener(type: K, listener: (this: SVGStopElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGStopElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGStopElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGStopElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGStopElement: { @@ -11588,10 +11589,10 @@ interface SVGStyleElement extends SVGElement { media: string; title: string; type: string; - addEventListener(type: K, listener: (this: SVGStyleElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGStyleElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGStyleElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGStyleElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGStyleElement: { @@ -11651,10 +11652,10 @@ interface SVGSVGElement extends SVGGraphicsElement, DocumentEvent, SVGFitToViewB unpauseAnimations(): void; unsuspendRedraw(suspendHandleID: number): void; unsuspendRedrawAll(): void; - addEventListener(type: K, listener: (this: SVGSVGElement, ev: SVGSVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGSVGElement, ev: SVGSVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGSVGElement, ev: SVGSVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGSVGElement, ev: SVGSVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGSVGElement: { @@ -11663,10 +11664,10 @@ declare var SVGSVGElement: { }; interface SVGSwitchElement extends SVGGraphicsElement { - addEventListener(type: K, listener: (this: SVGSwitchElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGSwitchElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGSwitchElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGSwitchElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGSwitchElement: { @@ -11675,10 +11676,10 @@ declare var SVGSwitchElement: { }; interface SVGSymbolElement extends SVGElement, SVGFitToViewBox { - addEventListener(type: K, listener: (this: SVGSymbolElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGSymbolElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGSymbolElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGSymbolElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGSymbolElement: { @@ -11701,10 +11702,10 @@ interface SVGTextContentElement extends SVGGraphicsElement { readonly LENGTHADJUST_SPACING: number; readonly LENGTHADJUST_SPACINGANDGLYPHS: number; readonly LENGTHADJUST_UNKNOWN: number; - addEventListener(type: K, listener: (this: SVGTextContentElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGTextContentElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGTextContentElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGTextContentElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGTextContentElement: { @@ -11716,10 +11717,10 @@ declare var SVGTextContentElement: { }; interface SVGTextElement extends SVGTextPositioningElement { - addEventListener(type: K, listener: (this: SVGTextElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGTextElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGTextElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGTextElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGTextElement: { @@ -11737,10 +11738,10 @@ interface SVGTextPathElement extends SVGTextContentElement, SVGURIReference { readonly TEXTPATH_SPACINGTYPE_AUTO: number; readonly TEXTPATH_SPACINGTYPE_EXACT: number; readonly TEXTPATH_SPACINGTYPE_UNKNOWN: number; - addEventListener(type: K, listener: (this: SVGTextPathElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGTextPathElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGTextPathElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGTextPathElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGTextPathElement: { @@ -11760,10 +11761,10 @@ interface SVGTextPositioningElement extends SVGTextContentElement { readonly rotate: SVGAnimatedNumberList; readonly x: SVGAnimatedLengthList; readonly y: SVGAnimatedLengthList; - addEventListener(type: K, listener: (this: SVGTextPositioningElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGTextPositioningElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGTextPositioningElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGTextPositioningElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGTextPositioningElement: { @@ -11772,10 +11773,10 @@ declare var SVGTextPositioningElement: { }; interface SVGTitleElement extends SVGElement { - addEventListener(type: K, listener: (this: SVGTitleElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGTitleElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGTitleElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGTitleElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGTitleElement: { @@ -11833,10 +11834,10 @@ declare var SVGTransformList: { }; interface SVGTSpanElement extends SVGTextPositioningElement { - addEventListener(type: K, listener: (this: SVGTSpanElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGTSpanElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGTSpanElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGTSpanElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGTSpanElement: { @@ -11858,10 +11859,10 @@ interface SVGUseElement extends SVGGraphicsElement, SVGURIReference { readonly width: SVGAnimatedLength; readonly x: SVGAnimatedLength; readonly y: SVGAnimatedLength; - addEventListener(type: K, listener: (this: SVGUseElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGUseElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGUseElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGUseElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGUseElement: { @@ -11871,10 +11872,10 @@ declare var SVGUseElement: { interface SVGViewElement extends SVGElement, SVGZoomAndPan, SVGFitToViewBox { readonly viewTarget: SVGStringList; - addEventListener(type: K, listener: (this: SVGViewElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: SVGViewElement, ev: SVGElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: SVGViewElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: SVGViewElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var SVGViewElement: { @@ -11994,10 +11995,10 @@ interface TextTrack extends EventTarget { readonly LOADING: number; readonly NONE: number; readonly SHOWING: number; - addEventListener(type: K, listener: (this: TextTrack, ev: TextTrackEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: TextTrack, ev: TextTrackEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: TextTrack, ev: TextTrackEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: TextTrack, ev: TextTrackEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var TextTrack: { @@ -12027,10 +12028,10 @@ interface TextTrackCue extends EventTarget { text: string; readonly track: TextTrack; getCueAsHTML(): DocumentFragment; - addEventListener(type: K, listener: (this: TextTrackCue, ev: TextTrackCueEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: TextTrackCue, ev: TextTrackCueEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: TextTrackCue, ev: TextTrackCueEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: TextTrackCue, ev: TextTrackCueEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var TextTrackCue: { @@ -12058,10 +12059,10 @@ interface TextTrackList extends EventTarget { readonly length: number; onaddtrack: ((this: TextTrackList, ev: TrackEvent) => any) | null; item(index: number): TextTrack; - addEventListener(type: K, listener: (this: TextTrackList, ev: TextTrackListEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: TextTrackList, ev: TextTrackListEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: TextTrackList, ev: TextTrackListEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: TextTrackList, ev: TextTrackListEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; [index: number]: TextTrack; } @@ -12269,10 +12270,10 @@ interface VideoTrackList extends EventTarget { readonly selectedIndex: number; getTrackById(id: string): VideoTrack | null; item(index: number): VideoTrack; - addEventListener(type: K, listener: (this: VideoTrackList, ev: VideoTrackListEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: VideoTrackList, ev: VideoTrackListEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: VideoTrackList, ev: VideoTrackListEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: VideoTrackList, ev: VideoTrackListEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; [index: number]: VideoTrack; } @@ -13290,10 +13291,10 @@ declare var WebKitPoint: { }; interface webkitRTCPeerConnection extends RTCPeerConnection { - addEventListener(type: K, listener: (this: webkitRTCPeerConnection, ev: RTCPeerConnectionEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: webkitRTCPeerConnection, ev: RTCPeerConnectionEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: webkitRTCPeerConnection, ev: RTCPeerConnectionEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: webkitRTCPeerConnection, ev: RTCPeerConnectionEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var webkitRTCPeerConnection: { @@ -13325,10 +13326,10 @@ interface WebSocket extends EventTarget { readonly CLOSING: number; readonly CONNECTING: number; readonly OPEN: number; - addEventListener(type: K, listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var WebSocket: { @@ -13640,10 +13641,10 @@ interface Window extends EventTarget, WindowTimers, WindowSessionStorage, Window scroll(options?: ScrollToOptions): void; scrollTo(options?: ScrollToOptions): void; scrollBy(options?: ScrollToOptions): void; - addEventListener(type: K, listener: (this: Window, ev: WindowEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: Window, ev: WindowEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: Window, ev: WindowEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: Window, ev: WindowEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var Window: { @@ -13659,10 +13660,10 @@ interface Worker extends EventTarget, AbstractWorker { onmessage: (this: Worker, ev: MessageEvent) => any; postMessage(message: any, transfer?: any[]): void; terminate(): void; - addEventListener(type: K, listener: (this: Worker, ev: WorkerEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: Worker, ev: WorkerEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: Worker, ev: WorkerEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: Worker, ev: WorkerEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var Worker: { @@ -13671,10 +13672,10 @@ declare var Worker: { }; interface XMLDocument extends Document { - addEventListener(type: K, listener: (this: XMLDocument, ev: DocumentEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: XMLDocument, ev: DocumentEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: XMLDocument, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: XMLDocument, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var XMLDocument: { @@ -13715,10 +13716,10 @@ interface XMLHttpRequest extends EventTarget, XMLHttpRequestEventTarget { readonly LOADING: number; readonly OPENED: number; readonly UNSENT: number; - addEventListener(type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var XMLHttpRequest: { @@ -13732,10 +13733,10 @@ declare var XMLHttpRequest: { }; interface XMLHttpRequestUpload extends EventTarget, XMLHttpRequestEventTarget { - addEventListener(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var XMLHttpRequestUpload: { @@ -13840,10 +13841,10 @@ interface AbstractWorkerEventMap { interface AbstractWorker { onerror: (this: AbstractWorker, ev: ErrorEvent) => any; - addEventListener(type: K, listener: (this: AbstractWorker, ev: AbstractWorkerEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: AbstractWorker, ev: AbstractWorkerEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: AbstractWorker, ev: AbstractWorkerEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: AbstractWorker, ev: AbstractWorkerEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } interface Body { @@ -13988,10 +13989,10 @@ interface GlobalEventHandlers { onpointerover: (this: GlobalEventHandlers, ev: PointerEvent) => any; onpointerup: (this: GlobalEventHandlers, ev: PointerEvent) => any; onwheel: (this: GlobalEventHandlers, ev: WheelEvent) => any; - addEventListener(type: K, listener: (this: GlobalEventHandlers, ev: GlobalEventHandlersEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: GlobalEventHandlers, ev: GlobalEventHandlersEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: GlobalEventHandlers, ev: GlobalEventHandlersEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: GlobalEventHandlers, ev: GlobalEventHandlersEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } interface GlobalFetch { @@ -14043,10 +14044,10 @@ interface MSBaseReader { readonly DONE: number; readonly EMPTY: number; readonly LOADING: number; - addEventListener(type: K, listener: (this: MSBaseReader, ev: MSBaseReaderEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: MSBaseReader, ev: MSBaseReaderEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: MSBaseReader, ev: MSBaseReaderEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: MSBaseReader, ev: MSBaseReaderEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } interface MSFileSaver { @@ -14192,10 +14193,10 @@ interface XMLHttpRequestEventTarget { onloadstart: (this: XMLHttpRequest, ev: Event) => any; onprogress: (this: XMLHttpRequest, ev: ProgressEvent) => any; ontimeout: (this: XMLHttpRequest, ev: ProgressEvent) => any; - addEventListener(type: K, listener: (this: XMLHttpRequestEventTarget, ev: XMLHttpRequestEventTargetEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: XMLHttpRequestEventTarget, ev: XMLHttpRequestEventTargetEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: XMLHttpRequestEventTarget, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: XMLHttpRequestEventTarget, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } interface BroadcastChannel extends EventTarget { @@ -14204,8 +14205,10 @@ interface BroadcastChannel extends EventTarget { onmessageerror: (ev: MessageEvent) => any; close(): void; postMessage(message: any): void; - addEventListener(type: K, listener: (this: BroadcastChannel, ev: BroadcastChannelEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: BroadcastChannel, ev: BroadcastChannelEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: BroadcastChannel, ev: BroadcastChannelEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var BroadcastChannel: { @@ -15085,10 +15088,10 @@ declare var indexedDB: IDBFactory; declare function atob(encodedString: string): string; declare function btoa(rawString: string): string; declare function fetch(input: RequestInfo, init?: RequestInit): Promise; -declare function addEventListener(type: K, listener: (this: Window, ev: WindowEventMap[K]) => any, useCapture?: boolean): void; -declare function addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; -declare function removeEventListener(type: K, listener: (this: Window, ev: WindowEventMap[K]) => any, useCapture?: boolean): void; -declare function removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; +declare function addEventListener(type: K, listener: (this: Window, ev: WindowEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; +declare function addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; +declare function removeEventListener(type: K, listener: (this: Window, ev: WindowEventMap[K]) => any, options?: boolean | EventListenerOptions): void; +declare function removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; type AAGUID = string; type AlgorithmIdentifier = string | Algorithm; type BodyInit = any; @@ -15112,7 +15115,6 @@ type GLsizeiptr = number; type GLubyte = number; type GLuint = number; type GLushort = number; -type HeadersInit = Headers | string[][]; type IDBKeyPath = string; type KeyFormat = string; type KeyType = string; @@ -15133,6 +15135,7 @@ type MouseWheelEvent = WheelEvent; type ScrollRestoration = "auto" | "manual"; type FormDataEntryValue = string | File; type InsertPosition = "beforebegin" | "afterbegin" | "beforeend" | "afterend"; +type HeadersInit = Headers | string[][] | { [key: string]: string }; type AppendMode = "segments" | "sequence"; type AudioContextState = "suspended" | "running" | "closed"; type BiquadFilterType = "lowpass" | "highpass" | "bandpass" | "lowshelf" | "highshelf" | "peaking" | "notch" | "allpass"; diff --git a/src/lib/dom.iterable.d.ts b/src/lib/dom.iterable.d.ts index e89a22f2c14..6ca728444f2 100644 --- a/src/lib/dom.iterable.d.ts +++ b/src/lib/dom.iterable.d.ts @@ -4,23 +4,6 @@ interface DOMTokenList { [Symbol.iterator](): IterableIterator; } -interface FormData { - /** - * Returns an array of key, value pairs for every entry in the list - */ - entries(): IterableIterator<[string, string | File]>; - /** - * Returns a list of keys in the list - */ - keys(): IterableIterator; - /** - * Returns a list of values in the list - */ - values(): IterableIterator; - - [Symbol.iterator](): IterableIterator; -} - interface Headers { [Symbol.iterator](): IterableIterator<[string, string]>; /** @@ -87,6 +70,31 @@ interface NodeListOf { [Symbol.iterator](): IterableIterator; } +interface HTMLCollectionBase { + [Symbol.iterator](): IterableIterator; +} + +interface HTMLCollectionOf { + [Symbol.iterator](): IterableIterator; +} + +interface FormData { + /** + * Returns an array of key, value pairs for every entry in the list + */ + entries(): IterableIterator<[string, string | File]>; + /** + * Returns a list of keys in the list + */ + keys(): IterableIterator; + /** + * Returns a list of values in the list + */ + values(): IterableIterator; + + [Symbol.iterator](): IterableIterator; +} + interface URLSearchParams { /** * Returns an array of key, value pairs for every entry in the search params diff --git a/src/lib/es2015.core.d.ts b/src/lib/es2015.core.d.ts index 9ea773e3eef..ccff68968f1 100644 --- a/src/lib/es2015.core.d.ts +++ b/src/lib/es2015.core.d.ts @@ -50,10 +50,16 @@ interface ArrayConstructor { /** * Creates an array from an array-like object. * @param arrayLike An array-like object to convert to an array. + */ + from(arrayLike: ArrayLike): T[]; + + /** + * Creates an array from an iterable object. + * @param arrayLike An array-like object to convert to an array. * @param mapfn A mapping function to call on every element of the array. * @param thisArg Value of 'this' used to invoke the mapfn. */ - from(arrayLike: ArrayLike, mapfn?: (v: T, k: number) => U, thisArg?: any): U[]; + from(arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; /** * Returns a new array from a set of elements. @@ -443,7 +449,7 @@ interface String { /** * Returns a String value that is made from count copies appended together. If count is 0, - * T is the empty String is returned. + * the empty string is returned. * @param count number of copies to append */ repeat(count: number): string; diff --git a/src/lib/es2015.iterable.d.ts b/src/lib/es2015.iterable.d.ts index 7b84c3e04c4..f3024bc334f 100644 --- a/src/lib/es2015.iterable.d.ts +++ b/src/lib/es2015.iterable.d.ts @@ -48,13 +48,19 @@ interface Array { } interface ArrayConstructor { + /** + * Creates an array from an iterable object. + * @param iterable An iterable object to convert to an array. + */ + from(iterable: Iterable): T[]; + /** * Creates an array from an iterable object. * @param iterable An iterable object to convert to an array. * @param mapfn A mapping function to call on every element of the array. * @param thisArg Value of 'this' used to invoke the mapfn. */ - from(iterable: Iterable, mapfn?: (v: T, k: number) => U, thisArg?: any): U[]; + from(iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } interface ReadonlyArray { diff --git a/src/lib/es2015.symbol.wellknown.d.ts b/src/lib/es2015.symbol.wellknown.d.ts index 268570ff232..23d836c6515 100644 --- a/src/lib/es2015.symbol.wellknown.d.ts +++ b/src/lib/es2015.symbol.wellknown.d.ts @@ -150,7 +150,7 @@ interface Promise { } interface PromiseConstructor { - readonly [Symbol.species]: Function; + readonly [Symbol.species]: PromiseConstructor; } interface RegExp { @@ -202,7 +202,7 @@ interface RegExp { } interface RegExpConstructor { - [Symbol.species](): RegExpConstructor; + readonly [Symbol.species]: RegExpConstructor; } interface String { @@ -283,3 +283,16 @@ interface Float32Array { interface Float64Array { readonly [Symbol.toStringTag]: "Float64Array"; } + +interface ArrayConstructor { + readonly [Symbol.species]: ArrayConstructor; +} +interface MapConstructor { + readonly [Symbol.species]: MapConstructor; +} +interface SetConstructor { + readonly [Symbol.species]: SetConstructor; +} +interface ArrayBufferConstructor { + readonly [Symbol.species]: ArrayBufferConstructor; +} \ No newline at end of file diff --git a/src/lib/es2017.d.ts b/src/lib/es2017.d.ts index 80282355a45..87aa273140b 100644 --- a/src/lib/es2017.d.ts +++ b/src/lib/es2017.d.ts @@ -3,3 +3,4 @@ /// /// /// +/// diff --git a/src/lib/es2017.typedarrays.d.ts b/src/lib/es2017.typedarrays.d.ts new file mode 100644 index 00000000000..a0b64135a30 --- /dev/null +++ b/src/lib/es2017.typedarrays.d.ts @@ -0,0 +1,35 @@ +interface Int8ArrayConstructor { + new (): Int8Array; +} + +interface Uint8ArrayConstructor { + new (): Uint8Array; +} + +interface Uint8ClampedArrayConstructor { + new (): Uint8ClampedArray; +} + +interface Int16ArrayConstructor { + new (): Int16Array; +} + +interface Uint16ArrayConstructor { + new (): Uint16Array; +} + +interface Int32ArrayConstructor { + new (): Int32Array; +} + +interface Uint32ArrayConstructor { + new (): Uint32Array; +} + +interface Float32ArrayConstructor { + new (): Float32Array; +} + +interface Float64ArrayConstructor { + new (): Float64Array; +} diff --git a/src/lib/webworker.generated.d.ts b/src/lib/webworker.generated.d.ts index 2651d1664ff..6eb17c33c5e 100644 --- a/src/lib/webworker.generated.d.ts +++ b/src/lib/webworker.generated.d.ts @@ -37,7 +37,7 @@ interface IDBIndexParameters { interface IDBObjectStoreParameters { autoIncrement?: boolean; - keyPath?: IDBKeyPath | null; + keyPath?: string | string[]; } interface KeyAlgorithm { @@ -74,7 +74,7 @@ interface RequestInit { body?: any; cache?: RequestCache; credentials?: RequestCredentials; - headers?: Headers | string[][]; + headers?: HeadersInit; integrity?: string; keepalive?: boolean; method?: string; @@ -86,7 +86,7 @@ interface RequestInit { } interface ResponseInit { - headers?: Headers | string[][]; + headers?: HeadersInit; status?: number; statusText?: string; } @@ -441,10 +441,10 @@ interface FileReader extends EventTarget, MSBaseReader { readAsBinaryString(blob: Blob): void; readAsDataURL(blob: Blob): void; readAsText(blob: Blob, encoding?: string): void; - addEventListener(type: K, listener: (this: FileReader, ev: MSBaseReaderEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: FileReader, ev: MSBaseReaderEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: FileReader, ev: MSBaseReaderEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: FileReader, ev: MSBaseReaderEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var FileReader: { @@ -472,7 +472,7 @@ interface Headers { declare var Headers: { prototype: Headers; - new(init?: Headers | string[][] | object): Headers; + new(init?: HeadersInit): Headers; }; interface IDBCursor { @@ -524,11 +524,12 @@ interface IDBDatabase extends EventTarget { createObjectStore(name: string, optionalParameters?: IDBObjectStoreParameters): IDBObjectStore; deleteObjectStore(name: string): void; transaction(storeNames: string | string[], mode?: IDBTransactionMode): IDBTransaction; - addEventListener(type: "versionchange", listener: (ev: IDBVersionChangeEvent) => any, useCapture?: boolean): void; - addEventListener(type: K, listener: (this: IDBDatabase, ev: IDBDatabaseEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: IDBDatabase, ev: IDBDatabaseEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: "versionchange", listener: (this: IDBDatabase, ev: IDBVersionChangeEvent) => any, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: "versionchange", listener: (this: IDBDatabase, ev: IDBVersionChangeEvent) => any, options?: boolean | EventListenerOptions): void; + addEventListener(type: K, listener: (this: IDBDatabase, ev: IDBDatabaseEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: IDBDatabase, ev: IDBDatabaseEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var IDBDatabase: { @@ -612,10 +613,10 @@ interface IDBOpenDBRequestEventMap extends IDBRequestEventMap { interface IDBOpenDBRequest extends IDBRequest { onblocked: (this: IDBOpenDBRequest, ev: Event) => any; onupgradeneeded: (this: IDBOpenDBRequest, ev: IDBVersionChangeEvent) => any; - addEventListener(type: K, listener: (this: IDBOpenDBRequest, ev: IDBOpenDBRequestEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: IDBOpenDBRequest, ev: IDBOpenDBRequestEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: IDBOpenDBRequest, ev: IDBOpenDBRequestEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: IDBOpenDBRequest, ev: IDBOpenDBRequestEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var IDBOpenDBRequest: { @@ -636,10 +637,10 @@ interface IDBRequest extends EventTarget { readonly result: any; source: IDBObjectStore | IDBIndex | IDBCursor; readonly transaction: IDBTransaction; - addEventListener(type: K, listener: (this: IDBRequest, ev: IDBRequestEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: IDBRequest, ev: IDBRequestEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: IDBRequest, ev: IDBRequestEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: IDBRequest, ev: IDBRequestEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var IDBRequest: { @@ -665,10 +666,10 @@ interface IDBTransaction extends EventTarget { readonly READ_ONLY: string; readonly READ_WRITE: string; readonly VERSION_CHANGE: string; - addEventListener(type: K, listener: (this: IDBTransaction, ev: IDBTransactionEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: IDBTransaction, ev: IDBTransactionEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: IDBTransaction, ev: IDBTransactionEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: IDBTransaction, ev: IDBTransactionEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var IDBTransaction: { @@ -733,10 +734,10 @@ interface MessagePort extends EventTarget { close(): void; postMessage(message?: any, transfer?: any[]): void; start(): void; - addEventListener(type: K, listener: (this: MessagePort, ev: MessagePortEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: MessagePort, ev: MessagePortEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: MessagePort, ev: MessagePortEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: MessagePort, ev: MessagePortEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var MessagePort: { @@ -764,10 +765,10 @@ interface Notification extends EventTarget { readonly tag: string; readonly title: string; close(): void; - addEventListener(type: K, listener: (this: Notification, ev: NotificationEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: Notification, ev: NotificationEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: Notification, ev: NotificationEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: Notification, ev: NotificationEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var Notification: { @@ -994,10 +995,10 @@ interface ServiceWorker extends EventTarget, AbstractWorker { readonly scriptURL: USVString; readonly state: ServiceWorkerState; postMessage(message: any, transfer?: any[]): void; - addEventListener(type: K, listener: (this: ServiceWorker, ev: ServiceWorkerEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: ServiceWorker, ev: ServiceWorkerEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: ServiceWorker, ev: ServiceWorkerEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: ServiceWorker, ev: ServiceWorkerEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var ServiceWorker: { @@ -1021,10 +1022,10 @@ interface ServiceWorkerRegistration extends EventTarget { showNotification(title: string, options?: NotificationOptions): Promise; unregister(): Promise; update(): Promise; - addEventListener(type: K, listener: (this: ServiceWorkerRegistration, ev: ServiceWorkerRegistrationEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: ServiceWorkerRegistration, ev: ServiceWorkerRegistrationEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: ServiceWorkerRegistration, ev: ServiceWorkerRegistrationEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: ServiceWorkerRegistration, ev: ServiceWorkerRegistrationEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var ServiceWorkerRegistration: { @@ -1089,10 +1090,10 @@ interface WebSocket extends EventTarget { readonly CLOSING: number; readonly CONNECTING: number; readonly OPEN: number; - addEventListener(type: K, listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var WebSocket: { @@ -1112,10 +1113,10 @@ interface Worker extends EventTarget, AbstractWorker { onmessage: (this: Worker, ev: MessageEvent) => any; postMessage(message: any, transfer?: any[]): void; terminate(): void; - addEventListener(type: K, listener: (this: Worker, ev: WorkerEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: Worker, ev: WorkerEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: Worker, ev: WorkerEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: Worker, ev: WorkerEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var Worker: { @@ -1155,10 +1156,10 @@ interface XMLHttpRequest extends EventTarget, XMLHttpRequestEventTarget { readonly LOADING: number; readonly OPENED: number; readonly UNSENT: number; - addEventListener(type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var XMLHttpRequest: { @@ -1172,10 +1173,10 @@ declare var XMLHttpRequest: { }; interface XMLHttpRequestUpload extends EventTarget, XMLHttpRequestEventTarget { - addEventListener(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var XMLHttpRequestUpload: { @@ -1189,10 +1190,10 @@ interface AbstractWorkerEventMap { interface AbstractWorker { onerror: (this: AbstractWorker, ev: ErrorEvent) => any; - addEventListener(type: K, listener: (this: AbstractWorker, ev: AbstractWorkerEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: AbstractWorker, ev: AbstractWorkerEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: AbstractWorker, ev: AbstractWorkerEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: AbstractWorker, ev: AbstractWorkerEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } interface Body { @@ -1229,10 +1230,10 @@ interface MSBaseReader { readonly DONE: number; readonly EMPTY: number; readonly LOADING: number; - addEventListener(type: K, listener: (this: MSBaseReader, ev: MSBaseReaderEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: MSBaseReader, ev: MSBaseReaderEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: MSBaseReader, ev: MSBaseReaderEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: MSBaseReader, ev: MSBaseReaderEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } interface NavigatorBeacon { @@ -1286,10 +1287,10 @@ interface XMLHttpRequestEventTarget { onloadstart: (this: XMLHttpRequest, ev: Event) => any; onprogress: (this: XMLHttpRequest, ev: ProgressEvent) => any; ontimeout: (this: XMLHttpRequest, ev: ProgressEvent) => any; - addEventListener(type: K, listener: (this: XMLHttpRequestEventTarget, ev: XMLHttpRequestEventTargetEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: XMLHttpRequestEventTarget, ev: XMLHttpRequestEventTargetEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: XMLHttpRequestEventTarget, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: XMLHttpRequestEventTarget, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } interface Client { @@ -1324,10 +1325,10 @@ interface DedicatedWorkerGlobalScope extends WorkerGlobalScope { onmessage: (this: DedicatedWorkerGlobalScope, ev: MessageEvent) => any; close(): void; postMessage(message: any, transfer?: any[]): void; - addEventListener(type: K, listener: (this: DedicatedWorkerGlobalScope, ev: DedicatedWorkerGlobalScopeEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: DedicatedWorkerGlobalScope, ev: DedicatedWorkerGlobalScopeEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: DedicatedWorkerGlobalScope, ev: DedicatedWorkerGlobalScopeEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: DedicatedWorkerGlobalScope, ev: DedicatedWorkerGlobalScopeEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var DedicatedWorkerGlobalScope: { @@ -1437,10 +1438,10 @@ interface ServiceWorkerGlobalScope extends WorkerGlobalScope { onsync: (this: ServiceWorkerGlobalScope, ev: SyncEvent) => any; readonly registration: ServiceWorkerRegistration; skipWaiting(): Promise; - addEventListener(type: K, listener: (this: ServiceWorkerGlobalScope, ev: ServiceWorkerGlobalScopeEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: ServiceWorkerGlobalScope, ev: ServiceWorkerGlobalScopeEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: ServiceWorkerGlobalScope, ev: ServiceWorkerGlobalScopeEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: ServiceWorkerGlobalScope, ev: ServiceWorkerGlobalScopeEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var ServiceWorkerGlobalScope: { @@ -1484,10 +1485,10 @@ interface WorkerGlobalScope extends EventTarget, WorkerUtils, WindowConsole, Glo msWriteProfilerMark(profilerMarkName: string): void; createImageBitmap(image: ImageBitmap | ImageData | Blob, options?: ImageBitmapOptions): Promise; createImageBitmap(image: ImageBitmap | ImageData | Blob, sx: number, sy: number, sw: number, sh: number, options?: ImageBitmapOptions): Promise; - addEventListener(type: K, listener: (this: WorkerGlobalScope, ev: WorkerGlobalScopeEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: WorkerGlobalScope, ev: WorkerGlobalScopeEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: WorkerGlobalScope, ev: WorkerGlobalScopeEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: WorkerGlobalScope, ev: WorkerGlobalScopeEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var WorkerGlobalScope: { @@ -1544,8 +1545,10 @@ interface BroadcastChannel extends EventTarget { onmessageerror: (ev: MessageEvent) => any; close(): void; postMessage(message: any): void; - addEventListener(type: K, listener: (this: BroadcastChannel, ev: BroadcastChannelEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + addEventListener(type: K, listener: (this: BroadcastChannel, ev: BroadcastChannelEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: BroadcastChannel, ev: BroadcastChannelEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } declare var BroadcastChannel: { @@ -1875,10 +1878,10 @@ declare function btoa(rawString: string): string; declare var console: Console; declare function fetch(input: RequestInfo, init?: RequestInit): Promise; declare function dispatchEvent(evt: Event): boolean; -declare function addEventListener(type: K, listener: (this: DedicatedWorkerGlobalScope, ev: DedicatedWorkerGlobalScopeEventMap[K]) => any, useCapture?: boolean): void; -declare function addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; -declare function removeEventListener(type: K, listener: (this: DedicatedWorkerGlobalScope, ev: DedicatedWorkerGlobalScopeEventMap[K]) => any, useCapture?: boolean): void; -declare function removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; +declare function addEventListener(type: K, listener: (this: DedicatedWorkerGlobalScope, ev: DedicatedWorkerGlobalScopeEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; +declare function addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; +declare function removeEventListener(type: K, listener: (this: DedicatedWorkerGlobalScope, ev: DedicatedWorkerGlobalScopeEventMap[K]) => any, options?: boolean | EventListenerOptions): void; +declare function removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; type AlgorithmIdentifier = string | Algorithm; type BodyInit = any; type IDBKeyPath = string; @@ -1887,6 +1890,7 @@ type USVString = string; type IDBValidKey = number | string | Date | IDBArrayKey; type BufferSource = ArrayBuffer | ArrayBufferView; type FormDataEntryValue = string | File; +type HeadersInit = Headers | string[][] | { [key: string]: string }; type IDBCursorDirection = "next" | "nextunique" | "prev" | "prevunique"; type IDBRequestReadyState = "pending" | "done"; type IDBTransactionMode = "readonly" | "readwrite" | "versionchange"; diff --git a/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl index 94bbc474495..c59e9c20060 100644 --- a/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2241,6 +2241,15 @@ + + + + + + + + + @@ -2970,6 +2979,15 @@ + + + + + + + + + @@ -4212,6 +4230,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl index 3ea6148617a..929b7edf058 100644 --- a/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2241,6 +2241,15 @@ + + + + + + + + + @@ -2970,6 +2979,15 @@ + + + + + + + + + @@ -4212,6 +4230,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl index 078b17179a4..8dab90a1ba2 100644 --- a/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2250,6 +2250,15 @@ + + + + + + + + + @@ -2979,6 +2988,15 @@ + + + + + + + + + @@ -4221,6 +4239,24 @@ + + + + + + + + + + + + + + + + + + @@ -8320,7 +8356,7 @@ - + diff --git a/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl index d10f7077dc5..c00e5a2a2e7 100644 --- a/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -827,10 +827,13 @@ - + - + + + + @@ -2229,6 +2232,15 @@ + + + + + + + + + @@ -2886,6 +2898,15 @@ + + + + + + + + + @@ -2913,6 +2934,15 @@ + + + + + + + + + @@ -2940,6 +2970,15 @@ + + + + + + + + + @@ -3163,7 +3202,7 @@ - + @@ -3172,7 +3211,7 @@ - + @@ -3181,7 +3220,7 @@ - + @@ -3665,10 +3704,13 @@ - + - + + + + @@ -4176,6 +4218,24 @@ + + + + + + + + + + + + + + + + + + @@ -6339,11 +6399,11 @@ - + - + - + diff --git a/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl index 06f8e9220bc..4865cf6c508 100644 --- a/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -839,12 +839,12 @@ - + - + - + @@ -2250,6 +2250,15 @@ + + + + + + + + + @@ -2907,6 +2916,15 @@ + + + + + + + + + @@ -2934,6 +2952,15 @@ + + + + + + + + + @@ -2961,6 +2988,15 @@ + + + + + + + + + @@ -3689,12 +3725,12 @@ - + - + - + @@ -4203,6 +4239,24 @@ + + + + + + + + + + + + + + + + + + @@ -6375,11 +6429,11 @@ - + - + - + diff --git a/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl index c23ea7cc378..2bf61430d60 100644 --- a/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -839,12 +839,12 @@ - + - + - + @@ -2250,6 +2250,15 @@ + + + + + + + + + @@ -2907,6 +2916,15 @@ + + + + + + + + + @@ -2934,6 +2952,15 @@ + + + + + + + + + @@ -2961,6 +2988,15 @@ + + + + + + + + + @@ -3689,12 +3725,12 @@ - + - + - + @@ -4203,6 +4239,24 @@ + + + + + + + + + + + + + + + + + + @@ -6375,11 +6429,11 @@ - + - + - + diff --git a/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl index 83a8d7cace7..31f3bfdefd5 100644 --- a/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2241,6 +2241,15 @@ + + + + + + + + + @@ -2970,6 +2979,15 @@ + + + + + + + + + @@ -4212,6 +4230,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl index 34a98237a2a..b2ae023f5a4 100644 --- a/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2241,6 +2241,15 @@ + + + + + + + + + @@ -2970,6 +2979,15 @@ + + + + + + + + + @@ -4212,6 +4230,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl index 2653d211440..2693d7cce27 100644 --- a/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2241,6 +2241,15 @@ + + + + + + + + + @@ -2970,6 +2979,15 @@ + + + + + + + + + @@ -4212,6 +4230,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl index 3b132575e58..b9d115872b6 100644 --- a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2225,6 +2225,15 @@ + + + + + + + + + @@ -2954,6 +2963,15 @@ + + + + + + + + + @@ -4193,6 +4211,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl index 014ca9ef8f6..1e480ff2a08 100644 --- a/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -820,10 +820,13 @@ - + - + + + + @@ -2222,6 +2225,15 @@ + + + + + + + + + @@ -2879,6 +2891,15 @@ + + + + + + + + + @@ -2906,6 +2927,15 @@ + + + + + + + + + @@ -2933,6 +2963,15 @@ + + + + + + + + + @@ -3658,10 +3697,13 @@ - + - + + + + @@ -4169,6 +4211,24 @@ + + + + + + + + + + + + + + + + + + @@ -6332,11 +6392,11 @@ - + - + - + diff --git a/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl index 7c2b517078c..bd78324f196 100644 --- a/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -829,12 +829,12 @@ - + - + - + @@ -2240,6 +2240,15 @@ + + + + + + + + + @@ -2897,6 +2906,15 @@ + + + + + + + + + @@ -2924,6 +2942,15 @@ + + + + + + + + + @@ -2951,6 +2978,15 @@ + + + + + + + + + @@ -3679,16 +3715,28 @@ - + - + - + + + + + + + + + + + + + @@ -3920,6 +3968,12 @@ + + + + + + @@ -4193,6 +4247,24 @@ + + + + + + + + + + + + + + + + + + @@ -6365,11 +6437,11 @@ - + - + - + diff --git a/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl index a30e3d898dc..0eafa4da0b2 100644 --- a/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -823,12 +823,12 @@ - + - + - + @@ -2234,6 +2234,15 @@ + + + + + + + + + @@ -2891,6 +2900,15 @@ + + + + + + + + + @@ -2918,6 +2936,15 @@ + + + + + + + + + @@ -2945,6 +2972,15 @@ + + + + + + + + + @@ -3673,12 +3709,12 @@ - + - + - + @@ -4187,6 +4223,24 @@ + + + + + + + + + + + + + + + + + + @@ -6359,11 +6413,11 @@ - + - + - + diff --git a/src/server/client.ts b/src/server/client.ts index 2781d7cf20a..8286119e828 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -170,8 +170,8 @@ namespace ts.server { }; } - getCompletionsAtPosition(fileName: string, position: number): CompletionInfo { - const args: protocol.CompletionsRequestArgs = this.createFileLocationRequestArgs(fileName, position); + getCompletionsAtPosition(fileName: string, position: number, options: GetCompletionsAtPositionOptions | undefined): CompletionInfo { + const args: protocol.CompletionsRequestArgs = { ...this.createFileLocationRequestArgs(fileName, position), ...options }; const request = this.processRequest(CommandNames.Completions, args); const response = this.processResponse(request); @@ -192,8 +192,8 @@ namespace ts.server { }; } - getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails { - const args: protocol.CompletionDetailsRequestArgs = { ...this.createFileLocationRequestArgs(fileName, position), entryNames: [entryName] }; + getCompletionEntryDetails(fileName: string, position: number, entryName: string, _options: FormatCodeOptions | FormatCodeSettings | undefined, source: string | undefined): CompletionEntryDetails { + const args: protocol.CompletionDetailsRequestArgs = { ...this.createFileLocationRequestArgs(fileName, position), entryNames: [{ name: entryName, source }] }; const request = this.processRequest(CommandNames.CompletionDetails, args); const response = this.processResponse(request); @@ -270,6 +270,25 @@ 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 response = this.processResponse(request); + + return { + definitions: response.body.definitions.map(entry => ({ + containerKind: ScriptElementKind.unknown, + containerName: "", + fileName: entry.file, + textSpan: this.decodeSpan(entry), + kind: ScriptElementKind.unknown, + name: "" + })), + textSpan: this.decodeSpan(response.body.textSpan, request.arguments.file) + }; + } + getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] { const args: protocol.FileLocationRequestArgs = this.createFileLocationRequestArgs(fileName, position); @@ -324,7 +343,7 @@ namespace ts.server { } getSyntacticDiagnostics(file: string): Diagnostic[] { - const args: protocol.SyntacticDiagnosticsSyncRequestArgs = { file, includeLinePosition: true }; + const args: protocol.SyntacticDiagnosticsSyncRequestArgs = { file, includeLinePosition: true }; const request = this.processRequest(CommandNames.SyntacticDiagnosticsSync, args); const response = this.processResponse(request); diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 0bd02f32d95..726621a540d 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -9,10 +9,12 @@ namespace ts.server { export const maxProgramSizeForNonTsFiles = 20 * 1024 * 1024; + // tslint:disable variable-name export const ProjectsUpdatedInBackgroundEvent = "projectsUpdatedInBackground"; export const ConfigFileDiagEvent = "configFileDiag"; export const ProjectLanguageServiceStateEvent = "projectLanguageServiceState"; export const ProjectInfoTelemetryEvent = "projectInfo"; + // tslint:enable variable-name export interface ProjectsUpdatedInBackgroundEvent { eventName: typeof ProjectsUpdatedInBackgroundEvent; @@ -78,9 +80,7 @@ namespace ts.server { export type ProjectServiceEvent = ProjectsUpdatedInBackgroundEvent | ConfigFileDiagEvent | ProjectLanguageServiceStateEvent | ProjectInfoTelemetryEvent; - export interface ProjectServiceEventHandler { - (event: ProjectServiceEvent): void; - } + export type ProjectServiceEventHandler = (event: ProjectServiceEvent) => void; export interface SafeList { [name: string]: { match: RegExp, exclude?: (string | number)[][], types?: string[] }; @@ -103,9 +103,9 @@ namespace ts.server { const compilerOptionConverters = prepareConvertersForEnumLikeCompilerOptions(optionDeclarations); const indentStyle = createMapFromTemplate({ - "none": IndentStyle.None, - "block": IndentStyle.Block, - "smart": IndentStyle.Smart + none: IndentStyle.None, + block: IndentStyle.Block, + smart: IndentStyle.Smart }); export interface TypesMapFile { @@ -134,31 +134,31 @@ namespace ts.server { const defaultTypeSafeList: SafeList = { "jquery": { // jquery files can have names like "jquery-1.10.2.min.js" (or "jquery.intellisense.js") - "match": /jquery(-(\.?\d+)+)?(\.intellisense)?(\.min)?\.js$/i, - "types": ["jquery"] + match: /jquery(-(\.?\d+)+)?(\.intellisense)?(\.min)?\.js$/i, + types: ["jquery"] }, "WinJS": { // e.g. c:/temp/UWApp1/lib/winjs-4.0.1/js/base.js - "match": /^(.*\/winjs-[.\d]+)\/js\/base\.js$/i, // If the winjs/base.js file is found.. - "exclude": [["^", 1, "/.*"]], // ..then exclude all files under the winjs folder - "types": ["winjs"] // And fetch the @types package for WinJS + match: /^(.*\/winjs-[.\d]+)\/js\/base\.js$/i, // If the winjs/base.js file is found.. + exclude: [["^", 1, "/.*"]], // ..then exclude all files under the winjs folder + types: ["winjs"] // And fetch the @types package for WinJS }, "Kendo": { // e.g. /Kendo3/wwwroot/lib/kendo/kendo.all.min.js - "match": /^(.*\/kendo)\/kendo\.all\.min\.js$/i, - "exclude": [["^", 1, "/.*"]], - "types": ["kendo-ui"] + match: /^(.*\/kendo)\/kendo\.all\.min\.js$/i, + exclude: [["^", 1, "/.*"]], + types: ["kendo-ui"] }, "Office Nuget": { // e.g. /scripts/Office/1/excel-15.debug.js - "match": /^(.*\/office\/1)\/excel-\d+\.debug\.js$/i, // Office NuGet package is installed under a "1/office" folder - "exclude": [["^", 1, "/.*"]], // Exclude that whole folder if the file indicated above is found in it - "types": ["office"] // @types package to fetch instead + match: /^(.*\/office\/1)\/excel-\d+\.debug\.js$/i, // Office NuGet package is installed under a "1/office" folder + exclude: [["^", 1, "/.*"]], // Exclude that whole folder if the file indicated above is found in it + types: ["office"] // @types package to fetch instead }, "Minified files": { // e.g. /whatever/blah.min.js - "match": /^(.+\.min\.js)$/i, - "exclude": [["^", 1, "$"]] + match: /^(.+\.min\.js)$/i, + exclude: [["^", 1, "$"]] } }; @@ -203,8 +203,10 @@ namespace ts.server { * This helper function processes a list of projects and return the concatenated, sortd and deduplicated output of processing each project. */ export function combineProjectOutput(projects: ReadonlyArray, action: (project: Project) => ReadonlyArray, comparer?: (a: T, b: T) => number, areEqual?: (a: T, b: T) => boolean) { - const result = flatMap(projects, action).sort(comparer); - return projects.length > 1 ? deduplicate(result, areEqual) : result; + const outputs = flatMap(projects, action); + return comparer + ? sortAndDeduplicate(outputs, comparer, areEqual) + : deduplicate(outputs, areEqual); } export interface HostConfiguration { @@ -355,6 +357,10 @@ namespace ts.server { * Open files: with value being project root path, and key being Path of the file that is open */ readonly openFiles = createMap(); + /** + * Map of open files that are opened without complete path but have projectRoot as current directory + */ + private readonly openFilesWithNonRootedDiskPath = createMap(); private compilerOptionsForInferredProjects: CompilerOptions; private compilerOptionsForInferredProjectsPerProjectRoot = createMap(); @@ -801,17 +807,14 @@ namespace ts.server { // 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 (fileOrDirectoryPath !== directory && !isSupportedSourceFileName(fileOrDirectory, project.getCompilationSettings(), this.hostConfiguration.extraFileExtensions)) { + if (fileOrDirectoryPath !== directory && hasExtension(fileOrDirectoryPath) && !isSupportedSourceFileName(fileOrDirectory, project.getCompilationSettings(), this.hostConfiguration.extraFileExtensions)) { this.logger.info(`Project: ${configFilename} Detected file add/remove of non supported extension: ${fileOrDirectory}`); return; } // Reload is pending, do the reload - if (!project.pendingReload) { - const configFileSpecs = project.configFileSpecs; - const result = getFileNamesFromConfigSpecs(configFileSpecs, getDirectoryPath(configFilename), project.getCompilationSettings(), project.getCachedDirectoryStructureHost(), this.hostConfiguration.extraFileExtensions); - project.updateErrorOnNoInputFiles(result.fileNames.length !== 0); - this.updateNonInferredProjectFiles(project, result.fileNames, fileNamePropertyReader); + if (project.pendingReload !== ConfigFileProgramReloadLevel.Full) { + project.pendingReload = ConfigFileProgramReloadLevel.Partial; this.delayUpdateProjectGraphAndInferredProjectsRefresh(project); } }, @@ -844,7 +847,7 @@ namespace ts.server { } else { this.logConfigFileWatchUpdate(project.getConfigFilePath(), project.canonicalConfigFilePath, configFileExistenceInfo, ConfigFileWatcherStatus.ReloadingInferredRootFiles); - project.pendingReload = true; + project.pendingReload = ConfigFileProgramReloadLevel.Full; this.delayUpdateProjectGraph(project); // As we scheduled the update on configured project graph, // we would need to schedule the project reload for only the root of inferred projects @@ -938,12 +941,16 @@ namespace ts.server { // Closing file should trigger re-reading the file content from disk. This is // because the user may chose to discard the buffer content before saving // to the disk, and the server's version of the file can be out of sync. - info.close(); + const fileExists = this.host.fileExists(info.fileName); + info.close(fileExists); this.stopWatchingConfigFilesForClosedScriptInfo(info); this.openFiles.delete(info.path); + const canonicalFileName = this.toCanonicalFileName(info.fileName); + if (this.openFilesWithNonRootedDiskPath.get(canonicalFileName) === info) { + this.openFilesWithNonRootedDiskPath.delete(canonicalFileName); + } - const fileExists = this.host.fileExists(info.fileName); // collect all projects that should be removed let projectsToRemove: Project[]; @@ -1069,7 +1076,7 @@ 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 forEachEntry(configFileExistenceInfo.openFilesImpactedByConfigFile, (isRootOfInferredProject, __key) => isRootOfInferredProject); + return forEachEntry(configFileExistenceInfo.openFilesImpactedByConfigFile, (isRootOfInferredProject) => isRootOfInferredProject); } private setConfigFileExistenceInfoByClosedConfiguredProject(closedProject: ConfiguredProject) { @@ -1379,24 +1386,42 @@ namespace ts.server { this.projectToSizeMap.forEach(val => (availableSpace -= (val || 0))); let totalNonTsFileSize = 0; + for (const f of fileNames) { const fileName = propertyReader.getFileName(f); if (hasTypeScriptFileExtension(fileName)) { continue; } + totalNonTsFileSize += this.host.getFileSize(fileName); + if (totalNonTsFileSize > maxProgramSizeForNonTsFiles) { + this.logger.info(getExceedLimitMessage({ propertyReader, hasTypeScriptFileExtension, host: this.host }, totalNonTsFileSize)); // Keep the size as zero since it's disabled return true; } } if (totalNonTsFileSize > availableSpace) { + this.logger.info(getExceedLimitMessage({ propertyReader, hasTypeScriptFileExtension, host: this.host }, totalNonTsFileSize)); return true; } this.projectToSizeMap.set(name, totalNonTsFileSize); return false; + + function getExceedLimitMessage(context: { propertyReader: FilePropertyReader, hasTypeScriptFileExtension: (filename: string) => boolean, host: ServerHost }, totalNonTsFileSize: number) { + const files = getTop5LargestFiles(context); + + return `Non TS file size exceeded limit (${totalNonTsFileSize}). Largest files: ${files.map(file => `${file.name}:${file.size}`).join(", ")}`; + } + function getTop5LargestFiles({ propertyReader, hasTypeScriptFileExtension, host }: { propertyReader: FilePropertyReader, hasTypeScriptFileExtension: (filename: string) => boolean, host: ServerHost }) { + return fileNames.map(f => propertyReader.getFileName(f)) + .filter(name => hasTypeScriptFileExtension(name)) + .map(name => ({ name, size: host.getFileSize(name) })) + .sort((a, b) => b.size - a.size) + .slice(0, 5); + } } private createExternalProject(projectFileName: string, files: protocol.ExternalFile[], options: protocol.ExternalProjectCompilerOptions, typeAcquisition: TypeAcquisition, excludedFiles: NormalizedPath[]) { @@ -1526,7 +1551,7 @@ namespace ts.server { else { const scriptKind = propertyReader.getScriptKind(f, this.hostConfiguration.extraFileExtensions); const hasMixedContent = propertyReader.hasMixedContent(f, this.hostConfiguration.extraFileExtensions); - scriptInfo = this.getOrCreateScriptInfoNotOpenedByClientForNormalizedPath(normalizedPath, scriptKind, hasMixedContent, project.directoryStructureHost); + scriptInfo = this.getOrCreateScriptInfoNotOpenedByClientForNormalizedPath(normalizedPath, project.currentDirectory, scriptKind, hasMixedContent, project.directoryStructureHost); path = scriptInfo.path; // If this script info is not already a root add it if (!project.isRoot(scriptInfo)) { @@ -1571,6 +1596,19 @@ namespace ts.server { this.addFilesToNonInferredProjectAndUpdateGraph(project, newUncheckedFiles, propertyReader, newTypeAcquisition); } + /** + * Reload the file names from config file specs and update the project graph + */ + /*@internal*/ + reloadFileNamesOfConfiguredProject(project: ConfiguredProject): boolean { + const configFileSpecs = project.configFileSpecs; + const configFileName = project.getConfigFilePath(); + const fileNamesResult = getFileNamesFromConfigSpecs(configFileSpecs, getDirectoryPath(configFileName), project.getCompilationSettings(), project.getCachedDirectoryStructureHost(), this.hostConfiguration.extraFileExtensions); + project.updateErrorOnNoInputFiles(fileNamesResult.fileNames.length !== 0); + this.updateNonInferredProjectFiles(project, fileNamesResult.fileNames, fileNamePropertyReader); + return project.updateGraph(); + } + /** * Read the config file of the project again and update the project */ @@ -1680,9 +1718,9 @@ namespace ts.server { } /*@internal*/ - getOrCreateScriptInfoNotOpenedByClient(uncheckedFileName: string, hostToQueryFileExistsOn: DirectoryStructureHost) { + getOrCreateScriptInfoNotOpenedByClient(uncheckedFileName: string, currentDirectory: string, hostToQueryFileExistsOn: DirectoryStructureHost) { return this.getOrCreateScriptInfoNotOpenedByClientForNormalizedPath( - toNormalizedPath(uncheckedFileName), /*scriptKind*/ undefined, + toNormalizedPath(uncheckedFileName), currentDirectory, /*scriptKind*/ undefined, /*hasMixedContent*/ undefined, hostToQueryFileExistsOn ); } @@ -1713,20 +1751,26 @@ namespace ts.server { } /*@internal*/ - getOrCreateScriptInfoNotOpenedByClientForNormalizedPath(fileName: NormalizedPath, scriptKind?: ScriptKind, hasMixedContent?: boolean, hostToQueryFileExistsOn?: DirectoryStructureHost) { - return this.getOrCreateScriptInfoForNormalizedPath(fileName, /*openedByClient*/ false, /*fileContent*/ undefined, scriptKind, hasMixedContent, hostToQueryFileExistsOn); + getOrCreateScriptInfoNotOpenedByClientForNormalizedPath(fileName: NormalizedPath, currentDirectory: string, scriptKind: ScriptKind | undefined, hasMixedContent: boolean | undefined, hostToQueryFileExistsOn: DirectoryStructureHost | undefined) { + return this.getOrCreateScriptInfoWorker(fileName, currentDirectory, /*openedByClient*/ false, /*fileContent*/ undefined, scriptKind, hasMixedContent, hostToQueryFileExistsOn); } /*@internal*/ - getOrCreateScriptInfoOpenedByClientForNormalizedPath(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, hostToQueryFileExistsOn?: DirectoryStructureHost) { - return this.getOrCreateScriptInfoForNormalizedPath(fileName, /*openedByClient*/ true, fileContent, scriptKind, hasMixedContent, hostToQueryFileExistsOn); + 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?: DirectoryStructureHost) { + 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?: DirectoryStructureHost) { 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, this.currentDirectory, this.toCanonicalFileName); + const path = normalizedPathToPath(fileName, currentDirectory, this.toCanonicalFileName); let info = this.getScriptInfoForPath(path); if (!info) { + Debug.assert(isRootedDiskPath(fileName) || openedByClient, "Script info with relative file name can only be open script info"); + Debug.assert(!isRootedDiskPath(fileName) || this.currentDirectory === currentDirectory || !this.openFilesWithNonRootedDiskPath.has(this.toCanonicalFileName(fileName)), "Open script files with non rooted disk path opened with current directory context cannot have same canonical names"); const isDynamic = isDynamicFileName(fileName); // 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)) { @@ -1737,6 +1781,10 @@ namespace ts.server { if (!openedByClient) { this.watchClosedScriptInfo(info); } + else if (!isRootedDiskPath(fileName) && currentDirectory !== this.currentDirectory) { + // File that is opened by user but isn't rooted disk path + this.openFilesWithNonRootedDiskPath.set(this.toCanonicalFileName(fileName), info); + } } if (openedByClient && !info.isScriptOpen()) { // Opening closed script info @@ -1753,8 +1801,12 @@ namespace ts.server { return info; } + /** + * 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 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) { @@ -1851,7 +1903,7 @@ namespace ts.server { } else if (!updatedProjects.has(configFileName)) { if (delayReload) { - project.pendingReload = true; + project.pendingReload = ConfigFileProgramReloadLevel.Full; this.delayUpdateProjectGraph(project); } else { @@ -1939,7 +1991,7 @@ namespace ts.server { let sendConfigFileDiagEvent = false; let configFileErrors: ReadonlyArray; - const info = this.getOrCreateScriptInfoOpenedByClientForNormalizedPath(fileName, fileContent, scriptKind, hasMixedContent); + const info = this.getOrCreateScriptInfoOpenedByClientForNormalizedPath(fileName, projectRootPath ? this.getNormalizedAbsolutePath(projectRootPath) : this.currentDirectory, fileContent, scriptKind, hasMixedContent); let project: ConfiguredProject | ExternalProject = this.findContainingExternalProject(fileName); if (!project) { configFileName = this.getConfigFileNameForFile(info, projectRootPath); diff --git a/src/server/project.ts b/src/server/project.ts index 0e1e7ac2cab..d2526ab2abb 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -98,9 +98,7 @@ namespace ts.server { getExternalFiles?(proj: Project): string[]; } - export interface PluginModuleFactory { - (mod: { typescript: typeof ts }): PluginModule; - } + export type PluginModuleFactory = (mod: { typescript: typeof ts }) => PluginModule; /** * The project root can be script info - if root is present, @@ -287,7 +285,7 @@ namespace ts.server { } private getOrCreateScriptInfoAndAttachToProject(fileName: string) { - const scriptInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient(fileName, this.directoryStructureHost); + const scriptInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient(fileName, this.currentDirectory, this.directoryStructureHost); if (scriptInfo) { const existingValue = this.rootFilesMap.get(scriptInfo.path); if (existingValue !== scriptInfo && existingValue !== undefined) { @@ -367,7 +365,7 @@ namespace ts.server { /*@internal*/ toPath(fileName: string) { - return this.projectService.toPath(fileName); + return toPath(fileName, this.currentDirectory, this.projectService.toCanonicalFileName); } /*@internal*/ @@ -660,7 +658,7 @@ namespace ts.server { } containsFile(filename: NormalizedPath, requireOpen?: boolean) { - const info = this.projectService.getScriptInfoForNormalizedPath(filename); + const info = this.projectService.getScriptInfoForPath(this.toPath(filename)); if (info && (info.isScriptOpen() || !requireOpen)) { return this.containsScriptInfo(info); } @@ -857,10 +855,11 @@ namespace ts.server { // by the LSHost 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.directoryStructureHost); + const scriptInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient(inserted, this.currentDirectory, this.directoryStructureHost); scriptInfo.attachToProject(this); }, - removed => this.detachScriptInfoFromProject(removed) + removed => this.detachScriptInfoFromProject(removed), + compareStringsCaseSensitive ); const elapsed = timestamp() - start; this.writeLog(`Finishing updateGraphWorker: Project: ${this.getProjectName()} structureChanged: ${hasChanges} Elapsed: ${elapsed}ms`); @@ -903,7 +902,7 @@ namespace ts.server { } getScriptInfoForNormalizedPath(fileName: NormalizedPath) { - const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(fileName); + const scriptInfo = this.projectService.getScriptInfoForPath(this.toPath(fileName)); if (scriptInfo && !scriptInfo.isAttached(this)) { return Errors.ThrowProjectDoesNotContainDocument(fileName, this); } @@ -1123,7 +1122,7 @@ namespace ts.server { readonly canonicalConfigFilePath: NormalizedPath; /* @internal */ - pendingReload: boolean; + pendingReload: ConfigFileProgramReloadLevel; /*@internal*/ configFileSpecs: ConfigFileSpecs; @@ -1163,12 +1162,17 @@ namespace ts.server { * @returns: true if set of files in the project stays the same and false - otherwise. */ updateGraph(): boolean { - if (this.pendingReload) { - this.pendingReload = false; - this.projectService.reloadConfiguredProject(this); - return true; + const reloadLevel = this.pendingReload; + this.pendingReload = ConfigFileProgramReloadLevel.None; + switch (reloadLevel) { + case ConfigFileProgramReloadLevel.Partial: + return this.projectService.reloadFileNamesOfConfiguredProject(this); + case ConfigFileProgramReloadLevel.Full: + this.projectService.reloadConfiguredProject(this); + return true; + default: + return super.updateGraph(); } - return super.updateGraph(); } /*@internal*/ diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 6092f235942..f44efa0db21 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -15,12 +15,17 @@ namespace ts.server.protocol { /* @internal */ CompletionsFull = "completions-full", CompletionDetails = "completionEntryDetails", + /* @internal */ + CompletionDetailsFull = "completionEntryDetails-full", CompileOnSaveAffectedFileList = "compileOnSaveAffectedFileList", CompileOnSaveEmitFile = "compileOnSaveEmitFile", Configure = "configure", Definition = "definition", /* @internal */ DefinitionFull = "definition-full", + DefinitionAndBoundSpan = "definitionAndBoundSpan", + /* @internal */ + DefinitionAndBoundSpanFull = "definitionAndBoundSpan-full", Implementation = "implementation", /* @internal */ ImplementationFull = "implementation-full", @@ -708,6 +713,11 @@ namespace ts.server.protocol { file: string; } + export interface DefinitionInfoAndBoundSpan { + definitions: ReadonlyArray; + textSpan: TextSpan; + } + /** * Definition response message. Gives text range for definition. */ @@ -715,6 +725,10 @@ namespace ts.server.protocol { body?: FileSpan[]; } + export interface DefinitionInfoAndBoundSpanReponse extends Response { + body?: DefinitionInfoAndBoundSpan; + } + /** * Definition response message. Gives text range for definition. */ @@ -1605,6 +1619,11 @@ namespace ts.server.protocol { * Optional prefix to apply to possible completions. */ prefix?: string; + /** + * If enabled, TypeScript will search through all external modules' exports and add them to the completions list. + * This affects lone identifier completions but not completions on the right hand side of `obj.`. + */ + includeExternalModuleExports: boolean; } /** diff --git a/src/server/scriptInfo.ts b/src/server/scriptInfo.ts index 9f029c00f0a..f800a1117d0 100644 --- a/src/server/scriptInfo.ts +++ b/src/server/scriptInfo.ts @@ -248,9 +248,9 @@ namespace ts.server { } } - public close() { + public close(fileExists = true) { this.textStorage.isOpen = false; - if (this.isDynamicOrHasMixedContent()) { + if (this.isDynamicOrHasMixedContent() || !fileExists) { if (this.textStorage.reload("")) { this.markContainingProjectsAsDirty(); } diff --git a/src/server/scriptVersionCache.ts b/src/server/scriptVersionCache.ts index 7c25e4cc3cb..fe71040b4f6 100644 --- a/src/server/scriptVersionCache.ts +++ b/src/server/scriptVersionCache.ts @@ -10,7 +10,7 @@ namespace ts.server { charCount(): number; lineCount(): number; isLeaf(): this is LineLeaf; - walk(rangeStart: number, rangeLength: number, walkFns: ILineIndexWalker): void; + walk(rangeStart: number, rangeLength: number, walkFns: LineIndexWalker): void; } export interface AbsolutePositionAndLineText { @@ -27,7 +27,7 @@ namespace ts.server { PostEnd } - interface ILineIndexWalker { + interface LineIndexWalker { goSubtree: boolean; done: boolean; leaf(relativeStart: number, relativeLength: number, lineCollection: LineLeaf): void; @@ -37,7 +37,7 @@ namespace ts.server { parent: LineNode, nodeType: CharRangeSection): void; } - class EditWalker implements ILineIndexWalker { + class EditWalker implements LineIndexWalker { goSubtree = true; get done() { return false; } @@ -429,7 +429,7 @@ namespace ts.server { } } - walk(rangeStart: number, rangeLength: number, walkFns: ILineIndexWalker) { + walk(rangeStart: number, rangeLength: number, walkFns: LineIndexWalker) { this.root.walk(rangeStart, rangeLength, walkFns); } @@ -458,7 +458,7 @@ namespace ts.server { const walkFns = { goSubtree: true, done: false, - leaf(this: ILineIndexWalker, relativeStart: number, relativeLength: number, ll: LineLeaf) { + leaf(this: LineIndexWalker, relativeStart: number, relativeLength: number, ll: LineLeaf) { if (!f(ll, relativeStart, relativeLength)) { this.done = true; } @@ -580,7 +580,7 @@ namespace ts.server { } } - private execWalk(rangeStart: number, rangeLength: number, walkFns: ILineIndexWalker, 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); } @@ -596,14 +596,14 @@ namespace ts.server { return walkFns.done; } - private skipChild(relativeStart: number, relativeLength: number, childIndex: number, walkFns: ILineIndexWalker, 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; } } - walk(rangeStart: number, rangeLength: number, walkFns: ILineIndexWalker) { + walk(rangeStart: number, rangeLength: number, walkFns: LineIndexWalker) { // assume (rangeStart < this.totalChars) && (rangeLength <= this.totalChars) let childIndex = 0; let childCharCount = this.children[childIndex].charCount(); @@ -814,7 +814,7 @@ namespace ts.server { return true; } - walk(rangeStart: number, rangeLength: number, walkFns: ILineIndexWalker) { + walk(rangeStart: number, rangeLength: number, walkFns: LineIndexWalker) { walkFns.leaf(rangeStart, rangeLength, this); } diff --git a/src/server/server.ts b/src/server/server.ts index 01dba98a503..f4faa0d3c77 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -3,7 +3,7 @@ /// namespace ts.server { - interface IOSessionOptions { + interface IoSessionOptions { host: ServerHost; cancellationToken: ServerCancellationToken; canUseEvents: boolean; @@ -200,7 +200,7 @@ namespace ts.server { return this.loggingEnabled() && this.level >= level; } - msg(s: string, type: Msg.Types = Msg.Err) { + msg(s: string, type: Msg = Msg.Err) { if (!this.canWrite) return; s = `[${nowString()}] ${s}\n`; @@ -529,7 +529,7 @@ namespace ts.server { } class IOSession extends Session { - constructor(options: IOSessionOptions) { + constructor(options: IoSessionOptions) { const { host, installerEventPort, globalTypingsCacheLocation, typingSafeListLocation, typesMapLocation, npmLocation, canUseEvents } = options; const typingsInstaller = disableAutomaticTypingAcquisition ? undefined @@ -816,7 +816,7 @@ namespace ts.server { if (useWatchGuard) { const currentDrive = extractWatchDirectoryCacheKey(sys.resolvePath(sys.getCurrentDirectory()), /*currentDriveKey*/ undefined); const statusCache = createMap(); - sys.watchDirectory = function (path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher { + sys.watchDirectory = (path, callback, recursive) => { const cacheKey = extractWatchDirectoryCacheKey(path, currentDrive); let status = cacheKey && statusCache.get(cacheKey); if (status === undefined) { @@ -828,7 +828,7 @@ 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`); @@ -933,7 +933,7 @@ namespace ts.server { const disableAutomaticTypingAcquisition = hasArgument("--disableAutomaticTypingAcquisition"); const telemetryEnabled = hasArgument(Arguments.EnableTelemetry); - const options: IOSessionOptions = { + const options: IoSessionOptions = { host: sys, cancellationToken, installerEventPort: eventPort, @@ -953,7 +953,7 @@ namespace ts.server { }; const ioSession = new IOSession(options); - process.on("uncaughtException", function (err: Error) { + process.on("uncaughtException", err => { ioSession.logError(err, "unknown"); }); // See https://github.com/Microsoft/TypeScript/issues/11348 diff --git a/src/server/session.ts b/src/server/session.ts index 7ada8d2ff9c..6c97c3c8bd4 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -124,7 +124,7 @@ namespace ts.server { // we want to ensure the value is maintained in the out since the file is // built using --preseveConstEnum. export type CommandNames = protocol.CommandTypes; - export const CommandNames = (protocol).CommandTypes; + export const CommandNames = (protocol).CommandTypes; // tslint:disable-line variable-name export function formatMessage(msg: T, logger: server.Logger, byteLength: (s: string, encoding: string) => number, newLine: string): string { const verboseLogging = logger.hasLevel(LogLevel.verbose); @@ -167,7 +167,7 @@ namespace ts.server { private timerHandle: any; private immediateId: number | undefined; - constructor(private readonly operationHost: MultistepOperationHost) {} + constructor(private readonly operationHost: MultistepOperationHost) { } public startNew(action: (next: NextStep) => void) { this.complete(); @@ -587,7 +587,7 @@ namespace ts.server { private getDiagnosticsWorker( args: protocol.FileRequestArgs, isSemantic: boolean, selector: (project: Project, file: string) => ReadonlyArray, includeLinePosition: boolean - ): ReadonlyArray | ReadonlyArray { + ): ReadonlyArray | ReadonlyArray { const { project, file } = this.getFileAndProject(args); if (isSemantic && isDeclarationFileInJSOnlyNonConfiguredProject(project, file)) { return emptyArray; @@ -609,20 +609,51 @@ namespace ts.server { } if (simplifiedResult) { - return definitions.map(def => { - const defScriptInfo = project.getScriptInfo(def.fileName); - return { - file: def.fileName, - start: defScriptInfo.positionToLineOffset(def.textSpan.start), - end: defScriptInfo.positionToLineOffset(textSpanEnd(def.textSpan)) - }; - }); + return this.mapDefinitionInfo(definitions, project); } else { return definitions; } } + private getDefinitionAndBoundSpan(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.DefinitionInfoAndBoundSpan | DefinitionInfoAndBoundSpan { + const { file, project } = this.getFileAndProject(args); + const position = this.getPositionInFile(args, file); + const scriptInfo = project.getScriptInfo(file); + + const definitionAndBoundSpan = project.getLanguageService().getDefinitionAndBoundSpan(file, position); + + if (!definitionAndBoundSpan || !definitionAndBoundSpan.definitions) { + return { + definitions: emptyArray, + textSpan: undefined + }; + } + + if (simplifiedResult) { + return { + definitions: this.mapDefinitionInfo(definitionAndBoundSpan.definitions, project), + textSpan: this.toLocationTextSpan(definitionAndBoundSpan.textSpan, scriptInfo) + }; + } + + return definitionAndBoundSpan; + } + + private mapDefinitionInfo(definitions: ReadonlyArray, project: Project): ReadonlyArray { + return definitions.map(def => this.toFileSpan(def.fileName, def.textSpan, project)); + } + + private toFileSpan(fileName: string, textSpan: TextSpan, project: Project): protocol.FileSpan { + const scriptInfo = project.getScriptInfo(fileName); + + return { + file: fileName, + start: scriptInfo.positionToLineOffset(textSpan.start), + end: scriptInfo.positionToLineOffset(textSpanEnd(textSpan)) + }; + } + private getTypeDefinition(args: protocol.FileLocationRequestArgs): ReadonlyArray { const { file, project } = this.getFileAndProject(args); const position = this.getPositionInFile(args, file); @@ -632,14 +663,7 @@ namespace ts.server { return emptyArray; } - return definitions.map(def => { - const defScriptInfo = project.getScriptInfo(def.fileName); - return { - file: def.fileName, - start: defScriptInfo.positionToLineOffset(def.textSpan.start), - end: defScriptInfo.positionToLineOffset(textSpanEnd(def.textSpan)) - }; - }); + return this.mapDefinitionInfo(definitions, project); } private getImplementation(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): ReadonlyArray | ReadonlyArray { @@ -650,14 +674,7 @@ namespace ts.server { return emptyArray; } if (simplifiedResult) { - return implementations.map(({ fileName, textSpan }) => { - const scriptInfo = project.getScriptInfo(fileName); - return { - file: fileName, - start: scriptInfo.positionToLineOffset(textSpan.start), - end: scriptInfo.positionToLineOffset(textSpanEnd(textSpan)) - }; - }); + return implementations.map(({ fileName, textSpan }) => this.toFileSpan(fileName, textSpan, project)); } else { return implementations; @@ -666,6 +683,7 @@ namespace ts.server { private getOccurrences(args: protocol.FileLocationRequestArgs): ReadonlyArray { const { file, project } = this.getFileAndProject(args); + const position = this.getPositionInFile(args, file); const occurrences = project.getLanguageService().getOccurrencesAtPosition(file, position); @@ -677,11 +695,9 @@ namespace ts.server { return occurrences.map(occurrence => { const { fileName, isWriteAccess, textSpan, isInString } = occurrence; const scriptInfo = project.getScriptInfo(fileName); - const start = scriptInfo.positionToLineOffset(textSpan.start); - const end = scriptInfo.positionToLineOffset(textSpanEnd(textSpan)); const result: protocol.OccurrencesResponseItem = { - start, - end, + start: scriptInfo.positionToLineOffset(textSpan.start), + end: scriptInfo.positionToLineOffset(textSpanEnd(textSpan)), file: fileName, isWriteAccess, }; @@ -958,7 +974,7 @@ namespace ts.server { projects, project => project.getLanguageService().findReferences(file, position), /*comparer*/ undefined, - /*areEqual (TODO: fixme)*/ undefined + equateValues ); } @@ -1184,39 +1200,35 @@ namespace ts.server { const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file); const position = this.getPosition(args, scriptInfo); - const completions = project.getLanguageService().getCompletionsAtPosition(file, position); + const completions = project.getLanguageService().getCompletionsAtPosition(file, position, args); if (simplifiedResult) { return mapDefined(completions && completions.entries, entry => { - if (completions.isMemberCompletion || (entry.name.toLowerCase().indexOf(prefix.toLowerCase()) === 0)) { + if (completions.isMemberCompletion || startsWith(entry.name.toLowerCase(), prefix.toLowerCase())) { const { name, kind, kindModifiers, sortText, replacementSpan, hasAction, source } = entry; - const convertedSpan = replacementSpan ? this.decorateSpan(replacementSpan, scriptInfo) : undefined; + const convertedSpan = replacementSpan ? this.toLocationTextSpan(replacementSpan, scriptInfo) : undefined; // Use `hasAction || undefined` to avoid serializing `false`. return { name, kind, kindModifiers, sortText, replacementSpan: convertedSpan, hasAction: hasAction || undefined, source }; } - }).sort((a, b) => compareStrings(a.name, b.name)); + }).sort((a, b) => compareStringsCaseSensitiveUI(a.name, b.name)); } else { return completions; } } - private getCompletionEntryDetails(args: protocol.CompletionDetailsRequestArgs): ReadonlyArray { + private getCompletionEntryDetails(args: protocol.CompletionDetailsRequestArgs, simplifiedResult: boolean): ReadonlyArray | ReadonlyArray { const { file, project } = this.getFileAndProject(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file); const position = this.getPosition(args, scriptInfo); const formattingOptions = project.projectService.getFormatCodeOptions(file); - return mapDefined(args.entryNames, entryName => { + const result = mapDefined(args.entryNames, entryName => { const { name, source } = typeof entryName === "string" ? { name: entryName, source: undefined } : entryName; - const details = project.getLanguageService().getCompletionEntryDetails(file, position, name, formattingOptions, source); - if (details) { - const mappedCodeActions = map(details.codeActions, action => this.mapCodeAction(action, scriptInfo)); - return { ...details, codeActions: mappedCodeActions }; - } - else { - return undefined; - } + return project.getLanguageService().getCompletionEntryDetails(file, position, name, formattingOptions, source); }); + return simplifiedResult + ? result.map(details => ({ ...details, codeActions: map(details.codeActions, action => this.mapCodeAction(action, scriptInfo)) })) + : result; } private getCompileOnSaveAffectedFileList(args: protocol.FileRequestArgs): ReadonlyArray { @@ -1337,13 +1349,13 @@ namespace ts.server { this.projectService.closeClientFile(file); } - private decorateNavigationBarItems(items: NavigationBarItem[], scriptInfo: ScriptInfo): protocol.NavigationBarItem[] { + private mapLocationNavigationBarItems(items: NavigationBarItem[], scriptInfo: ScriptInfo): protocol.NavigationBarItem[] { return map(items, item => ({ text: item.text, kind: item.kind, kindModifiers: item.kindModifiers, - spans: item.spans.map(span => this.decorateSpan(span, scriptInfo)), - childItems: this.decorateNavigationBarItems(item.childItems, scriptInfo), + spans: item.spans.map(span => this.toLocationTextSpan(span, scriptInfo)), + childItems: this.mapLocationNavigationBarItems(item.childItems, scriptInfo), indent: item.indent })); } @@ -1354,21 +1366,21 @@ namespace ts.server { return !items ? undefined : simplifiedResult - ? this.decorateNavigationBarItems(items, this.projectService.getScriptInfoForNormalizedPath(file)) + ? this.mapLocationNavigationBarItems(items, this.projectService.getScriptInfoForNormalizedPath(file)) : items; } - private decorateNavigationTree(tree: NavigationTree, scriptInfo: ScriptInfo): protocol.NavigationTree { + private toLocationNavigationTree(tree: NavigationTree, scriptInfo: ScriptInfo): protocol.NavigationTree { return { text: tree.text, kind: tree.kind, kindModifiers: tree.kindModifiers, - spans: tree.spans.map(span => this.decorateSpan(span, scriptInfo)), - childItems: map(tree.childItems, item => this.decorateNavigationTree(item, scriptInfo)) + spans: tree.spans.map(span => this.toLocationTextSpan(span, scriptInfo)), + childItems: map(tree.childItems, item => this.toLocationNavigationTree(item, scriptInfo)) }; } - private decorateSpan(span: TextSpan, scriptInfo: ScriptInfo): protocol.TextSpan { + private toLocationTextSpan(span: TextSpan, scriptInfo: ScriptInfo): protocol.TextSpan { return { start: scriptInfo.positionToLineOffset(span.start), end: scriptInfo.positionToLineOffset(textSpanEnd(span)) @@ -1381,7 +1393,7 @@ namespace ts.server { return !tree ? undefined : simplifiedResult - ? this.decorateNavigationTree(tree, this.projectService.getScriptInfoForNormalizedPath(file)) + ? this.toLocationNavigationTree(tree, this.projectService.getScriptInfoForNormalizedPath(file)) : tree; } @@ -1400,14 +1412,12 @@ namespace ts.server { return navItems.map((navItem) => { const scriptInfo = project.getScriptInfo(navItem.fileName); - const start = scriptInfo.positionToLineOffset(navItem.textSpan.start); - const end = scriptInfo.positionToLineOffset(textSpanEnd(navItem.textSpan)); const bakedItem: protocol.NavtoItem = { name: navItem.name, kind: navItem.kind, file: navItem.fileName, - start, - end, + start: scriptInfo.positionToLineOffset(navItem.textSpan.start), + end: scriptInfo.positionToLineOffset(textSpanEnd(navItem.textSpan)) }; if (navItem.kindModifiers && (navItem.kindModifiers !== "")) { bakedItem.kindModifiers = navItem.kindModifiers; @@ -1594,7 +1604,7 @@ namespace ts.server { fileName: change.fileName, textChanges: change.textChanges.map(textChange => this.convertTextChangeToCodeEdit(textChange, scriptInfo)) })); - return { description, changes, commands }; + return { description, changes, commands }; } private mapTextChangesToCodeEdits(project: Project, textChanges: FileTextChanges): protocol.FileCodeEdits { @@ -1622,7 +1632,7 @@ namespace ts.server { return !spans ? undefined : simplifiedResult - ? spans.map(span => this.decorateSpan(span, scriptInfo)) + ? spans.map(span => this.toLocationTextSpan(span, scriptInfo)) : spans; } @@ -1677,8 +1687,7 @@ namespace ts.server { return normalizePath(name); } - exit() { - } + exit() { /*overridden*/ } private notRequired(): HandlerResponse { return { responseRequired: false }; @@ -1738,6 +1747,12 @@ namespace ts.server { [CommandNames.DefinitionFull]: (request: protocol.DefinitionRequest) => { return this.requiredResponse(this.getDefinition(request.arguments, /*simplifiedResult*/ false)); }, + [CommandNames.DefinitionAndBoundSpan]: (request: protocol.DefinitionRequest) => { + return this.requiredResponse(this.getDefinitionAndBoundSpan(request.arguments, /*simplifiedResult*/ true)); + }, + [CommandNames.DefinitionAndBoundSpanFull]: (request: protocol.DefinitionRequest) => { + return this.requiredResponse(this.getDefinitionAndBoundSpan(request.arguments, /*simplifiedResult*/ false)); + }, [CommandNames.TypeDefinition]: (request: protocol.FileLocationRequest) => { return this.requiredResponse(this.getTypeDefinition(request.arguments)); }, @@ -1815,14 +1830,17 @@ namespace ts.server { [CommandNames.FormatRangeFull]: (request: protocol.FormatRequest) => { return this.requiredResponse(this.getFormattingEditsForRangeFull(request.arguments)); }, - [CommandNames.Completions]: (request: protocol.CompletionDetailsRequest) => { + [CommandNames.Completions]: (request: protocol.CompletionsRequest) => { return this.requiredResponse(this.getCompletions(request.arguments, /*simplifiedResult*/ true)); }, - [CommandNames.CompletionsFull]: (request: protocol.CompletionDetailsRequest) => { + [CommandNames.CompletionsFull]: (request: protocol.CompletionsRequest) => { return this.requiredResponse(this.getCompletions(request.arguments, /*simplifiedResult*/ false)); }, [CommandNames.CompletionDetails]: (request: protocol.CompletionDetailsRequest) => { - return this.requiredResponse(this.getCompletionEntryDetails(request.arguments)); + return this.requiredResponse(this.getCompletionEntryDetails(request.arguments, /*simplifiedResult*/ true)); + }, + [CommandNames.CompletionDetailsFull]: (request: protocol.CompletionDetailsRequest) => { + return this.requiredResponse(this.getCompletionEntryDetails(request.arguments, /*simplifiedResult*/ false)); }, [CommandNames.CompileOnSaveAffectedFileList]: (request: protocol.CompileOnSaveAffectedFileListRequest) => { return this.requiredResponse(this.getCompileOnSaveAffectedFileList(request.arguments)); diff --git a/src/server/shared.ts b/src/server/shared.ts index a8a122c3327..99a38eba389 100644 --- a/src/server/shared.ts +++ b/src/server/shared.ts @@ -1,6 +1,7 @@ /// namespace ts.server { + // tslint:disable variable-name export const ActionSet: ActionSet = "action::set"; export const ActionInvalidate: ActionInvalidate = "action::invalidate"; export const EventTypesRegistry: EventTypesRegistry = "event::typesRegistry"; diff --git a/src/server/typingsCache.ts b/src/server/typingsCache.ts index d6eeaa2cbcf..cde303bfd39 100644 --- a/src/server/typingsCache.ts +++ b/src/server/typingsCache.ts @@ -5,6 +5,7 @@ namespace ts.server { projectRootPath: Path; } + // tslint:disable-next-line interface-name (for backwards-compatibility) export interface ITypingsInstaller { isKnownTypesPackageName(name: string): boolean; installPackage(options: InstallPackageOptionsWithProjectRootPath): Promise; diff --git a/src/server/typingsInstaller/nodeTypingsInstaller.ts b/src/server/typingsInstaller/nodeTypingsInstaller.ts index 2a1036010a7..da16d5dde82 100644 --- a/src/server/typingsInstaller/nodeTypingsInstaller.ts +++ b/src/server/typingsInstaller/nodeTypingsInstaller.ts @@ -63,9 +63,9 @@ namespace ts.server.typingsInstaller { } } - const TypesRegistryPackageName = "types-registry"; + 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 { @@ -105,16 +105,16 @@ namespace ts.server.typingsInstaller { try { if (this.log.isEnabled()) { - this.log.writeLine(`Updating ${TypesRegistryPackageName} npm package...`); + this.log.writeLine(`Updating ${typesRegistryPackageName} npm package...`); } - this.execSyncAndLog(`${this.npmPath} install --ignore-scripts ${TypesRegistryPackageName}`, { cwd: globalTypingsCacheLocation }); + this.execSyncAndLog(`${this.npmPath} install --ignore-scripts ${typesRegistryPackageName}`, { cwd: globalTypingsCacheLocation }); if (this.log.isEnabled()) { - this.log.writeLine(`Updated ${TypesRegistryPackageName} npm package`); + this.log.writeLine(`Updated ${typesRegistryPackageName} npm package`); } } catch (e) { if (this.log.isEnabled()) { - this.log.writeLine(`Error updating ${TypesRegistryPackageName} package: ${(e).message}`); + this.log.writeLine(`Error updating ${typesRegistryPackageName} package: ${(e).message}`); } // store error info to report it later when it is known that server is already listening to events from typings installer this.delayedInitializationError = { @@ -243,7 +243,7 @@ namespace ts.server.typingsInstaller { const installer = new NodeTypingsInstaller(globalTypingsCacheLocation, typingSafeListLocation, typesMapLocation, npmLocation, /*throttleLimit*/5, log); installer.listen(); - function indent(newline: string, string: string): string { - return `${newline} ` + string.replace(/\r?\n/, `${newline} `); + function indent(newline: string, str: string): string { + return `${newline} ` + str.replace(/\r?\n/, `${newline} `); } } diff --git a/src/server/typingsInstaller/typingsInstaller.ts b/src/server/typingsInstaller/typingsInstaller.ts index 26e7781b440..eacbebbf4ab 100644 --- a/src/server/typingsInstaller/typingsInstaller.ts +++ b/src/server/typingsInstaller/typingsInstaller.ts @@ -248,7 +248,7 @@ namespace ts.server.typingsInstaller { this.log.writeLine(`Npm config file: '${npmConfigPath}' is missing, creating new one...`); } this.ensureDirectoryExists(directory, this.installTypingHost); - this.installTypingHost.writeFile(npmConfigPath, "{}"); + this.installTypingHost.writeFile(npmConfigPath, '{ "private": true }'); } } diff --git a/src/server/utilities.ts b/src/server/utilities.ts index 69399b672b3..c57d3b40dee 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -19,18 +19,19 @@ namespace ts.server { info(s: string): void; startGroup(): void; endGroup(): void; - msg(s: string, type?: Msg.Types): void; + msg(s: string, type?: Msg): void; getLogFileName(): string; } + // TODO: Use a const enum (https://github.com/Microsoft/TypeScript/issues/16804) + export enum Msg { + Err = "Err", + Info = "Info", + Perf = "Perf", + } export namespace Msg { - export type Err = "Err"; - export const Err: Err = "Err"; - export type Info = "Info"; - export const Info: Info = "Info"; - export type Perf = "Perf"; - export const Perf: Perf = "Perf"; - export type Types = Err | Info | Perf; + /** @deprecated Only here for backwards-compatibility. Prefer just `Msg`. */ + export type Types = Msg; } function getProjectRootPath(project: Project): Path { @@ -250,7 +251,7 @@ namespace ts.server { return; } - const insertIndex = binarySearch(array, insert, compare); + const insertIndex = binarySearch(array, insert, identity, compare); if (insertIndex < 0) { array.splice(~insertIndex, 0, insert); } @@ -266,7 +267,7 @@ namespace ts.server { return; } - const removeIndex = binarySearch(array, remove, compare); + const removeIndex = binarySearch(array, remove, identity, compare); if (removeIndex >= 0) { array.splice(removeIndex, 1); } @@ -288,8 +289,7 @@ namespace ts.server { return index === 0 || value !== array[index - 1]; } - export function enumerateInsertsAndDeletes(newItems: SortedReadonlyArray, oldItems: SortedReadonlyArray, inserted: (newItem: T) => void, deleted: (oldItem: T) => void, compare?: Comparer) { - compare = compare || compareValues; + export function enumerateInsertsAndDeletes(newItems: SortedReadonlyArray, oldItems: SortedReadonlyArray, inserted: (newItem: T) => void, deleted: (oldItem: T) => void, comparer: Comparer) { let newIndex = 0; let oldIndex = 0; const newLen = newItems.length; @@ -297,7 +297,7 @@ namespace ts.server { while (newIndex < newLen && oldIndex < oldLen) { const newItem = newItems[newIndex]; const oldItem = oldItems[oldIndex]; - const compareResult = compare(newItem, oldItem); + const compareResult = comparer(newItem, oldItem); if (compareResult === Comparison.LessThan) { inserted(newItem); newIndex++; @@ -320,8 +320,8 @@ namespace ts.server { } /* @internal */ - export function indent(string: string): string { - return "\n " + string; + export function indent(str: string): string { + return "\n " + str; } /** Put stringified JSON on the next line, indented. */ diff --git a/src/server/watchGuard/watchGuard.ts b/src/server/watchGuard/watchGuard.ts index f57369aecb9..8ec248ebb87 100644 --- a/src/server/watchGuard/watchGuard.ts +++ b/src/server/watchGuard/watchGuard.ts @@ -14,6 +14,5 @@ try { const watcher = fs.watch(directoryName, { recursive: true }, () => ({})); watcher.close(); } -catch (_e) { -} +catch { /*ignore*/ } process.exit(0); \ No newline at end of file diff --git a/src/services/breakpoints.ts b/src/services/breakpoints.ts index 37aa8df0ca1..73732ce87e8 100644 --- a/src/services/breakpoints.ts +++ b/src/services/breakpoints.ts @@ -31,7 +31,7 @@ namespace ts.BreakpointResolver { } // Cannot set breakpoint in ambient declarations - if (isInAmbientContext(tokenAtLocation)) { + if (tokenAtLocation.flags & NodeFlags.Ambient) { return undefined; } @@ -297,7 +297,7 @@ namespace ts.BreakpointResolver { } } - if (isPartOfExpression(node)) { + if (isExpressionNode(node)) { switch (node.parent.kind) { case SyntaxKind.DoStatement: // Set span as if on while keyword diff --git a/src/services/codefixes/fixCannotFindModule.ts b/src/services/codefixes/fixCannotFindModule.ts index c15ca341cb4..29f2475f21d 100644 --- a/src/services/codefixes/fixCannotFindModule.ts +++ b/src/services/codefixes/fixCannotFindModule.ts @@ -26,7 +26,7 @@ namespace ts.codefix { const typesPackageName = getTypesPackageName(packageName); return { - description: `Install '${typesPackageName}'`, + description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Install_0), [typesPackageName]), changes: [], commands: [{ type: "install package", packageName: typesPackageName }], }; diff --git a/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts b/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts index bc92cd8e0d1..e5c4266684d 100644 --- a/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts +++ b/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts @@ -20,8 +20,8 @@ namespace ts.codefix { // i.e. super(this.a), since in that case we won't suggest a fix if (superCall.expression && superCall.expression.kind === SyntaxKind.CallExpression) { const expressionArguments = (superCall.expression).arguments; - for (let i = 0; i < expressionArguments.length; i++) { - if ((expressionArguments[i]).expression === token) { + for (const arg of expressionArguments) { + if ((arg).expression === token) { return undefined; } } diff --git a/src/services/codefixes/fixSpelling.ts b/src/services/codefixes/fixSpelling.ts index ff3bd455291..2546a92a32f 100644 --- a/src/services/codefixes/fixSpelling.ts +++ b/src/services/codefixes/fixSpelling.ts @@ -22,7 +22,9 @@ namespace ts.codefix { } else { const meaning = getMeaningFromLocation(node); - suggestion = checker.getSuggestionForNonexistentSymbol(node, getTextOfNode(node), convertSemanticMeaningToSymbolFlags(meaning)); + const name = getTextOfNode(node); + Debug.assert(name !== undefined, "name should be defined"); + suggestion = checker.getSuggestionForNonexistentSymbol(node, name, convertSemanticMeaningToSymbolFlags(meaning)); } if (suggestion) { return [{ diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index 685c6832f13..206a3864ac0 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -104,8 +104,7 @@ namespace ts.codefix { } const signatureDeclarations: MethodDeclaration[] = []; - for (let i = 0; i < signatures.length; i++) { - const signature = signatures[i]; + for (const signature of signatures) { const methodDeclaration = signatureToMethodDeclaration(signature, enclosingDeclaration); if (methodDeclaration) { signatureDeclarations.push(methodDeclaration); @@ -194,8 +193,7 @@ namespace ts.codefix { let maxArgsSignature = signatures[0]; let minArgumentCount = signatures[0].minArgumentCount; let someSigHasRestParameter = false; - for (let i = 0; i < signatures.length; i++) { - const sig = signatures[i]; + for (const sig of signatures) { minArgumentCount = Math.min(sig.minArgumentCount, minArgumentCount); if (sig.hasRestParameter) { someSigHasRestParameter = true; diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 3f0d27e5b07..a0c7ffd75ea 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -166,7 +166,7 @@ namespace ts.codefix { return { host: context.host, newLineCharacter: context.newLineCharacter, - rulesProvider: context.rulesProvider, + formatContext: context.formatContext, sourceFile: context.sourceFile, checker, compilerOptions: context.program.getCompilerOptions(), @@ -181,6 +181,7 @@ namespace ts.codefix { Named, Default, Namespace, + Equals } export function getCodeActionForImport(moduleSymbol: Symbol, context: ImportCodeFixOptions): ImportCodeAction[] { @@ -212,7 +213,7 @@ namespace ts.codefix { function getNamespaceImportName(declaration: AnyImportSyntax): Identifier { if (declaration.kind === SyntaxKind.ImportDeclaration) { - const namedBindings = declaration.importClause && declaration.importClause.namedBindings; + const namedBindings = declaration.importClause && isImportClause(declaration.importClause) && declaration.importClause.namedBindings; return namedBindings && namedBindings.kind === SyntaxKind.NamespaceImport ? namedBindings.name : undefined; } else { @@ -237,10 +238,12 @@ namespace ts.codefix { return parent as ImportDeclaration; case SyntaxKind.ExternalModuleReference: return (parent as ExternalModuleReference).parent; - default: - Debug.assert(parent.kind === SyntaxKind.ExportDeclaration); + case SyntaxKind.ExportDeclaration: + case SyntaxKind.CallExpression: // For "require()" calls // Ignore these, can't add imports to them. return undefined; + default: + Debug.fail(); } } @@ -249,11 +252,19 @@ namespace ts.codefix { const lastImportDeclaration = findLast(sourceFile.statements, isAnyImportSyntax); const moduleSpecifierWithoutQuotes = stripQuotes(moduleSpecifier); - const importDecl = createImportDeclaration( - /*decorators*/ undefined, - /*modifiers*/ undefined, - createImportClauseOfKind(kind, symbolName), - createStringLiteralWithQuoteStyle(sourceFile, moduleSpecifierWithoutQuotes)); + const quotedModuleSpecifier = createStringLiteralWithQuoteStyle(sourceFile, moduleSpecifierWithoutQuotes); + const importDecl = kind !== ImportKind.Equals + ? createImportDeclaration( + /*decorators*/ undefined, + /*modifiers*/ undefined, + createImportClauseOfKind(kind, symbolName), + quotedModuleSpecifier) + : createImportEqualsDeclaration( + /*decorators*/ undefined, + /*modifiers*/ undefined, + createIdentifier(symbolName), + createExternalModuleReference(quotedModuleSpecifier)); + const changes = ChangeTracker.with(context, changeTracker => { if (lastImportDeclaration) { changeTracker.insertNodeAfter(sourceFile, lastImportDeclaration, importDecl, { suffix: newLineCharacter }); @@ -263,11 +274,17 @@ namespace ts.codefix { } }); + const actionFormat = kind === ImportKind.Equals + ? Diagnostics.Import_0_require_1 + : kind === ImportKind.Namespace + ? Diagnostics.Import_Asterisk_as_0_from_1 + : Diagnostics.Import_0_from_1; + // if this file doesn't have any import statements, insert an import statement and then insert a new line // between the only import statement and user code. Otherwise just insert the statement because chances // are there are already a new line seperating code and import statements. return createCodeAction( - Diagnostics.Import_0_from_1, + actionFormat, [symbolName, moduleSpecifierWithoutQuotes], changes, "NewImport", @@ -282,7 +299,7 @@ namespace ts.codefix { return literal; } - function createImportClauseOfKind(kind: ImportKind, symbolName: string) { + function createImportClauseOfKind(kind: ImportKind.Default | ImportKind.Named | ImportKind.Namespace, symbolName: string) { const id = createIdentifier(symbolName); switch (kind) { case ImportKind.Default: @@ -534,7 +551,7 @@ namespace ts.codefix { declarations: ReadonlyArray): ImportCodeAction { const fromExistingImport = firstDefined(declarations, declaration => { if (declaration.kind === SyntaxKind.ImportDeclaration && declaration.importClause) { - const changes = tryUpdateExistingImport(ctx, declaration.importClause); + const changes = tryUpdateExistingImport(ctx, isImportClause(declaration.importClause) && declaration.importClause || undefined); if (changes) { const moduleSpecifierWithoutQuotes = stripQuotes(declaration.moduleSpecifier.getText()); return createCodeAction( @@ -564,9 +581,10 @@ namespace ts.codefix { return expression && isStringLiteral(expression) ? expression.text : undefined; } - function tryUpdateExistingImport(context: SymbolContext & { kind: ImportKind }, importClause: ImportClause): FileTextChanges[] | undefined { + function tryUpdateExistingImport(context: SymbolContext & { kind: ImportKind }, importClause: ImportClause | ImportEqualsDeclaration): FileTextChanges[] | undefined { const { symbolName, sourceFile, kind } = context; - const { name, namedBindings } = importClause; + const { name } = importClause; + const { namedBindings } = importClause.kind !== SyntaxKind.ImportEqualsDeclaration && importClause; switch (kind) { case ImportKind.Default: return name ? undefined : ChangeTracker.with(context, t => @@ -592,6 +610,9 @@ namespace ts.codefix { return namedBindings ? undefined : ChangeTracker.with(context, t => t.replaceNode(sourceFile, importClause, createImportClause(name, createNamespaceImport(createIdentifier(symbolName))))); + case ImportKind.Equals: + return undefined; + default: Debug.assertNever(kind); } @@ -627,7 +648,7 @@ namespace ts.codefix { } function getActionsForUMDImport(context: ImportCodeFixContext): ImportCodeAction[] { - const { checker, symbolToken } = context; + const { checker, symbolToken, compilerOptions } = context; const umdSymbol = checker.getSymbolAtLocation(symbolToken); let symbol: ts.Symbol; let symbolName: string; @@ -644,6 +665,20 @@ namespace ts.codefix { Debug.fail("Either the symbol or the JSX namespace should be a UMD global if we got here"); } + const allowSyntheticDefaultImports = getAllowSyntheticDefaultImports(compilerOptions); + + // Import a synthetic `default` if enabled. + if (allowSyntheticDefaultImports) { + return getCodeActionForImport(symbol, { ...context, symbolName, kind: ImportKind.Default }); + } + const moduleKind = getEmitModuleKind(compilerOptions); + + // When a synthetic `default` is unavailable, use `import..require` if the module kind supports it. + if (moduleKind === ModuleKind.AMD || moduleKind === ModuleKind.CommonJS || moduleKind === ModuleKind.UMD) { + return getCodeActionForImport(symbol, { ...context, symbolName, kind: ImportKind.Equals }); + } + + // Fall back to the `import * as ns` style import. return getCodeActionForImport(symbol, { ...context, symbolName, kind: ImportKind.Namespace }); } diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index b952cc5a98d..378c73f2f75 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -368,7 +368,7 @@ namespace ts.codefix { } function inferTypeFromContextualType(node: Expression, checker: TypeChecker, usageContext: UsageContext): void { - if (isPartOfExpression(node)) { + if (isExpressionNode(node)) { addCandidateType(usageContext, checker.getContextualType(node)); } } diff --git a/src/services/completions.ts b/src/services/completions.ts index 562cdd5cbb2..f66242ca864 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -28,16 +28,18 @@ namespace ts.Completions { sourceFile: SourceFile, position: number, allSourceFiles: ReadonlyArray, + options: GetCompletionsAtPositionOptions, ): CompletionInfo | undefined { if (isInReferenceComment(sourceFile, position)) { - return PathCompletions.getTripleSlashReferenceCompletion(sourceFile, position, compilerOptions, host); + const entries = PathCompletions.getTripleSlashReferenceCompletion(sourceFile, position, compilerOptions, host); + return entries && pathCompletionsInfo(entries); } if (isInString(sourceFile, position)) { return getStringLiteralCompletionEntries(sourceFile, position, typeChecker, compilerOptions, host, log); } - const completionData = getCompletionData(typeChecker, log, sourceFile, position, allSourceFiles); + const completionData = getCompletionData(typeChecker, log, sourceFile, position, allSourceFiles, options); if (!completionData) { return undefined; } @@ -241,12 +243,17 @@ namespace ts.Completions { // a['/*completion position*/'] return getStringLiteralCompletionEntriesFromElementAccess(node.parent, typeChecker, compilerOptions.target, log); } - else if (node.parent.kind === SyntaxKind.ImportDeclaration || isExpressionOfExternalModuleImportEqualsDeclaration(node) || isRequireCall(node.parent, /*checkArgumentIsStringLiteral*/ false)) { + else if (node.parent.kind === SyntaxKind.ImportDeclaration || node.parent.kind === SyntaxKind.ExportDeclaration + || isRequireCall(node.parent, /*checkArgumentIsStringLiteral*/ false) || isImportCall(node.parent) + || isExpressionOfExternalModuleImportEqualsDeclaration(node)) { // Get all known external module names or complete a path to a module // i.e. import * as ns from "/*completion position*/"; + // var y = import("/*completion position*/"); // import x = require("/*completion position*/"); // var y = require("/*completion position*/"); - return PathCompletions.getStringLiteralCompletionEntriesFromModuleNames(node, compilerOptions, host, typeChecker); + // export * from "/*completion position*/"; + const entries = PathCompletions.getStringLiteralCompletionsFromModuleNames(node, compilerOptions, host, typeChecker); + return pathCompletionsInfo(entries); } else if (isEqualityExpression(node.parent)) { // Get completions from the type of the other operand @@ -275,6 +282,18 @@ namespace ts.Completions { } } + function pathCompletionsInfo(entries: CompletionEntry[]): CompletionInfo { + return { + // We don't want the editor to offer any other completions, such as snippets, inside a comment. + isGlobalCompletion: false, + isMemberCompletion: false, + // 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. + isNewIdentifierLocation: true, + entries, + }; + } + function getStringLiteralCompletionEntriesFromPropertyAssignment(element: ObjectLiteralElement, typeChecker: TypeChecker, target: ScriptTarget, log: Log): CompletionInfo | undefined { const type = typeChecker.getContextualType((element.parent)); const entries: CompletionEntry[] = []; @@ -362,7 +381,7 @@ namespace ts.Completions { { name, source }: CompletionEntryIdentifier, allSourceFiles: ReadonlyArray, ): { type: "symbol", symbol: Symbol, location: Node, symbolToOriginInfoMap: SymbolOriginInfoMap } | { type: "request", request: Request } | { type: "none" } { - const completionData = getCompletionData(typeChecker, log, sourceFile, position, allSourceFiles); + const completionData = getCompletionData(typeChecker, log, sourceFile, position, allSourceFiles, { includeExternalModuleExports: true }); if (!completionData) { return { type: "none" }; } @@ -396,7 +415,7 @@ namespace ts.Completions { entryId: CompletionEntryIdentifier, allSourceFiles: ReadonlyArray, host: LanguageServiceHost, - rulesProvider: formatting.RulesProvider, + formatContext: formatting.FormatContext, ): CompletionEntryDetails { const { name, source } = entryId; // Compute all the completion symbols again. @@ -417,7 +436,7 @@ namespace ts.Completions { } case "symbol": { const { symbol, location, symbolToOriginInfoMap } = symbolCompletion; - const codeActions = getCompletionEntryCodeActions(symbolToOriginInfoMap, symbol, typeChecker, host, compilerOptions, sourceFile, rulesProvider); + const codeActions = getCompletionEntryCodeActions(symbolToOriginInfoMap, symbol, typeChecker, host, compilerOptions, sourceFile, formatContext); const kindModifiers = SymbolDisplay.getSymbolModifiers(symbol); const { displayParts, documentation, symbolKind, tags } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, sourceFile, location, location, SemanticMeaning.All); return { name, kindModifiers, kind: symbolKind, displayParts, documentation, tags, codeActions, source: source === undefined ? undefined : [textPart(source)] }; @@ -448,7 +467,7 @@ namespace ts.Completions { host: LanguageServiceHost, compilerOptions: CompilerOptions, sourceFile: SourceFile, - rulesProvider: formatting.RulesProvider, + formatContext: formatting.FormatContext, ): CodeAction[] | undefined { const symbolOriginInfo = symbolToOriginInfoMap[getSymbolId(symbol)]; if (!symbolOriginInfo) { @@ -462,7 +481,7 @@ namespace ts.Completions { newLineCharacter: host.getNewLine(), compilerOptions, sourceFile, - rulesProvider, + formatContext, symbolName: symbol.name, getCanonicalFileName: createGetCanonicalFileName(host.useCaseSensitiveFileNames ? host.useCaseSensitiveFileNames() : false), symbolToken: undefined, @@ -503,6 +522,7 @@ namespace ts.Completions { sourceFile: SourceFile, position: number, allSourceFiles: ReadonlyArray, + options: GetCompletionsAtPositionOptions, ): CompletionData | undefined { const isJavaScriptFile = isSourceFileJavaScript(sourceFile); @@ -900,7 +920,9 @@ namespace ts.Completions { const symbolMeanings = SymbolFlags.Type | SymbolFlags.Value | SymbolFlags.Namespace | SymbolFlags.Alias; symbols = typeChecker.getSymbolsInScope(scopeNode, symbolMeanings); - getSymbolsFromOtherSourceFileExports(symbols, previousToken && isIdentifier(previousToken) ? previousToken.text : ""); + if (options.includeExternalModuleExports) { + getSymbolsFromOtherSourceFileExports(symbols, previousToken && isIdentifier(previousToken) ? previousToken.text : ""); + } filterGlobalCompletion(symbols); return true; @@ -1839,6 +1861,18 @@ namespace ts.Completions { } } + // If the symbol is for a member of an object type and is the internal name of an ES + // symbol, it is not a valid entry. Internal names for ES symbols start with "__@" + if (symbol.flags & SymbolFlags.ClassMember) { + const escapedName = symbol.escapedName as string; + if (escapedName.length >= 3 && + escapedName.charCodeAt(0) === CharacterCodes._ && + escapedName.charCodeAt(1) === CharacterCodes._ && + escapedName.charCodeAt(2) === CharacterCodes.at) { + return undefined; + } + } + return getCompletionEntryDisplayName(name, target, performCharacterChecks, allowStringLiteral); } diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index 3808cb78940..b8122827491 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -1,10 +1,14 @@ -/// -/// -/// -/// +/// +/// +/// +/// /* @internal */ namespace ts.formatting { + export interface FormatContext { + readonly options: ts.FormatCodeSettings; + readonly getRule: ts.formatting.RulesMap; + } export interface TextRangeWithKind extends TextRange { kind: SyntaxKind; @@ -67,7 +71,7 @@ namespace ts.formatting { delta: number; } - export function formatOnEnter(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeSettings): TextChange[] { + export function formatOnEnter(position: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] { const line = sourceFile.getLineAndCharacterOfPosition(position).line; if (line === 0) { return []; @@ -93,15 +97,15 @@ namespace ts.formatting { // end value is exclusive so add 1 to the result end: endOfFormatSpan + 1 }; - return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnEnter); + return formatSpan(span, sourceFile, formatContext, FormattingRequestKind.FormatOnEnter); } - export function formatOnSemicolon(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeSettings): TextChange[] { + export function formatOnSemicolon(position: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] { const semicolon = findImmediatelyPrecedingTokenOfKind(position, SyntaxKind.SemicolonToken, sourceFile); - return formatNodeLines(findOutermostNodeWithinListLevel(semicolon), sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnSemicolon); + return formatNodeLines(findOutermostNodeWithinListLevel(semicolon), sourceFile, formatContext, FormattingRequestKind.FormatOnSemicolon); } - export function formatOnOpeningCurly(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeSettings): TextChange[] { + export function formatOnOpeningCurly(position: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] { const openingCurly = findImmediatelyPrecedingTokenOfKind(position, SyntaxKind.OpenBraceToken, sourceFile); if (!openingCurly) { return []; @@ -126,29 +130,29 @@ namespace ts.formatting { end: position }; - return formatSpan(textRange, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnOpeningCurlyBrace); + return formatSpan(textRange, sourceFile, formatContext, FormattingRequestKind.FormatOnOpeningCurlyBrace); } - export function formatOnClosingCurly(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeSettings): TextChange[] { + export function formatOnClosingCurly(position: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] { const precedingToken = findImmediatelyPrecedingTokenOfKind(position, SyntaxKind.CloseBraceToken, sourceFile); - return formatNodeLines(findOutermostNodeWithinListLevel(precedingToken), sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnClosingCurlyBrace); + return formatNodeLines(findOutermostNodeWithinListLevel(precedingToken), sourceFile, formatContext, FormattingRequestKind.FormatOnClosingCurlyBrace); } - export function formatDocument(sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeSettings): TextChange[] { + export function formatDocument(sourceFile: SourceFile, formatContext: FormatContext): TextChange[] { const span = { pos: 0, end: sourceFile.text.length }; - return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatDocument); + return formatSpan(span, sourceFile, formatContext, FormattingRequestKind.FormatDocument); } - export function formatSelection(start: number, end: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeSettings): 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), end, }; - return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatSelection); + return formatSpan(span, sourceFile, formatContext, FormattingRequestKind.FormatSelection); } /** @@ -337,7 +341,7 @@ namespace ts.formatting { } /* @internal */ - export function formatNodeGivenIndentation(node: Node, sourceFileLike: SourceFileLike, languageVariant: LanguageVariant, initialIndentation: number, delta: number, rulesProvider: RulesProvider): TextChange[] { + export function formatNodeGivenIndentation(node: Node, sourceFileLike: SourceFileLike, languageVariant: LanguageVariant, initialIndentation: number, delta: number, formatContext: FormatContext): TextChange[] { const range = { pos: 0, end: sourceFileLike.text.length }; return getFormattingScanner(sourceFileLike.text, languageVariant, range.pos, range.end, scanner => formatSpanWorker( range, @@ -345,14 +349,13 @@ namespace ts.formatting { initialIndentation, delta, scanner, - rulesProvider.getFormatOptions(), - rulesProvider, + formatContext, FormattingRequestKind.FormatSelection, _ => false, // assume that node does not have any errors sourceFileLike)); } - function formatNodeLines(node: Node, sourceFile: SourceFile, options: FormatCodeSettings, rulesProvider: RulesProvider, requestKind: FormattingRequestKind): TextChange[] { + function formatNodeLines(node: Node, sourceFile: SourceFile, formatContext: FormatContext, requestKind: FormattingRequestKind): TextChange[] { if (!node) { return []; } @@ -362,24 +365,19 @@ namespace ts.formatting { end: node.end }; - return formatSpan(span, sourceFile, options, rulesProvider, requestKind); + return formatSpan(span, sourceFile, formatContext, requestKind); } - function formatSpan(originalRange: TextRange, - sourceFile: SourceFile, - options: FormatCodeSettings, - rulesProvider: RulesProvider, - 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(sourceFile.text, sourceFile.languageVariant, getScanStartPosition(enclosingNode, originalRange, sourceFile), originalRange.end, scanner => formatSpanWorker( originalRange, enclosingNode, - SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, options), - getOwnOrInheritedDelta(enclosingNode, options, sourceFile), + SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, formatContext.options), + getOwnOrInheritedDelta(enclosingNode, formatContext.options, sourceFile), scanner, - options, - rulesProvider, + formatContext, requestKind, prepareRangeContainsErrorFunction(sourceFile.parseDiagnostics, originalRange), sourceFile)); @@ -390,8 +388,7 @@ namespace ts.formatting { initialIndentation: number, delta: number, formattingScanner: FormattingScanner, - options: FormatCodeSettings, - rulesProvider: RulesProvider, + { options, getRule }: FormatContext, requestKind: FormattingRequestKind, rangeContainsError: (r: TextRange) => boolean, sourceFile: SourceFileLike): TextChange[] { @@ -714,6 +711,11 @@ namespace ts.formatting { processNode(child, childContextNode, childStartLine, undecoratedChildStartLine, childIndentation.indentation, childIndentation.delta); + if (child.kind === SyntaxKind.JsxText) { + const range: TextRange = { pos: child.getStart(), end: child.getEnd() }; + indentMultilineCommentOrJsxText(range, childIndentation.indentation, /*firstLineIsIndented*/ true, /*indentFinalLine*/ false); + } + childContextNode = node; if (isFirstListItem && parent.kind === SyntaxKind.ArrayLiteralExpression && inheritedIndentation === Constants.Unknown) { @@ -833,7 +835,7 @@ namespace ts.formatting { switch (triviaItem.kind) { case SyntaxKind.MultiLineCommentTrivia: if (triviaInRange) { - indentMultilineComment(triviaItem, commentIndentation, /*firstLineIsIndented*/ !indentNextTokenOrTrivia); + indentMultilineCommentOrJsxText(triviaItem, commentIndentation, /*firstLineIsIndented*/ !indentNextTokenOrTrivia); } indentNextTokenOrTrivia = false; break; @@ -912,14 +914,14 @@ namespace ts.formatting { formattingContext.updateContext(previousItem, previousParent, currentItem, currentParent, contextNode); - const rule = rulesProvider.getRulesMap().GetRule(formattingContext); + const rule = getRule(formattingContext); let trimTrailingWhitespaces: boolean; let lineAdded: boolean; if (rule) { applyRuleEdits(rule, previousItem, previousStartLine, currentItem, currentStartLine); - if (rule.Operation.Action & (RuleAction.Space | RuleAction.Delete) && currentStartLine !== previousStartLine) { + if (rule.action & (RuleAction.Space | RuleAction.Delete) && currentStartLine !== previousStartLine) { lineAdded = false; // 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. @@ -927,7 +929,7 @@ namespace ts.formatting { dynamicIndentation.recomputeIndentation(/*lineAddedByFormatting*/ false); } } - else if (rule.Operation.Action & RuleAction.NewLine && currentStartLine === previousStartLine) { + else if (rule.action & RuleAction.NewLine && currentStartLine === previousStartLine) { lineAdded = true; // Handle the case where token2 is moved to the new line. // In this case we indent token2 in the next pass but we set @@ -938,7 +940,7 @@ 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 = !(rule.Operation.Action & RuleAction.Delete) && rule.Flag !== RuleFlags.CanDeleteNewLines; + trimTrailingWhitespaces = !(rule.action & RuleAction.Delete) && rule.flags !== RuleFlags.CanDeleteNewLines; } else { trimTrailingWhitespaces = true; @@ -985,7 +987,7 @@ namespace ts.formatting { return indentationString !== sourceFile.text.substr(startLinePosition, indentationString.length); } - function indentMultilineComment(commentRange: TextRange, indentation: number, firstLineIsIndented: boolean) { + function indentMultilineCommentOrJsxText(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; @@ -1006,7 +1008,9 @@ namespace ts.formatting { startPos = getStartPositionOfLine(line + 1, sourceFile); } - parts.push({ pos: startPos, end: commentRange.end }); + if (indentFinalLine) { + parts.push({ pos: startPos, end: commentRange.end }); + } } const startLinePos = getStartPositionOfLine(startLine, sourceFile); @@ -1111,7 +1115,7 @@ namespace ts.formatting { currentRange: TextRangeWithKind, currentStartLine: number): void { - switch (rule.Operation.Action) { + switch (rule.action) { case RuleAction.Ignore: // no action required return; @@ -1125,7 +1129,7 @@ namespace ts.formatting { // exit early if we on different lines and rule cannot change number of newlines // if line1 and line2 are on subsequent lines then no edits are required - ok to exit // if line1 and line2 are separated with more than one newline - ok to exit since we cannot delete extra new lines - if (rule.Flag !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) { + if (rule.flags !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) { return; } @@ -1137,7 +1141,7 @@ namespace ts.formatting { break; case RuleAction.Space: // exit early if we on different lines and rule cannot change number of newlines - if (rule.Flag !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) { + if (rule.flags !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) { return; } diff --git a/src/services/formatting/formattingContext.ts b/src/services/formatting/formattingContext.ts index 043df72f434..2ba987e4af3 100644 --- a/src/services/formatting/formattingContext.ts +++ b/src/services/formatting/formattingContext.ts @@ -1,7 +1,14 @@ -/// - /* @internal */ namespace ts.formatting { + export const enum FormattingRequestKind { + FormatDocument, + FormatSelection, + FormatOnEnter, + FormatOnSemicolon, + FormatOnOpeningCurlyBrace, + FormatOnClosingCurlyBrace + } + export class FormattingContext { public currentTokenSpan: TextRangeWithKind; public nextTokenSpan: TextRangeWithKind; diff --git a/src/services/formatting/formattingRequestKind.ts b/src/services/formatting/formattingRequestKind.ts deleted file mode 100644 index 6c671e1b888..00000000000 --- a/src/services/formatting/formattingRequestKind.ts +++ /dev/null @@ -1,13 +0,0 @@ -/// - -/* @internal */ -namespace ts.formatting { - export const enum FormattingRequestKind { - FormatDocument, - FormatSelection, - FormatOnEnter, - FormatOnSemicolon, - FormatOnOpeningCurlyBrace, - FormatOnClosingCurlyBrace - } -} \ No newline at end of file diff --git a/src/services/formatting/references.ts b/src/services/formatting/references.ts deleted file mode 100644 index 318f10c664e..00000000000 --- a/src/services/formatting/references.ts +++ /dev/null @@ -1,12 +0,0 @@ -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// \ No newline at end of file diff --git a/src/services/formatting/rule.ts b/src/services/formatting/rule.ts index 10987c745c2..aa1bb6b43e9 100644 --- a/src/services/formatting/rule.ts +++ b/src/services/formatting/rule.ts @@ -1,14 +1,30 @@ -/// - /* @internal */ namespace ts.formatting { - export class Rule { + export interface Rule { // Used for debugging to identify each rule based on the property name it's assigned to. - public debugName?: string; - constructor( - readonly Descriptor: RuleDescriptor, - readonly Operation: RuleOperation, - readonly Flag: RuleFlags = RuleFlags.None) { - } + readonly debugName: string; + readonly context: ReadonlyArray; + readonly action: RuleAction; + readonly flags: RuleFlags; + } + + export type ContextPredicate = (context: FormattingContext) => boolean; + export const anyContext: ReadonlyArray = emptyArray; + + export const enum RuleAction { + Ignore = 1 << 0, + Space = 1 << 1, + NewLine = 1 << 2, + Delete = 1 << 3, + } + + export const enum RuleFlags { + None, + CanDeleteNewLines, + } + + export interface TokenRange { + readonly tokens: ReadonlyArray; + readonly isSpecific: boolean; } } \ No newline at end of file diff --git a/src/services/formatting/ruleAction.ts b/src/services/formatting/ruleAction.ts deleted file mode 100644 index 13e9043e1c6..00000000000 --- a/src/services/formatting/ruleAction.ts +++ /dev/null @@ -1,11 +0,0 @@ -/// - -/* @internal */ -namespace ts.formatting { - export const enum RuleAction { - Ignore = 0x00000001, - Space = 0x00000002, - NewLine = 0x00000004, - Delete = 0x00000008 - } -} \ No newline at end of file diff --git a/src/services/formatting/ruleDescriptor.ts b/src/services/formatting/ruleDescriptor.ts deleted file mode 100644 index 96506adc3dc..00000000000 --- a/src/services/formatting/ruleDescriptor.ts +++ /dev/null @@ -1,30 +0,0 @@ -/// - -/* @internal */ -namespace ts.formatting { - export class RuleDescriptor { - constructor(public LeftTokenRange: Shared.TokenRange, public RightTokenRange: Shared.TokenRange) { - } - - public toString(): string { - return "[leftRange=" + this.LeftTokenRange + "," + - "rightRange=" + this.RightTokenRange + "]"; - } - - static create1(left: SyntaxKind, right: SyntaxKind): RuleDescriptor { - return RuleDescriptor.create4(Shared.TokenRange.FromToken(left), Shared.TokenRange.FromToken(right)); - } - - static create2(left: Shared.TokenRange, right: SyntaxKind): RuleDescriptor { - return RuleDescriptor.create4(left, Shared.TokenRange.FromToken(right)); - } - - static create3(left: SyntaxKind, right: Shared.TokenRange): RuleDescriptor { - return RuleDescriptor.create4(Shared.TokenRange.FromToken(left), right); - } - - static create4(left: Shared.TokenRange, right: Shared.TokenRange): RuleDescriptor { - return new RuleDescriptor(left, right); - } - } -} \ No newline at end of file diff --git a/src/services/formatting/ruleFlag.ts b/src/services/formatting/ruleFlag.ts deleted file mode 100644 index 7619f232ad4..00000000000 --- a/src/services/formatting/ruleFlag.ts +++ /dev/null @@ -1,10 +0,0 @@ -/// - - -/* @internal */ -namespace ts.formatting { - export const enum RuleFlags { - None, - CanDeleteNewLines - } -} \ No newline at end of file diff --git a/src/services/formatting/ruleOperation.ts b/src/services/formatting/ruleOperation.ts deleted file mode 100644 index 8ad83b11653..00000000000 --- a/src/services/formatting/ruleOperation.ts +++ /dev/null @@ -1,21 +0,0 @@ -/// - -/* @internal */ -namespace ts.formatting { - export class RuleOperation { - constructor(public Context: RuleOperationContext, public Action: RuleAction) {} - - public toString(): string { - return "[context=" + this.Context + "," + - "action=" + this.Action + "]"; - } - - static create1(action: RuleAction) { - return RuleOperation.create2(RuleOperationContext.Any, action); - } - - static create2(context: RuleOperationContext, action: RuleAction) { - return new RuleOperation(context, action); - } - } -} \ No newline at end of file diff --git a/src/services/formatting/ruleOperationContext.ts b/src/services/formatting/ruleOperationContext.ts deleted file mode 100644 index bf96363ad7d..00000000000 --- a/src/services/formatting/ruleOperationContext.ts +++ /dev/null @@ -1,32 +0,0 @@ -/// - -/* @internal */ -namespace ts.formatting { - - export class RuleOperationContext { - private readonly customContextChecks: { (context: FormattingContext): boolean; }[]; - - constructor(...funcs: { (context: FormattingContext): boolean; }[]) { - this.customContextChecks = funcs; - } - - static readonly Any: RuleOperationContext = new RuleOperationContext(); - - public IsAny(): boolean { - return this === RuleOperationContext.Any; - } - - public InContext(context: FormattingContext): boolean { - if (this.IsAny()) { - return true; - } - - for (const check of this.customContextChecks) { - if (!check(context)) { - return false; - } - } - return true; - } - } -} \ No newline at end of file diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index d41d9dfbfd8..8214ffd6f2d 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -1,928 +1,723 @@ -/// - /* @internal */ namespace ts.formatting { - export class Rules { - public IgnoreBeforeComment: Rule; - public IgnoreAfterLineComment: Rule; + export interface RuleSpec { + readonly leftTokenRange: TokenRange; + readonly rightTokenRange: TokenRange; + readonly rule: Rule; + } - // Space after keyword but not before ; or : or ? - public NoSpaceBeforeSemicolon: Rule; - public NoSpaceBeforeColon: Rule; - public NoSpaceBeforeQuestionMark: Rule; - public SpaceAfterColon: Rule; - // insert space after '?' only when it is used in conditional operator - public SpaceAfterQuestionMarkInConditionalOperator: Rule; - // in other cases there should be no space between '?' and next token - public NoSpaceAfterQuestionMark: Rule; + export function getAllRules(): RuleSpec[] { + const allTokens: SyntaxKind[] = []; + for (let token = SyntaxKind.FirstToken; token <= SyntaxKind.LastToken; token++) { + allTokens.push(token); + } + function anyTokenExcept(token: SyntaxKind): TokenRange { + return { tokens: allTokens.filter(t => t !== token), isSpecific: false }; + } - public SpaceAfterSemicolon: Rule; + const anyToken: TokenRange = { tokens: allTokens, isSpecific: false }; + const anyTokenIncludingMultilineComments = tokenRangeFrom([...allTokens, SyntaxKind.MultiLineCommentTrivia]); + 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 unaryPrefixExpressions = [ + SyntaxKind.NumericLiteral, SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, + SyntaxKind.OpenBraceToken, 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 comments = [SyntaxKind.SingleLineCommentTrivia, SyntaxKind.MultiLineCommentTrivia]; + const typeNames = [SyntaxKind.Identifier, ...typeKeywords]; - // Space/new line after }. - public SpaceAfterCloseBrace: Rule; - - // 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 }) - public SpaceBetweenCloseBraceAndElse: Rule; - public SpaceBetweenCloseBraceAndWhile: Rule; - public NoSpaceAfterCloseBrace: Rule; - - // No space for dot - public NoSpaceBeforeDot: Rule; - public NoSpaceAfterDot: Rule; - - // No space before and after indexer - public NoSpaceBeforeOpenBracket: Rule; - public NoSpaceAfterCloseBracket: Rule; - - // Insert a space after { and before } in single-line contexts, but remove space from empty object literals {}. - public SpaceAfterOpenBrace: Rule; - public SpaceBeforeCloseBrace: Rule; - public NoSpaceAfterOpenBrace: Rule; - public NoSpaceBeforeCloseBrace: Rule; - public NoSpaceBetweenEmptyBraceBrackets: Rule; - - // Insert new line after { and before } in multi-line contexts. - public NewLineAfterOpenBraceInBlockContext: Rule; - - // For functions and control block place } on a new line [multi-line rule] - public NewLineBeforeCloseBraceInBlockContext: Rule; - - // Special handling of unary operators. - // Prefix operators generally shouldn't have a space between - // them and their target unary expression. - public NoSpaceAfterUnaryPrefixOperator: Rule; - public NoSpaceAfterUnaryPreincrementOperator: Rule; - public NoSpaceAfterUnaryPredecrementOperator: Rule; - public NoSpaceBeforeUnaryPostincrementOperator: Rule; - public NoSpaceBeforeUnaryPostdecrementOperator: Rule; - - // 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 - public SpaceAfterPostincrementWhenFollowedByAdd: Rule; - public SpaceAfterAddWhenFollowedByUnaryPlus: Rule; - public SpaceAfterAddWhenFollowedByPreincrement: Rule; - public SpaceAfterPostdecrementWhenFollowedBySubtract: Rule; - public SpaceAfterSubtractWhenFollowedByUnaryMinus: Rule; - public SpaceAfterSubtractWhenFollowedByPredecrement: Rule; - - public NoSpaceBeforeComma: Rule; - - public SpaceAfterCertainKeywords: Rule; - public NoSpaceAfterNewKeywordOnConstructorSignature: Rule; - public SpaceAfterLetConstInVariableDeclaration: Rule; - public NoSpaceBeforeOpenParenInFuncCall: Rule; - public SpaceAfterFunctionInFuncDecl: Rule; - public SpaceBeforeOpenParenInFuncDecl: Rule; - public NoSpaceBeforeOpenParenInFuncDecl: Rule; - public SpaceAfterVoidOperator: Rule; - - public NoSpaceBetweenReturnAndSemicolon: Rule; - - // 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] - public SpaceBetweenStatements: Rule; - - // This low-pri rule takes care of "try {" and "finally {" in case the rule SpaceBeforeOpenBraceInControl didn't execute on FormatOnEnter. - public SpaceAfterTryFinally: Rule; - - // 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) {} - public SpaceAfterGetSetInMember: Rule; - - // Special case for binary operators (that are keywords). For these we have to add a space and shouldn't follow any user options. - public SpaceBeforeBinaryKeywordOperator: Rule; - public SpaceAfterBinaryKeywordOperator: Rule; - - // TypeScript-specific rules - - // Treat constructor as an identifier in a function declaration, and remove spaces between constructor and following left parentheses - public SpaceAfterConstructor: Rule; - public NoSpaceAfterConstructor: Rule; - - // Use of module as a function call. e.g.: import m2 = module("m2"); - public NoSpaceAfterModuleImport: Rule; - - // Add a space around certain TypeScript keywords - public SpaceAfterCertainTypeScriptKeywords: Rule; - public SpaceBeforeCertainTypeScriptKeywords: Rule; - - // Treat string literals in module names as identifiers, and add a space between the literal and the opening Brace braces, e.g.: module "m2" { - public SpaceAfterModuleName: Rule; - - // Lambda expressions - public SpaceBeforeArrow: Rule; - public SpaceAfterArrow: Rule; - - // Optional parameters and let args - public NoSpaceAfterEllipsis: Rule; - public NoSpaceAfterOptionalParameters: Rule; - - // generics - public NoSpaceBeforeOpenAngularBracket: Rule; - public NoSpaceBetweenCloseParenAndAngularBracket: Rule; - public NoSpaceAfterOpenAngularBracket: Rule; - public NoSpaceBeforeCloseAngularBracket: Rule; - public NoSpaceAfterCloseAngularBracket: Rule; - - // Remove spaces in empty interface literals. e.g.: x: {} - public NoSpaceBetweenEmptyInterfaceBraceBrackets: Rule; - - // These rules are higher in priority than user-configurable rules. - public HighPriorityCommonRules: Rule[]; - - // These rules are applied after high priority rules. - public UserConfigurableRules: Rule[]; - - // These rules are lower in priority than user-configurable rules. - public LowPriorityCommonRules: Rule[]; - - /// - /// Rules controlled by user options - /// - - // Insert space after comma delimiter - public SpaceAfterComma: Rule; - public NoSpaceAfterComma: Rule; - - // Insert space before and after binary operators - public SpaceBeforeBinaryOperator: Rule; - public SpaceAfterBinaryOperator: Rule; - public NoSpaceBeforeBinaryOperator: Rule; - public NoSpaceAfterBinaryOperator: Rule; - - // Insert space after keywords in control flow statements - public SpaceAfterKeywordInControl: Rule; - public NoSpaceAfterKeywordInControl: Rule; - - // Open Brace braces after function + // Place a space before open brace in a function declaration // TypeScript: Function can have return types, which can be made of tons of different token kinds - public FunctionOpenBraceLeftTokenRange: Shared.TokenRange; - public SpaceBeforeOpenBraceInFunction: Rule; - public NewLineBeforeOpenBraceInFunction: Rule; + const functionOpenBraceLeftTokenRange = anyTokenIncludingMultilineComments; - // Open Brace braces after TypeScript module/class/interface - public TypeScriptOpenBraceLeftTokenRange: Shared.TokenRange; - public SpaceBeforeOpenBraceInTypeScriptDeclWithBlock: Rule; - public NewLineBeforeOpenBraceInTypeScriptDeclWithBlock: Rule; + // 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]); - // Open Brace braces after control block - public ControlOpenBraceLeftTokenRange: Shared.TokenRange; - public SpaceBeforeOpenBraceInControl: Rule; - public NewLineBeforeOpenBraceInControl: Rule; - - // Insert space after semicolon in for statement - public SpaceAfterSemicolonInFor: Rule; - public NoSpaceAfterSemicolonInFor: Rule; - - // Insert space after opening and before closing nonempty parenthesis - public SpaceAfterOpenParen: Rule; - public SpaceBeforeCloseParen: Rule; - public SpaceBetweenOpenParens: Rule; - public NoSpaceBetweenParens: Rule; - public NoSpaceAfterOpenParen: Rule; - public NoSpaceBeforeCloseParen: Rule; - - // Insert space after opening and before closing nonempty brackets - public SpaceAfterOpenBracket: Rule; - public SpaceBeforeCloseBracket: Rule; - public NoSpaceBetweenBrackets: Rule; - public NoSpaceAfterOpenBracket: Rule; - public NoSpaceBeforeCloseBracket: Rule; - - // Insert space after function keyword for anonymous functions - public SpaceAfterAnonymousFunctionKeyword: Rule; - public NoSpaceAfterAnonymousFunctionKeyword: Rule; - - // Insert space after @ in decorator - public SpaceBeforeAt: Rule; - public NoSpaceAfterAt: Rule; - public SpaceAfterDecorator: Rule; - - // Generator: function* - public NoSpaceBetweenFunctionKeywordAndStar: Rule; - public SpaceAfterStarInGeneratorDeclaration: Rule; - public NoSpaceBetweenYieldKeywordAndStar: Rule; - public SpaceBetweenYieldOrYieldStarAndOperand: Rule; - - // Async functions - public SpaceBetweenAsyncAndOpenParen: Rule; - public SpaceBetweenAsyncAndFunctionKeyword: Rule; - - // Template strings - public NoSpaceBetweenTagAndTemplateString: Rule; - public NoSpaceAfterTemplateHeadAndMiddle: Rule; - public SpaceAfterTemplateHeadAndMiddle: Rule; - public NoSpaceBeforeTemplateMiddleAndTail: Rule; - public SpaceBeforeTemplateMiddleAndTail: Rule; - - // No space after { and before } in JSX expression - public NoSpaceAfterOpenBraceInJsxExpression: Rule; - public SpaceAfterOpenBraceInJsxExpression: Rule; - public NoSpaceBeforeCloseBraceInJsxExpression: Rule; - public SpaceBeforeCloseBraceInJsxExpression: Rule; - - // JSX opening elements - public SpaceBeforeJsxAttribute: Rule; - public SpaceBeforeSlashInJsxOpeningElement: Rule; - public NoSpaceBeforeGreaterThanTokenInJsxOpeningElement: Rule; - public NoSpaceBeforeEqualInJsxAttribute: Rule; - public NoSpaceAfterEqualInJsxAttribute: Rule; - - // No space after type assertions - public NoSpaceAfterTypeAssertion: Rule; - public SpaceAfterTypeAssertion: Rule; - - // No space before non-null assertion operator - public NoSpaceBeforeNonNullAssertionOperator: Rule; - - constructor() { - /// - /// Common Rules - /// + // 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]); + // These rules are higher in priority than user-configurable + const highPriorityCommonRules = [ // Leave comments alone - this.IgnoreBeforeComment = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.Comments), RuleOperation.create1(RuleAction.Ignore)); - this.IgnoreAfterLineComment = new Rule(RuleDescriptor.create3(SyntaxKind.SingleLineCommentTrivia, Shared.TokenRange.Any), RuleOperation.create1(RuleAction.Ignore)); + rule("IgnoreBeforeComment", anyToken, comments, anyContext, RuleAction.Ignore), + rule("IgnoreAfterLineComment", SyntaxKind.SingleLineCommentTrivia, anyToken, anyContext, RuleAction.Ignore), - // Space after keyword but not before ; or : or ? - this.NoSpaceBeforeSemicolon = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.SemicolonToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - this.NoSpaceBeforeColon = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.ColonToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete)); - this.NoSpaceBeforeQuestionMark = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.QuestionToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete)); - this.SpaceAfterColon = new Rule(RuleDescriptor.create3(SyntaxKind.ColonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Space)); - this.SpaceAfterQuestionMarkInConditionalOperator = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsConditionalOperatorContext), RuleAction.Space)); - this.NoSpaceAfterQuestionMark = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - this.SpaceAfterSemicolon = new Rule(RuleDescriptor.create3(SyntaxKind.SemicolonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); + rule("NoSpaceBeforeColon", anyToken, SyntaxKind.ColonToken, [isNonJsxSameLineTokenContext, isNotBinaryOpContext], RuleAction.Delete), + rule("SpaceAfterColon", SyntaxKind.ColonToken, anyToken, [isNonJsxSameLineTokenContext, isNotBinaryOpContext], RuleAction.Space), + rule("NoSpaceBeforeQuestionMark", anyToken, SyntaxKind.QuestionToken, [isNonJsxSameLineTokenContext, isNotBinaryOpContext], RuleAction.Delete), + // insert space after '?' only when it is used in conditional operator + rule("SpaceAfterQuestionMarkInConditionalOperator", SyntaxKind.QuestionToken, anyToken, [isNonJsxSameLineTokenContext, isConditionalOperatorContext], RuleAction.Space), - // Space after }. - this.SpaceAfterCloseBrace = new Rule(RuleDescriptor.create3(SyntaxKind.CloseBraceToken, Shared.TokenRange.FromRange(SyntaxKind.FirstToken, SyntaxKind.LastToken, [SyntaxKind.CloseParenToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsAfterCodeBlockContext), RuleAction.Space)); + // in other cases there should be no space between '?' and next token + rule("NoSpaceAfterQuestionMark", SyntaxKind.QuestionToken, anyToken, [isNonJsxSameLineTokenContext], RuleAction.Delete), - // Special case for (}, else) and (}, while) since else & while tokens are not part of the tree which makes SpaceAfterCloseBrace rule not applied - this.SpaceBetweenCloseBraceAndElse = new Rule(RuleDescriptor.create1(SyntaxKind.CloseBraceToken, SyntaxKind.ElseKeyword), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); - this.SpaceBetweenCloseBraceAndWhile = new Rule(RuleDescriptor.create1(SyntaxKind.CloseBraceToken, SyntaxKind.WhileKeyword), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); - this.NoSpaceAfterCloseBrace = new Rule(RuleDescriptor.create3(SyntaxKind.CloseBraceToken, Shared.TokenRange.FromTokens([SyntaxKind.CloseBracketToken, SyntaxKind.CommaToken, SyntaxKind.SemicolonToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - - // No space for dot - this.NoSpaceBeforeDot = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.DotToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - this.NoSpaceAfterDot = new Rule(RuleDescriptor.create3(SyntaxKind.DotToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - - // No space before and after indexer - this.NoSpaceBeforeOpenBracket = new Rule( - RuleDescriptor.create2(Shared.TokenRange.AnyExcept(SyntaxKind.AsyncKeyword), SyntaxKind.OpenBracketToken), - RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - this.NoSpaceAfterCloseBracket = new Rule(RuleDescriptor.create3(SyntaxKind.CloseBracketToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsNotBeforeBlockInFunctionDeclarationContext), RuleAction.Delete)); - - // Place a space before open brace in a function declaration - this.FunctionOpenBraceLeftTokenRange = Shared.TokenRange.AnyIncludingMultilineComments; - this.SpaceBeforeOpenBraceInFunction = new Rule(RuleDescriptor.create2(this.FunctionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForFunctions"), Rules.IsFunctionDeclContext, Rules.IsBeforeBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines); - - // Place a space before open brace in a TypeScript declaration that has braces as children (class, module, enum, etc) - this.TypeScriptOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.MultiLineCommentTrivia, SyntaxKind.ClassKeyword, SyntaxKind.ExportKeyword, SyntaxKind.ImportKeyword]); - this.SpaceBeforeOpenBraceInTypeScriptDeclWithBlock = new Rule(RuleDescriptor.create2(this.TypeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForFunctions"), Rules.IsTypeScriptDeclWithBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines); - - // Place a space before open brace in a control flow construct - this.ControlOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.MultiLineCommentTrivia, SyntaxKind.DoKeyword, SyntaxKind.TryKeyword, SyntaxKind.FinallyKeyword, SyntaxKind.ElseKeyword]); - this.SpaceBeforeOpenBraceInControl = new Rule(RuleDescriptor.create2(this.ControlOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForControlBlocks"), Rules.IsControlDeclContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines); - - // Insert a space after { and before } in single-line contexts, but remove space from empty object literals {}. - this.SpaceAfterOpenBrace = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), Rules.IsBraceWrappedContext), RuleAction.Space)); - this.SpaceBeforeCloseBrace = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), Rules.IsBraceWrappedContext), RuleAction.Space)); - this.NoSpaceAfterOpenBrace = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - this.NoSpaceBeforeCloseBrace = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - this.NoSpaceBetweenEmptyBraceBrackets = new Rule(RuleDescriptor.create1(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsObjectContext), RuleAction.Delete)); - - // Insert new line after { and before } in multi-line contexts. - this.NewLineAfterOpenBraceInBlockContext = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsMultilineBlockContext), RuleAction.NewLine)); - - // For functions and control block place } on a new line [multi-line rule] - this.NewLineBeforeCloseBraceInBlockContext = new Rule(RuleDescriptor.create2(Shared.TokenRange.AnyIncludingMultilineComments, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsMultilineBlockContext), RuleAction.NewLine)); + rule("NoSpaceBeforeDot", anyToken, SyntaxKind.DotToken, [isNonJsxSameLineTokenContext], RuleAction.Delete), + rule("NoSpaceAfterDot", SyntaxKind.DotToken, anyToken, [isNonJsxSameLineTokenContext], RuleAction.Delete), // Special handling of unary operators. // Prefix operators generally shouldn't have a space between // them and their target unary expression. - this.NoSpaceAfterUnaryPrefixOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.UnaryPrefixOperators, Shared.TokenRange.UnaryPrefixExpressions), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete)); - this.NoSpaceAfterUnaryPreincrementOperator = new Rule(RuleDescriptor.create3(SyntaxKind.PlusPlusToken, Shared.TokenRange.UnaryPreincrementExpressions), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - this.NoSpaceAfterUnaryPredecrementOperator = new Rule(RuleDescriptor.create3(SyntaxKind.MinusMinusToken, Shared.TokenRange.UnaryPredecrementExpressions), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - this.NoSpaceBeforeUnaryPostincrementOperator = new Rule(RuleDescriptor.create2(Shared.TokenRange.UnaryPostincrementExpressions, SyntaxKind.PlusPlusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - this.NoSpaceBeforeUnaryPostdecrementOperator = new Rule(RuleDescriptor.create2(Shared.TokenRange.UnaryPostdecrementExpressions, SyntaxKind.MinusMinusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); + rule("NoSpaceAfterUnaryPrefixOperator", unaryPrefixOperators, unaryPrefixExpressions, [isNonJsxSameLineTokenContext, isNotBinaryOpContext], RuleAction.Delete), + rule("NoSpaceAfterUnaryPreincrementOperator", SyntaxKind.PlusPlusToken, unaryPreincrementExpressions, [isNonJsxSameLineTokenContext], RuleAction.Delete), + rule("NoSpaceAfterUnaryPredecrementOperator", SyntaxKind.MinusMinusToken, unaryPredecrementExpressions, [isNonJsxSameLineTokenContext], RuleAction.Delete), + rule("NoSpaceBeforeUnaryPostincrementOperator", unaryPostincrementExpressions, SyntaxKind.PlusPlusToken, [isNonJsxSameLineTokenContext], RuleAction.Delete), + rule("NoSpaceBeforeUnaryPostdecrementOperator", unaryPostdecrementExpressions, SyntaxKind.MinusMinusToken, [isNonJsxSameLineTokenContext], RuleAction.Delete), // 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 - this.SpaceAfterPostincrementWhenFollowedByAdd = new Rule(RuleDescriptor.create1(SyntaxKind.PlusPlusToken, SyntaxKind.PlusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); - this.SpaceAfterAddWhenFollowedByUnaryPlus = new Rule(RuleDescriptor.create1(SyntaxKind.PlusToken, SyntaxKind.PlusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); - this.SpaceAfterAddWhenFollowedByPreincrement = new Rule(RuleDescriptor.create1(SyntaxKind.PlusToken, SyntaxKind.PlusPlusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); - this.SpaceAfterPostdecrementWhenFollowedBySubtract = new Rule(RuleDescriptor.create1(SyntaxKind.MinusMinusToken, SyntaxKind.MinusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); - this.SpaceAfterSubtractWhenFollowedByUnaryMinus = new Rule(RuleDescriptor.create1(SyntaxKind.MinusToken, SyntaxKind.MinusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); - this.SpaceAfterSubtractWhenFollowedByPredecrement = new Rule(RuleDescriptor.create1(SyntaxKind.MinusToken, SyntaxKind.MinusMinusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + rule("SpaceAfterPostincrementWhenFollowedByAdd", SyntaxKind.PlusPlusToken, SyntaxKind.PlusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Space), + rule("SpaceAfterAddWhenFollowedByUnaryPlus", SyntaxKind.PlusToken, SyntaxKind.PlusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Space), + rule("SpaceAfterAddWhenFollowedByPreincrement", SyntaxKind.PlusToken, SyntaxKind.PlusPlusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Space), + rule("SpaceAfterPostdecrementWhenFollowedBySubtract", SyntaxKind.MinusMinusToken, SyntaxKind.MinusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Space), + rule("SpaceAfterSubtractWhenFollowedByUnaryMinus", SyntaxKind.MinusToken, SyntaxKind.MinusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Space), + rule("SpaceAfterSubtractWhenFollowedByPredecrement", SyntaxKind.MinusToken, SyntaxKind.MinusMinusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Space), - this.NoSpaceBeforeComma = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CommaToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); + rule("NoSpaceAfterCloseBrace", SyntaxKind.CloseBraceToken, [SyntaxKind.CloseBracketToken, SyntaxKind.CommaToken, SyntaxKind.SemicolonToken], [isNonJsxSameLineTokenContext], RuleAction.Delete), + // For functions and control block place } on a new line [multi-line rule] + rule("NewLineBeforeCloseBraceInBlockContext", anyTokenIncludingMultilineComments, SyntaxKind.CloseBraceToken, [isMultilineBlockContext], RuleAction.NewLine), - this.SpaceAfterCertainKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.VarKeyword, SyntaxKind.ThrowKeyword, SyntaxKind.NewKeyword, SyntaxKind.DeleteKeyword, SyntaxKind.ReturnKeyword, SyntaxKind.TypeOfKeyword, SyntaxKind.AwaitKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); - this.NoSpaceAfterNewKeywordOnConstructorSignature = new Rule(RuleDescriptor.create1(SyntaxKind.NewKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsConstructorSignatureContext), RuleAction.Delete)); - this.SpaceAfterLetConstInVariableDeclaration = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.LetKeyword, SyntaxKind.ConstKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsStartOfVariableDeclarationList), RuleAction.Space)); - this.NoSpaceBeforeOpenParenInFuncCall = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsFunctionCallOrNewContext, Rules.IsPreviousTokenNotComma), RuleAction.Delete)); - this.SpaceAfterFunctionInFuncDecl = new Rule(RuleDescriptor.create3(SyntaxKind.FunctionKeyword, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space)); - this.SpaceBeforeOpenParenInFuncDecl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceBeforeFunctionParenthesis"), Rules.IsNonJsxSameLineTokenContext, Rules.IsFunctionDeclContext), RuleAction.Space)); - this.NoSpaceBeforeOpenParenInFuncDecl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceBeforeFunctionParenthesis"), Rules.IsNonJsxSameLineTokenContext, Rules.IsFunctionDeclContext), RuleAction.Delete)); - this.SpaceAfterVoidOperator = new Rule(RuleDescriptor.create3(SyntaxKind.VoidKeyword, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsVoidOpContext), RuleAction.Space)); + // Space/new line after }. + rule("SpaceAfterCloseBrace", SyntaxKind.CloseBraceToken, anyTokenExcept(SyntaxKind.CloseParenToken), [isNonJsxSameLineTokenContext, isAfterCodeBlockContext], RuleAction.Space), + // 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.Space), + rule("SpaceBetweenCloseBraceAndWhile", SyntaxKind.CloseBraceToken, SyntaxKind.WhileKeyword, [isNonJsxSameLineTokenContext], RuleAction.Space), + rule("NoSpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [isNonJsxSameLineTokenContext, isObjectContext], RuleAction.Delete), - this.NoSpaceBetweenReturnAndSemicolon = new Rule(RuleDescriptor.create1(SyntaxKind.ReturnKeyword, SyntaxKind.SemicolonToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); + rule("NoSpaceBetweenFunctionKeywordAndStar", SyntaxKind.FunctionKeyword, SyntaxKind.AsteriskToken, [isFunctionDeclarationOrFunctionExpressionContext], RuleAction.Delete), + rule("SpaceAfterStarInGeneratorDeclaration", SyntaxKind.AsteriskToken, [SyntaxKind.Identifier, SyntaxKind.OpenParenToken], [isFunctionDeclarationOrFunctionExpressionContext], RuleAction.Space), - // 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] - this.SpaceBetweenStatements = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.DoKeyword, SyntaxKind.ElseKeyword, SyntaxKind.CaseKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsNonJsxElementContext, Rules.IsNotForContext), RuleAction.Space)); - - // This low-pri rule takes care of "try {" and "finally {" in case the rule SpaceBeforeOpenBraceInControl didn't execute on FormatOnEnter. - this.SpaceAfterTryFinally = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.TryKeyword, SyntaxKind.FinallyKeyword]), SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); + rule("SpaceAfterFunctionInFuncDecl", SyntaxKind.FunctionKeyword, anyToken, [isFunctionDeclContext], RuleAction.Space), + // Insert new line after { and before } in multi-line contexts. + rule("NewLineAfterOpenBraceInBlockContext", SyntaxKind.OpenBraceToken, anyToken, [isMultilineBlockContext], RuleAction.NewLine), + // 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) {} - this.SpaceAfterGetSetInMember = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.GetKeyword, SyntaxKind.SetKeyword]), SyntaxKind.Identifier), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space)); + rule("SpaceAfterGetSetInMember", [SyntaxKind.GetKeyword, SyntaxKind.SetKeyword], SyntaxKind.Identifier, [isFunctionDeclContext], RuleAction.Space), + + rule("NoSpaceBetweenYieldKeywordAndStar", SyntaxKind.YieldKeyword, SyntaxKind.AsteriskToken, [isNonJsxSameLineTokenContext, isYieldOrYieldStarWithOperand], RuleAction.Delete), + rule("SpaceBetweenYieldOrYieldStarAndOperand", [SyntaxKind.YieldKeyword, SyntaxKind.AsteriskToken], anyToken, [isNonJsxSameLineTokenContext, isYieldOrYieldStarWithOperand], RuleAction.Space), + + rule("NoSpaceBetweenReturnAndSemicolon", SyntaxKind.ReturnKeyword, SyntaxKind.SemicolonToken, [isNonJsxSameLineTokenContext], RuleAction.Delete), + rule("SpaceAfterCertainKeywords", [SyntaxKind.VarKeyword, SyntaxKind.ThrowKeyword, SyntaxKind.NewKeyword, SyntaxKind.DeleteKeyword, SyntaxKind.ReturnKeyword, SyntaxKind.TypeOfKeyword, SyntaxKind.AwaitKeyword], anyToken, [isNonJsxSameLineTokenContext], RuleAction.Space), + rule("SpaceAfterLetConstInVariableDeclaration", [SyntaxKind.LetKeyword, SyntaxKind.ConstKeyword], anyToken, [isNonJsxSameLineTokenContext, isStartOfVariableDeclarationList], RuleAction.Space), + rule("NoSpaceBeforeOpenParenInFuncCall", anyToken, SyntaxKind.OpenParenToken, [isNonJsxSameLineTokenContext, isFunctionCallOrNewContext, isPreviousTokenNotComma], RuleAction.Delete), // Special case for binary operators (that are keywords). For these we have to add a space and shouldn't follow any user options. - this.SpaceBeforeBinaryKeywordOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryKeywordOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); - this.SpaceAfterBinaryKeywordOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.BinaryKeywordOperators, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + rule("SpaceBeforeBinaryKeywordOperator", anyToken, binaryKeywordOperators, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Space), + rule("SpaceAfterBinaryKeywordOperator", binaryKeywordOperators, anyToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Space), - // TypeScript-specific higher priority rules - - this.SpaceAfterConstructor = new Rule(RuleDescriptor.create1(SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterConstructor"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); - this.NoSpaceAfterConstructor = new Rule(RuleDescriptor.create1(SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterConstructor"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - - // Use of module as a function call. e.g.: import m2 = module("m2"); - this.NoSpaceAfterModuleImport = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.ModuleKeyword, SyntaxKind.RequireKeyword]), SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - - // Add a space around certain TypeScript keywords - this.SpaceAfterCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.AbstractKeyword, SyntaxKind.ClassKeyword, SyntaxKind.DeclareKeyword, SyntaxKind.DefaultKeyword, SyntaxKind.EnumKeyword, SyntaxKind.ExportKeyword, SyntaxKind.ExtendsKeyword, SyntaxKind.GetKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.ImportKeyword, SyntaxKind.InterfaceKeyword, SyntaxKind.ModuleKeyword, SyntaxKind.NamespaceKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.PublicKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.ReadonlyKeyword, SyntaxKind.SetKeyword, SyntaxKind.StaticKeyword, SyntaxKind.TypeKeyword, SyntaxKind.FromKeyword, SyntaxKind.KeyOfKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); - this.SpaceBeforeCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.ExtendsKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.FromKeyword])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); - - // Treat string literals in module names as identifiers, and add a space between the literal and the opening Brace braces, e.g.: module "m2" { - this.SpaceAfterModuleName = new Rule(RuleDescriptor.create1(SyntaxKind.StringLiteral, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsModuleDeclContext), RuleAction.Space)); - - // Lambda expressions - this.SpaceBeforeArrow = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.EqualsGreaterThanToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); - this.SpaceAfterArrow = new Rule(RuleDescriptor.create3(SyntaxKind.EqualsGreaterThanToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); - - // Optional parameters and let args - this.NoSpaceAfterEllipsis = new Rule(RuleDescriptor.create1(SyntaxKind.DotDotDotToken, SyntaxKind.Identifier), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - this.NoSpaceAfterOptionalParameters = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.CommaToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete)); - - // generics and type assertions - this.NoSpaceBeforeOpenAngularBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.TypeNames, SyntaxKind.LessThanToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsTypeArgumentOrParameterOrAssertionContext), RuleAction.Delete)); - this.NoSpaceBetweenCloseParenAndAngularBracket = new Rule(RuleDescriptor.create1(SyntaxKind.CloseParenToken, SyntaxKind.LessThanToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsTypeArgumentOrParameterOrAssertionContext), RuleAction.Delete)); - this.NoSpaceAfterOpenAngularBracket = new Rule(RuleDescriptor.create3(SyntaxKind.LessThanToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsTypeArgumentOrParameterOrAssertionContext), RuleAction.Delete)); - this.NoSpaceBeforeCloseAngularBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.GreaterThanToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsTypeArgumentOrParameterOrAssertionContext), RuleAction.Delete)); - this.NoSpaceAfterCloseAngularBracket = new Rule(RuleDescriptor.create3(SyntaxKind.GreaterThanToken, Shared.TokenRange.FromTokens([SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.GreaterThanToken, SyntaxKind.CommaToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsTypeArgumentOrParameterOrAssertionContext), RuleAction.Delete)); - - // Remove spaces in empty interface literals. e.g.: x: {} - this.NoSpaceBetweenEmptyInterfaceBraceBrackets = new Rule(RuleDescriptor.create1(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsObjectTypeContext), RuleAction.Delete)); - - // decorators - this.SpaceBeforeAt = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.AtToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); - this.NoSpaceAfterAt = new Rule(RuleDescriptor.create3(SyntaxKind.AtToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - this.SpaceAfterDecorator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.AbstractKeyword, SyntaxKind.Identifier, SyntaxKind.ExportKeyword, SyntaxKind.DefaultKeyword, SyntaxKind.ClassKeyword, SyntaxKind.StaticKeyword, SyntaxKind.PublicKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.GetKeyword, SyntaxKind.SetKeyword, SyntaxKind.OpenBracketToken, SyntaxKind.AsteriskToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsEndOfDecoratorContextOnSameLine), RuleAction.Space)); - - this.NoSpaceBetweenFunctionKeywordAndStar = new Rule(RuleDescriptor.create1(SyntaxKind.FunctionKeyword, SyntaxKind.AsteriskToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclarationOrFunctionExpressionContext), RuleAction.Delete)); - this.SpaceAfterStarInGeneratorDeclaration = new Rule(RuleDescriptor.create3(SyntaxKind.AsteriskToken, Shared.TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.OpenParenToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclarationOrFunctionExpressionContext), RuleAction.Space)); - this.NoSpaceBetweenYieldKeywordAndStar = new Rule(RuleDescriptor.create1(SyntaxKind.YieldKeyword, SyntaxKind.AsteriskToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsYieldOrYieldStarWithOperand), RuleAction.Delete)); - this.SpaceBetweenYieldOrYieldStarAndOperand = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.YieldKeyword, SyntaxKind.AsteriskToken]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsYieldOrYieldStarWithOperand), RuleAction.Space)); + rule("SpaceAfterVoidOperator", SyntaxKind.VoidKeyword, anyToken, [isNonJsxSameLineTokenContext, isVoidOpContext], RuleAction.Space), // Async-await - this.SpaceBetweenAsyncAndOpenParen = new Rule(RuleDescriptor.create1(SyntaxKind.AsyncKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsArrowFunctionContext, Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); - this.SpaceBetweenAsyncAndFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.AsyncKeyword, SyntaxKind.FunctionKeyword), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); + rule("SpaceBetweenAsyncAndOpenParen", SyntaxKind.AsyncKeyword, SyntaxKind.OpenParenToken, [isArrowFunctionContext, isNonJsxSameLineTokenContext], RuleAction.Space), + rule("SpaceBetweenAsyncAndFunctionKeyword", SyntaxKind.AsyncKeyword, SyntaxKind.FunctionKeyword, [isNonJsxSameLineTokenContext], RuleAction.Space), // template string - this.NoSpaceBetweenTagAndTemplateString = new Rule(RuleDescriptor.create3(SyntaxKind.Identifier, Shared.TokenRange.FromTokens([SyntaxKind.NoSubstitutionTemplateLiteral, SyntaxKind.TemplateHead])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); + rule("NoSpaceBetweenTagAndTemplateString", SyntaxKind.Identifier, [SyntaxKind.NoSubstitutionTemplateLiteral, SyntaxKind.TemplateHead], [isNonJsxSameLineTokenContext], RuleAction.Delete), - // jsx opening element - this.SpaceBeforeJsxAttribute = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.Identifier), RuleOperation.create2(new RuleOperationContext(Rules.IsNextTokenParentJsxAttribute, Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); - this.SpaceBeforeSlashInJsxOpeningElement = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.SlashToken), RuleOperation.create2(new RuleOperationContext(Rules.IsJsxSelfClosingElementContext, Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); - this.NoSpaceBeforeGreaterThanTokenInJsxOpeningElement = new Rule(RuleDescriptor.create1(SyntaxKind.SlashToken, SyntaxKind.GreaterThanToken), RuleOperation.create2(new RuleOperationContext(Rules.IsJsxSelfClosingElementContext, Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - this.NoSpaceBeforeEqualInJsxAttribute = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.EqualsToken), RuleOperation.create2(new RuleOperationContext(Rules.IsJsxAttributeContext, Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - this.NoSpaceAfterEqualInJsxAttribute = new Rule(RuleDescriptor.create3(SyntaxKind.EqualsToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsJsxAttributeContext, Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); + // JSX opening elements + rule("SpaceBeforeJsxAttribute", anyToken, SyntaxKind.Identifier, [isNextTokenParentJsxAttribute, isNonJsxSameLineTokenContext], RuleAction.Space), + rule("SpaceBeforeSlashInJsxOpeningElement", anyToken, SyntaxKind.SlashToken, [isJsxSelfClosingElementContext, isNonJsxSameLineTokenContext], RuleAction.Space), + rule("NoSpaceBeforeGreaterThanTokenInJsxOpeningElement", SyntaxKind.SlashToken, SyntaxKind.GreaterThanToken, [isJsxSelfClosingElementContext, isNonJsxSameLineTokenContext], RuleAction.Delete), + rule("NoSpaceBeforeEqualInJsxAttribute", anyToken, SyntaxKind.EqualsToken, [isJsxAttributeContext, isNonJsxSameLineTokenContext], RuleAction.Delete), + rule("NoSpaceAfterEqualInJsxAttribute", SyntaxKind.EqualsToken, anyToken, [isJsxAttributeContext, isNonJsxSameLineTokenContext], RuleAction.Delete), - // No space before non-null assertion operator - this.NoSpaceBeforeNonNullAssertionOperator = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.ExclamationToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsNonNullAssertionContext), RuleAction.Delete)); + // 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.Delete), + // Add a space around certain TypeScript keywords + rule( + "SpaceAfterCertainTypeScriptKeywords", + [ + SyntaxKind.AbstractKeyword, + SyntaxKind.ClassKeyword, + SyntaxKind.DeclareKeyword, + SyntaxKind.DefaultKeyword, + SyntaxKind.EnumKeyword, + SyntaxKind.ExportKeyword, + SyntaxKind.ExtendsKeyword, + SyntaxKind.GetKeyword, + SyntaxKind.ImplementsKeyword, + SyntaxKind.ImportKeyword, + SyntaxKind.InterfaceKeyword, + SyntaxKind.ModuleKeyword, + SyntaxKind.NamespaceKeyword, + SyntaxKind.PrivateKeyword, + SyntaxKind.PublicKeyword, + SyntaxKind.ProtectedKeyword, + SyntaxKind.ReadonlyKeyword, + SyntaxKind.SetKeyword, + SyntaxKind.StaticKeyword, + SyntaxKind.TypeKeyword, + SyntaxKind.FromKeyword, + SyntaxKind.KeyOfKeyword, + ], + anyToken, + [isNonJsxSameLineTokenContext], + RuleAction.Space), + rule( + "SpaceBeforeCertainTypeScriptKeywords", + anyToken, + [SyntaxKind.ExtendsKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.FromKeyword], + [isNonJsxSameLineTokenContext], + RuleAction.Space), + // 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.Space), - /// - /// Rules controlled by user options - /// + // Lambda expressions + rule("SpaceBeforeArrow", anyToken, SyntaxKind.EqualsGreaterThanToken, [isNonJsxSameLineTokenContext], RuleAction.Space), + rule("SpaceAfterArrow", SyntaxKind.EqualsGreaterThanToken, anyToken, [isNonJsxSameLineTokenContext], RuleAction.Space), - // Insert space after comma delimiter - this.SpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterCommaDelimiter"), Rules.IsNonJsxSameLineTokenContext, Rules.IsNonJsxElementContext, Rules.IsNextTokenNotCloseBracket), RuleAction.Space)); - this.NoSpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterCommaDelimiter"), Rules.IsNonJsxSameLineTokenContext, Rules.IsNonJsxElementContext), RuleAction.Delete)); + // Optional parameters and let args + rule("NoSpaceAfterEllipsis", SyntaxKind.DotDotDotToken, SyntaxKind.Identifier, [isNonJsxSameLineTokenContext], RuleAction.Delete), + rule("NoSpaceAfterOptionalParameters", SyntaxKind.QuestionToken, [SyntaxKind.CloseParenToken, SyntaxKind.CommaToken], [isNonJsxSameLineTokenContext, isNotBinaryOpContext], RuleAction.Delete), - // Insert space before and after binary operators - this.SpaceBeforeBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceBeforeAndAfterBinaryOperators"), Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); - this.SpaceAfterBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.BinaryOperators, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceBeforeAndAfterBinaryOperators"), Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); - this.NoSpaceBeforeBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceBeforeAndAfterBinaryOperators"), Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Delete)); - this.NoSpaceAfterBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.BinaryOperators, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceBeforeAndAfterBinaryOperators"), Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Delete)); + // Remove spaces in empty interface literals. e.g.: x: {} + rule("NoSpaceBetweenEmptyInterfaceBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [isNonJsxSameLineTokenContext, isObjectTypeContext], RuleAction.Delete), + + // generics and type assertions + rule("NoSpaceBeforeOpenAngularBracket", typeNames, SyntaxKind.LessThanToken, [isNonJsxSameLineTokenContext, isTypeArgumentOrParameterOrAssertionContext], RuleAction.Delete), + rule("NoSpaceBetweenCloseParenAndAngularBracket", SyntaxKind.CloseParenToken, SyntaxKind.LessThanToken, [isNonJsxSameLineTokenContext, isTypeArgumentOrParameterOrAssertionContext], RuleAction.Delete), + rule("NoSpaceAfterOpenAngularBracket", SyntaxKind.LessThanToken, anyToken, [isNonJsxSameLineTokenContext, isTypeArgumentOrParameterOrAssertionContext], RuleAction.Delete), + rule("NoSpaceBeforeCloseAngularBracket", anyToken, SyntaxKind.GreaterThanToken, [isNonJsxSameLineTokenContext, isTypeArgumentOrParameterOrAssertionContext], RuleAction.Delete), + rule("NoSpaceAfterCloseAngularBracket", + SyntaxKind.GreaterThanToken, + [SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.GreaterThanToken, SyntaxKind.CommaToken], + [isNonJsxSameLineTokenContext, isTypeArgumentOrParameterOrAssertionContext], + RuleAction.Delete), + + // decorators + rule("SpaceBeforeAt", anyToken, SyntaxKind.AtToken, [isNonJsxSameLineTokenContext], RuleAction.Space), + rule("NoSpaceAfterAt", SyntaxKind.AtToken, anyToken, [isNonJsxSameLineTokenContext], RuleAction.Delete), + // Insert space after @ in decorator + rule("SpaceAfterDecorator", + anyToken, + [ + SyntaxKind.AbstractKeyword, + SyntaxKind.Identifier, + SyntaxKind.ExportKeyword, + SyntaxKind.DefaultKeyword, + SyntaxKind.ClassKeyword, + SyntaxKind.StaticKeyword, + SyntaxKind.PublicKeyword, + SyntaxKind.PrivateKeyword, + SyntaxKind.ProtectedKeyword, + SyntaxKind.GetKeyword, + SyntaxKind.SetKeyword, + SyntaxKind.OpenBracketToken, + SyntaxKind.AsteriskToken, + ], + [isEndOfDecoratorContextOnSameLine], + RuleAction.Space), + + rule("NoSpaceBeforeNonNullAssertionOperator", anyToken, SyntaxKind.ExclamationToken, [isNonJsxSameLineTokenContext, isNonNullAssertionContext], RuleAction.Delete), + rule("NoSpaceAfterNewKeywordOnConstructorSignature", SyntaxKind.NewKeyword, SyntaxKind.OpenParenToken, [isNonJsxSameLineTokenContext, isConstructorSignatureContext], RuleAction.Delete), + ]; + + // 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.Space), + rule("NoSpaceAfterConstructor", SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken, [isOptionDisabledOrUndefined("insertSpaceAfterConstructor"), isNonJsxSameLineTokenContext], RuleAction.Delete), + + rule("SpaceAfterComma", SyntaxKind.CommaToken, anyToken, [isOptionEnabled("insertSpaceAfterCommaDelimiter"), isNonJsxSameLineTokenContext, isNonJsxElementContext, isNextTokenNotCloseBracket], RuleAction.Space), + rule("NoSpaceAfterComma", SyntaxKind.CommaToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterCommaDelimiter"), isNonJsxSameLineTokenContext, isNonJsxElementContext], RuleAction.Delete), + + // Insert space after function keyword for anonymous functions + rule("SpaceAfterAnonymousFunctionKeyword", SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken, [isOptionEnabled("insertSpaceAfterFunctionKeywordForAnonymousFunctions"), isFunctionDeclContext], RuleAction.Space), + rule("NoSpaceAfterAnonymousFunctionKeyword", SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken, [isOptionDisabledOrUndefined("insertSpaceAfterFunctionKeywordForAnonymousFunctions"), isFunctionDeclContext], RuleAction.Delete), // Insert space after keywords in control flow statements - this.SpaceAfterKeywordInControl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Keywords, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterKeywordsInControlFlowStatements"), Rules.IsControlDeclContext), RuleAction.Space)); - this.NoSpaceAfterKeywordInControl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Keywords, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterKeywordsInControlFlowStatements"), Rules.IsControlDeclContext), RuleAction.Delete)); + rule("SpaceAfterKeywordInControl", keywords, SyntaxKind.OpenParenToken, [isOptionEnabled("insertSpaceAfterKeywordsInControlFlowStatements"), isControlDeclContext], RuleAction.Space), + rule("NoSpaceAfterKeywordInControl", keywords, SyntaxKind.OpenParenToken, [isOptionDisabledOrUndefined("insertSpaceAfterKeywordsInControlFlowStatements"), isControlDeclContext], RuleAction.Delete), + + // Insert space after opening and before closing nonempty parenthesis + rule("SpaceAfterOpenParen", SyntaxKind.OpenParenToken, anyToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), isNonJsxSameLineTokenContext], RuleAction.Space), + rule("SpaceBeforeCloseParen", anyToken, SyntaxKind.CloseParenToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), isNonJsxSameLineTokenContext], RuleAction.Space), + rule("SpaceBetweenOpenParens", SyntaxKind.OpenParenToken, SyntaxKind.OpenParenToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), isNonJsxSameLineTokenContext], RuleAction.Space), + rule("NoSpaceBetweenParens", SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, [isNonJsxSameLineTokenContext], RuleAction.Delete), + rule("NoSpaceAfterOpenParen", SyntaxKind.OpenParenToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), isNonJsxSameLineTokenContext], RuleAction.Delete), + rule("NoSpaceBeforeCloseParen", anyToken, SyntaxKind.CloseParenToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), isNonJsxSameLineTokenContext], RuleAction.Delete), + + // Insert space after opening and before closing nonempty brackets + rule("SpaceAfterOpenBracket", SyntaxKind.OpenBracketToken, anyToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), isNonJsxSameLineTokenContext], RuleAction.Space), + rule("SpaceBeforeCloseBracket", anyToken, SyntaxKind.CloseBracketToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), isNonJsxSameLineTokenContext], RuleAction.Space), + rule("NoSpaceBetweenBrackets", SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken, [isNonJsxSameLineTokenContext], RuleAction.Delete), + rule("NoSpaceAfterOpenBracket", SyntaxKind.OpenBracketToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), isNonJsxSameLineTokenContext], RuleAction.Delete), + rule("NoSpaceBeforeCloseBracket", anyToken, SyntaxKind.CloseBracketToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), isNonJsxSameLineTokenContext], RuleAction.Delete), + + // 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.Space), + rule("SpaceBeforeCloseBrace", anyToken, SyntaxKind.CloseBraceToken, [isOptionEnabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), isBraceWrappedContext], RuleAction.Space), + rule("NoSpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [isNonJsxSameLineTokenContext, isObjectContext], RuleAction.Delete), + rule("NoSpaceAfterOpenBrace", SyntaxKind.OpenBraceToken, anyToken, [isOptionDisabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), isNonJsxSameLineTokenContext], RuleAction.Delete), + rule("NoSpaceBeforeCloseBrace", anyToken, SyntaxKind.CloseBraceToken, [isOptionDisabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), isNonJsxSameLineTokenContext], RuleAction.Delete), + + // Insert space after opening and before closing template string braces + rule("SpaceAfterTemplateHeadAndMiddle", [SyntaxKind.TemplateHead, SyntaxKind.TemplateMiddle], anyToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), isNonJsxSameLineTokenContext], RuleAction.Space), + rule("SpaceBeforeTemplateMiddleAndTail", anyToken, [SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail], [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), isNonJsxSameLineTokenContext], RuleAction.Space), + rule("NoSpaceAfterTemplateHeadAndMiddle", [SyntaxKind.TemplateHead, SyntaxKind.TemplateMiddle], anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), isNonJsxSameLineTokenContext], RuleAction.Delete), + rule("NoSpaceBeforeTemplateMiddleAndTail", anyToken, [SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail], [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), isNonJsxSameLineTokenContext], RuleAction.Delete), + + // No space after { and before } in JSX expression + rule("SpaceAfterOpenBraceInJsxExpression", SyntaxKind.OpenBraceToken, anyToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), isNonJsxSameLineTokenContext, isJsxExpressionContext], RuleAction.Space), + rule("SpaceBeforeCloseBraceInJsxExpression", anyToken, SyntaxKind.CloseBraceToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), isNonJsxSameLineTokenContext, isJsxExpressionContext], RuleAction.Space), + rule("NoSpaceAfterOpenBraceInJsxExpression", SyntaxKind.OpenBraceToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), isNonJsxSameLineTokenContext, isJsxExpressionContext], RuleAction.Delete), + rule("NoSpaceBeforeCloseBraceInJsxExpression", anyToken, SyntaxKind.CloseBraceToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), isNonJsxSameLineTokenContext, isJsxExpressionContext], RuleAction.Delete), + + // Insert space after semicolon in for statement + rule("SpaceAfterSemicolonInFor", SyntaxKind.SemicolonToken, anyToken, [isOptionEnabled("insertSpaceAfterSemicolonInForStatements"), isNonJsxSameLineTokenContext, isForContext], RuleAction.Space), + rule("NoSpaceAfterSemicolonInFor", SyntaxKind.SemicolonToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterSemicolonInForStatements"), isNonJsxSameLineTokenContext, isForContext], RuleAction.Delete), + + // Insert space before and after binary operators + rule("SpaceBeforeBinaryOperator", anyToken, binaryOperators, [isOptionEnabled("insertSpaceBeforeAndAfterBinaryOperators"), isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Space), + rule("SpaceAfterBinaryOperator", binaryOperators, anyToken, [isOptionEnabled("insertSpaceBeforeAndAfterBinaryOperators"), isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Space), + rule("NoSpaceBeforeBinaryOperator", anyToken, binaryOperators, [isOptionDisabledOrUndefined("insertSpaceBeforeAndAfterBinaryOperators"), isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Delete), + rule("NoSpaceAfterBinaryOperator", binaryOperators, anyToken, [isOptionDisabledOrUndefined("insertSpaceBeforeAndAfterBinaryOperators"), isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Delete), + + rule("SpaceBeforeOpenParenInFuncDecl", anyToken, SyntaxKind.OpenParenToken, [isOptionEnabled("insertSpaceBeforeFunctionParenthesis"), isNonJsxSameLineTokenContext, isFunctionDeclContext], RuleAction.Space), + rule("NoSpaceBeforeOpenParenInFuncDecl", anyToken, SyntaxKind.OpenParenToken, [isOptionDisabledOrUndefined("insertSpaceBeforeFunctionParenthesis"), isNonJsxSameLineTokenContext, isFunctionDeclContext], RuleAction.Delete), + + // Open Brace braces after control block + rule("NewLineBeforeOpenBraceInControl", controlOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionEnabled("placeOpenBraceOnNewLineForControlBlocks"), isControlDeclContext, isBeforeMultilineBlockContext], RuleAction.NewLine, RuleFlags.CanDeleteNewLines), // Open Brace braces after function // TypeScript: Function can have return types, which can be made of tons of different token kinds - this.NewLineBeforeOpenBraceInFunction = new Rule(RuleDescriptor.create2(this.FunctionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("placeOpenBraceOnNewLineForFunctions"), Rules.IsFunctionDeclContext, Rules.IsBeforeMultilineBlockContext), RuleAction.NewLine), RuleFlags.CanDeleteNewLines); - + rule("NewLineBeforeOpenBraceInFunction", functionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionEnabled("placeOpenBraceOnNewLineForFunctions"), isFunctionDeclContext, isBeforeMultilineBlockContext], RuleAction.NewLine, RuleFlags.CanDeleteNewLines), // Open Brace braces after TypeScript module/class/interface - this.NewLineBeforeOpenBraceInTypeScriptDeclWithBlock = new Rule(RuleDescriptor.create2(this.TypeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("placeOpenBraceOnNewLineForFunctions"), Rules.IsTypeScriptDeclWithBlockContext, Rules.IsBeforeMultilineBlockContext), RuleAction.NewLine), RuleFlags.CanDeleteNewLines); + rule("NewLineBeforeOpenBraceInTypeScriptDeclWithBlock", typeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionEnabled("placeOpenBraceOnNewLineForFunctions"), isTypeScriptDeclWithBlockContext, isBeforeMultilineBlockContext], RuleAction.NewLine, RuleFlags.CanDeleteNewLines), - // Open Brace braces after control block - this.NewLineBeforeOpenBraceInControl = new Rule(RuleDescriptor.create2(this.ControlOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("placeOpenBraceOnNewLineForControlBlocks"), Rules.IsControlDeclContext, Rules.IsBeforeMultilineBlockContext), RuleAction.NewLine), RuleFlags.CanDeleteNewLines); + rule("SpaceAfterTypeAssertion", SyntaxKind.GreaterThanToken, anyToken, [isOptionEnabled("insertSpaceAfterTypeAssertion"), isNonJsxSameLineTokenContext, isTypeAssertionContext], RuleAction.Space), + rule("NoSpaceAfterTypeAssertion", SyntaxKind.GreaterThanToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterTypeAssertion"), isNonJsxSameLineTokenContext, isTypeAssertionContext], RuleAction.Delete), + ]; - // Insert space after semicolon in for statement - this.SpaceAfterSemicolonInFor = new Rule(RuleDescriptor.create3(SyntaxKind.SemicolonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterSemicolonInForStatements"), Rules.IsNonJsxSameLineTokenContext, Rules.IsForContext), RuleAction.Space)); - this.NoSpaceAfterSemicolonInFor = new Rule(RuleDescriptor.create3(SyntaxKind.SemicolonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterSemicolonInForStatements"), Rules.IsNonJsxSameLineTokenContext, Rules.IsForContext), RuleAction.Delete)); + // These rules are lower in priority than user-configurable + const lowPriorityCommonRules = [ + // Space after keyword but not before ; or : or ? + rule("NoSpaceBeforeSemicolon", anyToken, SyntaxKind.SemicolonToken, [isNonJsxSameLineTokenContext], RuleAction.Delete), - // Insert space after opening and before closing nonempty parenthesis - this.SpaceAfterOpenParen = new Rule(RuleDescriptor.create3(SyntaxKind.OpenParenToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); - this.SpaceBeforeCloseParen = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); - this.SpaceBetweenOpenParens = new Rule(RuleDescriptor.create1(SyntaxKind.OpenParenToken, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); - this.NoSpaceBetweenParens = new Rule(RuleDescriptor.create1(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - this.NoSpaceAfterOpenParen = new Rule(RuleDescriptor.create3(SyntaxKind.OpenParenToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - this.NoSpaceBeforeCloseParen = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); + rule("SpaceBeforeOpenBraceInControl", controlOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForControlBlocks"), isControlDeclContext, isNotFormatOnEnter, isSameLineTokenOrBeforeBlockContext], RuleAction.Space, RuleFlags.CanDeleteNewLines), + rule("SpaceBeforeOpenBraceInFunction", functionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForFunctions"), isFunctionDeclContext, isBeforeBlockContext, isNotFormatOnEnter, isSameLineTokenOrBeforeBlockContext], RuleAction.Space, RuleFlags.CanDeleteNewLines), + rule("SpaceBeforeOpenBraceInTypeScriptDeclWithBlock", typeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForFunctions"), isTypeScriptDeclWithBlockContext, isNotFormatOnEnter, isSameLineTokenOrBeforeBlockContext], RuleAction.Space, RuleFlags.CanDeleteNewLines), - // Insert space after opening and before closing nonempty brackets - this.SpaceAfterOpenBracket = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBracketToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); - this.SpaceBeforeCloseBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBracketToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); - this.NoSpaceBetweenBrackets = new Rule(RuleDescriptor.create1(SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - this.NoSpaceAfterOpenBracket = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBracketToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - this.NoSpaceBeforeCloseBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBracketToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); + rule("NoSpaceBeforeComma", anyToken, SyntaxKind.CommaToken, [isNonJsxSameLineTokenContext], RuleAction.Delete), + // No space before and after indexer + rule("NoSpaceBeforeOpenBracket", anyTokenExcept(SyntaxKind.AsyncKeyword), SyntaxKind.OpenBracketToken, [isNonJsxSameLineTokenContext], RuleAction.Delete), + rule("NoSpaceAfterCloseBracket", SyntaxKind.CloseBracketToken, anyToken, [isNonJsxSameLineTokenContext, isNotBeforeBlockInFunctionDeclarationContext], RuleAction.Delete), + rule("SpaceAfterSemicolon", SyntaxKind.SemicolonToken, anyToken, [isNonJsxSameLineTokenContext], RuleAction.Space), - // Insert space after opening and before closing template string braces - this.NoSpaceAfterTemplateHeadAndMiddle = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.TemplateHead, SyntaxKind.TemplateMiddle]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - this.SpaceAfterTemplateHeadAndMiddle = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.TemplateHead, SyntaxKind.TemplateMiddle]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); - this.NoSpaceBeforeTemplateMiddleAndTail = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail])), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); - this.SpaceBeforeTemplateMiddleAndTail = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail])), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); + // 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] + rule( + "SpaceBetweenStatements", + [SyntaxKind.CloseParenToken, SyntaxKind.DoKeyword, SyntaxKind.ElseKeyword, SyntaxKind.CaseKeyword], + anyToken, + [isNonJsxSameLineTokenContext, isNonJsxElementContext, isNotForContext], + RuleAction.Space), + // This low-pri rule takes care of "try {" and "finally {" in case the rule SpaceBeforeOpenBraceInControl didn't execute on FormatOnEnter. + rule("SpaceAfterTryFinally", [SyntaxKind.TryKeyword, SyntaxKind.FinallyKeyword], SyntaxKind.OpenBraceToken, [isNonJsxSameLineTokenContext], RuleAction.Space), + ]; - // No space after { and before } in JSX expression - this.NoSpaceAfterOpenBraceInJsxExpression = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), Rules.IsNonJsxSameLineTokenContext, Rules.IsJsxExpressionContext), RuleAction.Delete)); - this.SpaceAfterOpenBraceInJsxExpression = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), Rules.IsNonJsxSameLineTokenContext, Rules.IsJsxExpressionContext), RuleAction.Space)); - this.NoSpaceBeforeCloseBraceInJsxExpression = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), Rules.IsNonJsxSameLineTokenContext, Rules.IsJsxExpressionContext), RuleAction.Delete)); - this.SpaceBeforeCloseBraceInJsxExpression = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), Rules.IsNonJsxSameLineTokenContext, Rules.IsJsxExpressionContext), RuleAction.Space)); + return [ + ...highPriorityCommonRules, + ...userConfigurableRules, + ...lowPriorityCommonRules, + ]; + } - // Insert space after function keyword for anonymous functions - this.SpaceAfterAnonymousFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterFunctionKeywordForAnonymousFunctions"), Rules.IsFunctionDeclContext), RuleAction.Space)); - this.NoSpaceAfterAnonymousFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterFunctionKeywordForAnonymousFunctions"), Rules.IsFunctionDeclContext), RuleAction.Delete)); + function rule( + debugName: string, + left: SyntaxKind | ReadonlyArray | TokenRange, + right: SyntaxKind | ReadonlyArray | TokenRange, + context: ReadonlyArray, + action: RuleAction, + flags: RuleFlags = RuleFlags.None, + ): RuleSpec { + return { leftTokenRange: toTokenRange(left), rightTokenRange: toTokenRange(right), rule: { debugName, context, action, flags } }; + } - // No space after type assertion - this.NoSpaceAfterTypeAssertion = new Rule(RuleDescriptor.create3(SyntaxKind.GreaterThanToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterTypeAssertion"), Rules.IsNonJsxSameLineTokenContext, Rules.IsTypeAssertionContext), RuleAction.Delete)); - this.SpaceAfterTypeAssertion = new Rule(RuleDescriptor.create3(SyntaxKind.GreaterThanToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterTypeAssertion"), Rules.IsNonJsxSameLineTokenContext, Rules.IsTypeAssertionContext), RuleAction.Space)); + function tokenRangeFrom(tokens: ReadonlyArray): TokenRange { + return { tokens, isSpecific: true }; + } - // These rules are higher in priority than user-configurable rules. - this.HighPriorityCommonRules = [ - this.IgnoreBeforeComment, this.IgnoreAfterLineComment, - this.NoSpaceBeforeColon, this.SpaceAfterColon, this.NoSpaceBeforeQuestionMark, this.SpaceAfterQuestionMarkInConditionalOperator, - this.NoSpaceAfterQuestionMark, - this.NoSpaceBeforeDot, this.NoSpaceAfterDot, - this.NoSpaceAfterUnaryPrefixOperator, - this.NoSpaceAfterUnaryPreincrementOperator, this.NoSpaceAfterUnaryPredecrementOperator, - this.NoSpaceBeforeUnaryPostincrementOperator, this.NoSpaceBeforeUnaryPostdecrementOperator, - this.SpaceAfterPostincrementWhenFollowedByAdd, - this.SpaceAfterAddWhenFollowedByUnaryPlus, this.SpaceAfterAddWhenFollowedByPreincrement, - this.SpaceAfterPostdecrementWhenFollowedBySubtract, - this.SpaceAfterSubtractWhenFollowedByUnaryMinus, this.SpaceAfterSubtractWhenFollowedByPredecrement, - this.NoSpaceAfterCloseBrace, - this.NewLineBeforeCloseBraceInBlockContext, - this.SpaceAfterCloseBrace, this.SpaceBetweenCloseBraceAndElse, this.SpaceBetweenCloseBraceAndWhile, this.NoSpaceBetweenEmptyBraceBrackets, - this.NoSpaceBetweenFunctionKeywordAndStar, this.SpaceAfterStarInGeneratorDeclaration, - this.SpaceAfterFunctionInFuncDecl, this.NewLineAfterOpenBraceInBlockContext, this.SpaceAfterGetSetInMember, - this.NoSpaceBetweenYieldKeywordAndStar, this.SpaceBetweenYieldOrYieldStarAndOperand, - this.NoSpaceBetweenReturnAndSemicolon, - this.SpaceAfterCertainKeywords, - this.SpaceAfterLetConstInVariableDeclaration, - this.NoSpaceBeforeOpenParenInFuncCall, - this.SpaceBeforeBinaryKeywordOperator, this.SpaceAfterBinaryKeywordOperator, - this.SpaceAfterVoidOperator, - this.SpaceBetweenAsyncAndOpenParen, this.SpaceBetweenAsyncAndFunctionKeyword, - this.NoSpaceBetweenTagAndTemplateString, - this.SpaceBeforeJsxAttribute, this.SpaceBeforeSlashInJsxOpeningElement, this.NoSpaceBeforeGreaterThanTokenInJsxOpeningElement, - this.NoSpaceBeforeEqualInJsxAttribute, this.NoSpaceAfterEqualInJsxAttribute, + function toTokenRange(arg: SyntaxKind | ReadonlyArray | TokenRange): TokenRange { + return typeof arg === "number" ? tokenRangeFrom([arg]) : isArray(arg) ? tokenRangeFrom(arg) : arg; + } - // TypeScript-specific rules - this.NoSpaceAfterModuleImport, - this.SpaceAfterCertainTypeScriptKeywords, this.SpaceBeforeCertainTypeScriptKeywords, - this.SpaceAfterModuleName, - this.SpaceBeforeArrow, this.SpaceAfterArrow, - this.NoSpaceAfterEllipsis, - this.NoSpaceAfterOptionalParameters, - this.NoSpaceBetweenEmptyInterfaceBraceBrackets, - this.NoSpaceBeforeOpenAngularBracket, - this.NoSpaceBetweenCloseParenAndAngularBracket, - this.NoSpaceAfterOpenAngularBracket, - this.NoSpaceBeforeCloseAngularBracket, - this.NoSpaceAfterCloseAngularBracket, - this.SpaceBeforeAt, - this.NoSpaceAfterAt, - this.SpaceAfterDecorator, - this.NoSpaceBeforeNonNullAssertionOperator, - this.NoSpaceAfterNewKeywordOnConstructorSignature - ]; - - // These rules are applied after high priority rules. - this.UserConfigurableRules = [ - this.SpaceAfterConstructor, this.NoSpaceAfterConstructor, - this.SpaceAfterComma, this.NoSpaceAfterComma, - this.SpaceAfterAnonymousFunctionKeyword, this.NoSpaceAfterAnonymousFunctionKeyword, - this.SpaceAfterKeywordInControl, this.NoSpaceAfterKeywordInControl, - this.SpaceAfterOpenParen, this.SpaceBeforeCloseParen, this.SpaceBetweenOpenParens, this.NoSpaceBetweenParens, this.NoSpaceAfterOpenParen, this.NoSpaceBeforeCloseParen, - this.SpaceAfterOpenBracket, this.SpaceBeforeCloseBracket, this.NoSpaceBetweenBrackets, this.NoSpaceAfterOpenBracket, this.NoSpaceBeforeCloseBracket, - this.SpaceAfterOpenBrace, this.SpaceBeforeCloseBrace, this.NoSpaceBetweenEmptyBraceBrackets, this.NoSpaceAfterOpenBrace, this.NoSpaceBeforeCloseBrace, - this.SpaceAfterTemplateHeadAndMiddle, this.SpaceBeforeTemplateMiddleAndTail, this.NoSpaceAfterTemplateHeadAndMiddle, this.NoSpaceBeforeTemplateMiddleAndTail, - this.SpaceAfterOpenBraceInJsxExpression, this.SpaceBeforeCloseBraceInJsxExpression, this.NoSpaceAfterOpenBraceInJsxExpression, this.NoSpaceBeforeCloseBraceInJsxExpression, - this.SpaceAfterSemicolonInFor, this.NoSpaceAfterSemicolonInFor, - this.SpaceBeforeBinaryOperator, this.SpaceAfterBinaryOperator, this.NoSpaceBeforeBinaryOperator, this.NoSpaceAfterBinaryOperator, - this.SpaceBeforeOpenParenInFuncDecl, this.NoSpaceBeforeOpenParenInFuncDecl, - this.NewLineBeforeOpenBraceInControl, - this.NewLineBeforeOpenBraceInFunction, this.NewLineBeforeOpenBraceInTypeScriptDeclWithBlock, - this.SpaceAfterTypeAssertion, this.NoSpaceAfterTypeAssertion - ]; - - // These rules are lower in priority than user-configurable rules. - this.LowPriorityCommonRules = [ - this.NoSpaceBeforeSemicolon, - this.SpaceBeforeOpenBraceInControl, this.SpaceBeforeOpenBraceInFunction, this.SpaceBeforeOpenBraceInTypeScriptDeclWithBlock, - this.NoSpaceBeforeComma, - this.NoSpaceBeforeOpenBracket, - this.NoSpaceAfterCloseBracket, - this.SpaceAfterSemicolon, - this.SpaceBetweenStatements, this.SpaceAfterTryFinally - ]; - - if (Debug.isDebugging) { - const o: ts.MapLike = this; - for (const name in o) { - const rule = o[name]; - if (rule instanceof Rule) { - rule.debugName = name; - } - } + function tokenRangeFromRange(from: SyntaxKind, to: SyntaxKind, except: ReadonlyArray = []): TokenRange { + const tokens: SyntaxKind[] = []; + for (let token = from; token <= to; token++) { + if (!contains(except, token)) { + tokens.push(token); } } + return tokenRangeFrom(tokens); + } - /// - /// Contexts - /// + /// + /// Contexts + /// - static IsOptionEnabled(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { - return (context) => context.options && context.options.hasOwnProperty(optionName) && !!context.options[optionName]; - } + function isOptionEnabled(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { + return (context) => context.options && context.options.hasOwnProperty(optionName) && !!context.options[optionName]; + } - static IsOptionDisabled(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { - return (context) => context.options && context.options.hasOwnProperty(optionName) && !context.options[optionName]; - } + function isOptionDisabled(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { + return (context) => context.options && context.options.hasOwnProperty(optionName) && !context.options[optionName]; + } - static IsOptionDisabledOrUndefined(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { - return (context) => !context.options || !context.options.hasOwnProperty(optionName) || !context.options[optionName]; - } + function isOptionDisabledOrUndefined(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { + return (context) => !context.options || !context.options.hasOwnProperty(optionName) || !context.options[optionName]; + } - static isOptionDisabledOrUndefinedOrTokensOnSameLine(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { - return (context) => !context.options || !context.options.hasOwnProperty(optionName) || !context.options[optionName] || context.TokensAreOnSameLine(); - } + function isOptionDisabledOrUndefinedOrTokensOnSameLine(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { + return (context) => !context.options || !context.options.hasOwnProperty(optionName) || !context.options[optionName] || context.TokensAreOnSameLine(); + } - static IsOptionEnabledOrUndefined(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { - return (context) => !context.options || !context.options.hasOwnProperty(optionName) || !!context.options[optionName]; - } + function isOptionEnabledOrUndefined(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { + return (context) => !context.options || !context.options.hasOwnProperty(optionName) || !!context.options[optionName]; + } - static IsForContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.ForStatement; - } + function isForContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.ForStatement; + } - static IsNotForContext(context: FormattingContext): boolean { - return !Rules.IsForContext(context); - } + function isNotForContext(context: FormattingContext): boolean { + return !isForContext(context); + } - static IsBinaryOpContext(context: FormattingContext): boolean { + function isBinaryOpContext(context: FormattingContext): boolean { - switch (context.contextNode.kind) { - case SyntaxKind.BinaryExpression: - case SyntaxKind.ConditionalExpression: - case SyntaxKind.AsExpression: - case SyntaxKind.ExportSpecifier: - case SyntaxKind.ImportSpecifier: - case SyntaxKind.TypePredicate: - case SyntaxKind.UnionType: - case SyntaxKind.IntersectionType: - return true; - - // equals in binding elements: function foo([[x, y] = [1, 2]]) - case SyntaxKind.BindingElement: - // equals in type X = ... - case SyntaxKind.TypeAliasDeclaration: - // equal in import a = module('a'); - case SyntaxKind.ImportEqualsDeclaration: - // equal in let a = 0; - case SyntaxKind.VariableDeclaration: - // equal in p = 0; - case SyntaxKind.Parameter: - case SyntaxKind.EnumMember: - case SyntaxKind.PropertyDeclaration: - case SyntaxKind.PropertySignature: - 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] - case SyntaxKind.TypeParameter: - return context.currentTokenSpan.kind === SyntaxKind.InKeyword || context.nextTokenSpan.kind === SyntaxKind.InKeyword; - // 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 false; - } - - static IsNotBinaryOpContext(context: FormattingContext): boolean { - return !Rules.IsBinaryOpContext(context); - } - - static IsConditionalOperatorContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.ConditionalExpression; - } - - static IsSameLineTokenOrBeforeBlockContext(context: FormattingContext): boolean { - return context.TokensAreOnSameLine() || Rules.IsBeforeBlockContext(context); - } - - static IsBraceWrappedContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.ObjectBindingPattern || Rules.IsSingleLineBlockContext(context); - } - - // This check is done before an open brace in a control construct, a function, or a typescript block declaration - static IsBeforeMultilineBlockContext(context: FormattingContext): boolean { - return Rules.IsBeforeBlockContext(context) && !(context.NextNodeAllOnSameLine() || context.NextNodeBlockIsOnOneLine()); - } - - static IsMultilineBlockContext(context: FormattingContext): boolean { - return Rules.IsBlockContext(context) && !(context.ContextNodeAllOnSameLine() || context.ContextNodeBlockIsOnOneLine()); - } - - static IsSingleLineBlockContext(context: FormattingContext): boolean { - return Rules.IsBlockContext(context) && (context.ContextNodeAllOnSameLine() || context.ContextNodeBlockIsOnOneLine()); - } - - static IsBlockContext(context: FormattingContext): boolean { - return Rules.NodeIsBlockContext(context.contextNode); - } - - static IsBeforeBlockContext(context: FormattingContext): boolean { - return Rules.NodeIsBlockContext(context.nextTokenParent); - } - - // IMPORTANT!!! This method must return true ONLY for nodes with open and close braces as immediate children - static NodeIsBlockContext(node: Node): boolean { - if (Rules.NodeIsTypeScriptDeclWithBlockContext(node)) { - // This means we are in a context that looks like a block to the user, but in the grammar is actually not a node (it's a class, module, enum, object type literal, etc). + switch (context.contextNode.kind) { + case SyntaxKind.BinaryExpression: + case SyntaxKind.ConditionalExpression: + case SyntaxKind.AsExpression: + case SyntaxKind.ExportSpecifier: + case SyntaxKind.ImportSpecifier: + case SyntaxKind.TypePredicate: + case SyntaxKind.UnionType: + case SyntaxKind.IntersectionType: return true; - } - switch (node.kind) { - case SyntaxKind.Block: - case SyntaxKind.CaseBlock: - case SyntaxKind.ObjectLiteralExpression: - case SyntaxKind.ModuleBlock: + // equals in binding elements: function foo([[x, y] = [1, 2]]) + case SyntaxKind.BindingElement: + // equals in type X = ... + case SyntaxKind.TypeAliasDeclaration: + // equal in import a = module('a'); + case SyntaxKind.ImportEqualsDeclaration: + // equal in let a = 0; + case SyntaxKind.VariableDeclaration: + // equal in p = 0; + case SyntaxKind.Parameter: + case SyntaxKind.EnumMember: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + 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] + case SyntaxKind.TypeParameter: + return context.currentTokenSpan.kind === SyntaxKind.InKeyword || context.nextTokenSpan.kind === SyntaxKind.InKeyword; + // 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 false; + } + + function isNotBinaryOpContext(context: FormattingContext): boolean { + return !isBinaryOpContext(context); + } + + function isConditionalOperatorContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.ConditionalExpression; + } + + function isSameLineTokenOrBeforeBlockContext(context: FormattingContext): boolean { + return context.TokensAreOnSameLine() || isBeforeBlockContext(context); + } + + function isBraceWrappedContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.ObjectBindingPattern || 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()); + } + + function isMultilineBlockContext(context: FormattingContext): boolean { + return isBlockContext(context) && !(context.ContextNodeAllOnSameLine() || context.ContextNodeBlockIsOnOneLine()); + } + + function isSingleLineBlockContext(context: FormattingContext): boolean { + return isBlockContext(context) && (context.ContextNodeAllOnSameLine() || context.ContextNodeBlockIsOnOneLine()); + } + + function isBlockContext(context: FormattingContext): boolean { + return nodeIsBlockContext(context.contextNode); + } + + function isBeforeBlockContext(context: FormattingContext): boolean { + return nodeIsBlockContext(context.nextTokenParent); + } + + // IMPORTANT!!! This method must return true ONLY for nodes with open and close braces as immediate children + function nodeIsBlockContext(node: Node): boolean { + if (nodeIsTypeScriptDeclWithBlockContext(node)) { + // This means we are in a context that looks like a block to the user, but in the grammar is actually not a node (it's a class, module, enum, object type literal, etc). + return true; + } + + switch (node.kind) { + case SyntaxKind.Block: + case SyntaxKind.CaseBlock: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.ModuleBlock: + return true; + } + + return false; + } + + function isFunctionDeclContext(context: FormattingContext): boolean { + switch (context.contextNode.kind) { + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + // case SyntaxKind.MemberFunctionDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + // case SyntaxKind.MethodSignature: + case SyntaxKind.CallSignature: + case SyntaxKind.FunctionExpression: + case SyntaxKind.Constructor: + case SyntaxKind.ArrowFunction: + // case SyntaxKind.ConstructorDeclaration: + // case SyntaxKind.SimpleArrowFunctionExpression: + // case SyntaxKind.ParenthesizedArrowFunctionExpression: + case SyntaxKind.InterfaceDeclaration: // This one is not truly a function, but for formatting purposes, it acts just like one + return true; + } + + return false; + } + + function isFunctionDeclarationOrFunctionExpressionContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.FunctionDeclaration || context.contextNode.kind === SyntaxKind.FunctionExpression; + } + + function isTypeScriptDeclWithBlockContext(context: FormattingContext): boolean { + return nodeIsTypeScriptDeclWithBlockContext(context.contextNode); + } + + function nodeIsTypeScriptDeclWithBlockContext(node: Node): boolean { + switch (node.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.TypeLiteral: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.ExportDeclaration: + case SyntaxKind.NamedExports: + case SyntaxKind.ImportDeclaration: + case SyntaxKind.NamedImports: + return true; + } + + return false; + } + + function isAfterCodeBlockContext(context: FormattingContext): boolean { + switch (context.currentTokenParent.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.CatchClause: + case SyntaxKind.ModuleBlock: + case SyntaxKind.SwitchStatement: + return true; + 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) { return true; - } - - return false; - } - - static IsFunctionDeclContext(context: FormattingContext): boolean { - switch (context.contextNode.kind) { - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.MethodSignature: - // case SyntaxKind.MemberFunctionDeclaration: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - // case SyntaxKind.MethodSignature: - case SyntaxKind.CallSignature: - case SyntaxKind.FunctionExpression: - case SyntaxKind.Constructor: - case SyntaxKind.ArrowFunction: - // case SyntaxKind.ConstructorDeclaration: - // case SyntaxKind.SimpleArrowFunctionExpression: - // case SyntaxKind.ParenthesizedArrowFunctionExpression: - case SyntaxKind.InterfaceDeclaration: // This one is not truly a function, but for formatting purposes, it acts just like one - return true; - } - - return false; - } - - static IsFunctionDeclarationOrFunctionExpressionContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.FunctionDeclaration || context.contextNode.kind === SyntaxKind.FunctionExpression; - } - - static IsTypeScriptDeclWithBlockContext(context: FormattingContext): boolean { - return Rules.NodeIsTypeScriptDeclWithBlockContext(context.contextNode); - } - - static NodeIsTypeScriptDeclWithBlockContext(node: Node): boolean { - switch (node.kind) { - case SyntaxKind.ClassDeclaration: - case SyntaxKind.ClassExpression: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.TypeLiteral: - case SyntaxKind.ModuleDeclaration: - case SyntaxKind.ExportDeclaration: - case SyntaxKind.NamedExports: - case SyntaxKind.ImportDeclaration: - case SyntaxKind.NamedImports: - return true; - } - - return false; - } - - static IsAfterCodeBlockContext(context: FormattingContext): boolean { - switch (context.currentTokenParent.kind) { - case SyntaxKind.ClassDeclaration: - case SyntaxKind.ModuleDeclaration: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.CatchClause: - case SyntaxKind.ModuleBlock: - case SyntaxKind.SwitchStatement: - return true; - 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) { - return true; - } } } - return false; } + return false; + } - static IsControlDeclContext(context: FormattingContext): boolean { - switch (context.contextNode.kind) { - case SyntaxKind.IfStatement: - case SyntaxKind.SwitchStatement: - case SyntaxKind.ForStatement: - case SyntaxKind.ForInStatement: - case SyntaxKind.ForOfStatement: - case SyntaxKind.WhileStatement: - case SyntaxKind.TryStatement: - case SyntaxKind.DoStatement: - case SyntaxKind.WithStatement: - // TODO - // case SyntaxKind.ElseClause: - case SyntaxKind.CatchClause: - return true; + function isControlDeclContext(context: FormattingContext): boolean { + switch (context.contextNode.kind) { + case SyntaxKind.IfStatement: + case SyntaxKind.SwitchStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.TryStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.WithStatement: + // TODO + // case SyntaxKind.ElseClause: + case SyntaxKind.CatchClause: + return true; - default: - return false; - } - } - - static IsObjectContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.ObjectLiteralExpression; - } - - static IsFunctionCallContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.CallExpression; - } - - static IsNewContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.NewExpression; - } - - static IsFunctionCallOrNewContext(context: FormattingContext): boolean { - return Rules.IsFunctionCallContext(context) || Rules.IsNewContext(context); - } - - static IsPreviousTokenNotComma(context: FormattingContext): boolean { - return context.currentTokenSpan.kind !== SyntaxKind.CommaToken; - } - - static IsNextTokenNotCloseBracket(context: FormattingContext): boolean { - return context.nextTokenSpan.kind !== SyntaxKind.CloseBracketToken; - } - - static IsArrowFunctionContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.ArrowFunction; - } - - static IsNonJsxSameLineTokenContext(context: FormattingContext): boolean { - return context.TokensAreOnSameLine() && context.contextNode.kind !== SyntaxKind.JsxText; - } - - static IsNonJsxElementContext(context: FormattingContext): boolean { - return context.contextNode.kind !== SyntaxKind.JsxElement; - } - - static IsJsxExpressionContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.JsxExpression; - } - - static IsNextTokenParentJsxAttribute(context: FormattingContext): boolean { - return context.nextTokenParent.kind === SyntaxKind.JsxAttribute; - } - - static IsJsxAttributeContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.JsxAttribute; - } - - static IsJsxSelfClosingElementContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.JsxSelfClosingElement; - } - - static IsNotBeforeBlockInFunctionDeclarationContext(context: FormattingContext): boolean { - return !Rules.IsFunctionDeclContext(context) && !Rules.IsBeforeBlockContext(context); - } - - static IsEndOfDecoratorContextOnSameLine(context: FormattingContext): boolean { - return context.TokensAreOnSameLine() && - context.contextNode.decorators && - Rules.NodeIsInDecoratorContext(context.currentTokenParent) && - !Rules.NodeIsInDecoratorContext(context.nextTokenParent); - } - - static NodeIsInDecoratorContext(node: Node): boolean { - while (isPartOfExpression(node)) { - node = node.parent; - } - return node.kind === SyntaxKind.Decorator; - } - - static IsStartOfVariableDeclarationList(context: FormattingContext): boolean { - return context.currentTokenParent.kind === SyntaxKind.VariableDeclarationList && - context.currentTokenParent.getStart(context.sourceFile) === context.currentTokenSpan.pos; - } - - static IsNotFormatOnEnter(context: FormattingContext): boolean { - return context.formattingRequestKind !== FormattingRequestKind.FormatOnEnter; - } - - static IsModuleDeclContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.ModuleDeclaration; - } - - static IsObjectTypeContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.TypeLiteral; // && context.contextNode.parent.kind !== SyntaxKind.InterfaceDeclaration; - } - - static IsConstructorSignatureContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.ConstructSignature; - } - - static IsTypeArgumentOrParameterOrAssertion(token: TextRangeWithKind, parent: Node): boolean { - if (token.kind !== SyntaxKind.LessThanToken && token.kind !== SyntaxKind.GreaterThanToken) { + default: return false; - } - switch (parent.kind) { - case SyntaxKind.TypeReference: - case SyntaxKind.TypeAssertionExpression: - case SyntaxKind.TypeAliasDeclaration: - case SyntaxKind.ClassDeclaration: - case SyntaxKind.ClassExpression: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.FunctionExpression: - case SyntaxKind.ArrowFunction: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.MethodSignature: - case SyntaxKind.CallSignature: - case SyntaxKind.ConstructSignature: - case SyntaxKind.CallExpression: - case SyntaxKind.NewExpression: - case SyntaxKind.ExpressionWithTypeArguments: - return true; - default: - return false; - - } - } - - static IsTypeArgumentOrParameterOrAssertionContext(context: FormattingContext): boolean { - return Rules.IsTypeArgumentOrParameterOrAssertion(context.currentTokenSpan, context.currentTokenParent) || - Rules.IsTypeArgumentOrParameterOrAssertion(context.nextTokenSpan, context.nextTokenParent); - } - - static IsTypeAssertionContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.TypeAssertionExpression; - } - - static IsVoidOpContext(context: FormattingContext): boolean { - return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword && context.currentTokenParent.kind === SyntaxKind.VoidExpression; - } - - static IsYieldOrYieldStarWithOperand(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.YieldExpression && (context.contextNode).expression !== undefined; - } - - static IsNonNullAssertionContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.NonNullExpression; } } -} \ No newline at end of file + + function isObjectContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.ObjectLiteralExpression; + } + + function isFunctionCallContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.CallExpression; + } + + function isNewContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.NewExpression; + } + + function isFunctionCallOrNewContext(context: FormattingContext): boolean { + return isFunctionCallContext(context) || isNewContext(context); + } + + function isPreviousTokenNotComma(context: FormattingContext): boolean { + return context.currentTokenSpan.kind !== SyntaxKind.CommaToken; + } + + function isNextTokenNotCloseBracket(context: FormattingContext): boolean { + return context.nextTokenSpan.kind !== SyntaxKind.CloseBracketToken; + } + + function isArrowFunctionContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.ArrowFunction; + } + + function isNonJsxSameLineTokenContext(context: FormattingContext): boolean { + return context.TokensAreOnSameLine() && context.contextNode.kind !== SyntaxKind.JsxText; + } + + function isNonJsxElementContext(context: FormattingContext): boolean { + return context.contextNode.kind !== SyntaxKind.JsxElement; + } + + function isJsxExpressionContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.JsxExpression; + } + + function isNextTokenParentJsxAttribute(context: FormattingContext): boolean { + return context.nextTokenParent.kind === SyntaxKind.JsxAttribute; + } + + function isJsxAttributeContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.JsxAttribute; + } + + function isJsxSelfClosingElementContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.JsxSelfClosingElement; + } + + function isNotBeforeBlockInFunctionDeclarationContext(context: FormattingContext): boolean { + return !isFunctionDeclContext(context) && !isBeforeBlockContext(context); + } + + function isEndOfDecoratorContextOnSameLine(context: FormattingContext): boolean { + return context.TokensAreOnSameLine() && + context.contextNode.decorators && + nodeIsInDecoratorContext(context.currentTokenParent) && + !nodeIsInDecoratorContext(context.nextTokenParent); + } + + function nodeIsInDecoratorContext(node: Node): boolean { + while (isExpressionNode(node)) { + node = node.parent; + } + return node.kind === SyntaxKind.Decorator; + } + + function isStartOfVariableDeclarationList(context: FormattingContext): boolean { + return context.currentTokenParent.kind === SyntaxKind.VariableDeclarationList && + context.currentTokenParent.getStart(context.sourceFile) === context.currentTokenSpan.pos; + } + + function isNotFormatOnEnter(context: FormattingContext): boolean { + return context.formattingRequestKind !== FormattingRequestKind.FormatOnEnter; + } + + function isModuleDeclContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.ModuleDeclaration; + } + + function isObjectTypeContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.TypeLiteral; // && context.contextNode.parent.kind !== SyntaxKind.InterfaceDeclaration; + } + + function isConstructorSignatureContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.ConstructSignature; + } + + function isTypeArgumentOrParameterOrAssertion(token: TextRangeWithKind, parent: Node): boolean { + if (token.kind !== SyntaxKind.LessThanToken && token.kind !== SyntaxKind.GreaterThanToken) { + return false; + } + switch (parent.kind) { + case SyntaxKind.TypeReference: + case SyntaxKind.TypeAssertionExpression: + case SyntaxKind.TypeAliasDeclaration: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.CallExpression: + case SyntaxKind.NewExpression: + case SyntaxKind.ExpressionWithTypeArguments: + return true; + default: + return false; + + } + } + + function isTypeArgumentOrParameterOrAssertionContext(context: FormattingContext): boolean { + return isTypeArgumentOrParameterOrAssertion(context.currentTokenSpan, context.currentTokenParent) || + isTypeArgumentOrParameterOrAssertion(context.nextTokenSpan, context.nextTokenParent); + } + + function isTypeAssertionContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.TypeAssertionExpression; + } + + function isVoidOpContext(context: FormattingContext): boolean { + return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword && context.currentTokenParent.kind === SyntaxKind.VoidExpression; + } + + function isYieldOrYieldStarWithOperand(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.YieldExpression && (context.contextNode).expression !== undefined; + } + + function isNonNullAssertionContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.NonNullExpression; + } +} diff --git a/src/services/formatting/rulesMap.ts b/src/services/formatting/rulesMap.ts index d1f6e4724f7..d44e47a763a 100644 --- a/src/services/formatting/rulesMap.ts +++ b/src/services/formatting/rulesMap.ts @@ -1,156 +1,107 @@ -/// +/// /* @internal */ namespace ts.formatting { - export class RulesMap { - public map: RulesBucket[]; - public mapRowLength: number; - - constructor(rules: ReadonlyArray) { - this.mapRowLength = SyntaxKind.LastToken + 1; - this.map = new Array(this.mapRowLength * this.mapRowLength); - - // This array is used only during construction of the rulesbucket in the map - const rulesBucketConstructionStateList: RulesBucketConstructionState[] = new Array(this.map.length); - for (const rule of rules) { - this.FillRule(rule, rulesBucketConstructionStateList); - } - } - - private GetRuleBucketIndex(row: number, column: number): number { - Debug.assert(row <= SyntaxKind.LastKeyword && column <= SyntaxKind.LastKeyword, "Must compute formatting context from tokens"); - return (row * this.mapRowLength) + column; - } - - private FillRule(rule: Rule, rulesBucketConstructionStateList: RulesBucketConstructionState[]): void { - const specificRule = rule.Descriptor.LeftTokenRange.isSpecific() && rule.Descriptor.RightTokenRange.isSpecific(); - - rule.Descriptor.LeftTokenRange.GetTokens().forEach((left) => { - rule.Descriptor.RightTokenRange.GetTokens().forEach((right) => { - const rulesBucketIndex = this.GetRuleBucketIndex(left, right); - - let rulesBucket = this.map[rulesBucketIndex]; - if (rulesBucket === undefined) { - rulesBucket = this.map[rulesBucketIndex] = new RulesBucket(); - } - - rulesBucket.AddRule(rule, specificRule, rulesBucketConstructionStateList, rulesBucketIndex); - }); - }); - } - - public GetRule(context: FormattingContext): Rule | undefined { - const bucketIndex = this.GetRuleBucketIndex(context.currentTokenSpan.kind, context.nextTokenSpan.kind); - const bucket = this.map[bucketIndex]; - if (bucket) { - for (const rule of bucket.Rules()) { - if (rule.Operation.Context.InContext(context)) { - return rule; - } - } - } - return undefined; - } + export function getFormatContext(options: FormatCodeSettings): formatting.FormatContext { + return { options, getRule: getRulesMap() }; } - const MaskBitSize = 5; - const Mask = 0x1f; + let rulesMapCache: RulesMap | undefined; + + function getRulesMap(): RulesMap { + if (rulesMapCache === undefined) { + rulesMapCache = createRulesMap(getAllRules()); + } + return rulesMapCache; + } + + export type RulesMap = (context: FormattingContext) => Rule | undefined; + function createRulesMap(rules: ReadonlyArray): RulesMap { + const map = buildMap(rules); + return context => { + const bucket = map[getRuleBucketIndex(context.currentTokenSpan.kind, context.nextTokenSpan.kind)]; + return bucket && find(bucket, rule => every(rule.context, c => c(context))); + }; + } + + function buildMap(rules: ReadonlyArray): ReadonlyArray> { + // Map from bucket index to array of rules + const map: Rule[][] = new Array(mapRowLength * mapRowLength); + // This array is used only during construction of the rulesbucket in the map + const rulesBucketConstructionStateList = new Array(map.length); + for (const rule of rules) { + const specificRule = rule.leftTokenRange.isSpecific && rule.rightTokenRange.isSpecific; + + for (const left of rule.leftTokenRange.tokens) { + for (const right of rule.rightTokenRange.tokens) { + const index = getRuleBucketIndex(left, right); + let rulesBucket = map[index]; + if (rulesBucket === undefined) { + rulesBucket = map[index] = []; + } + addRule(rulesBucket, rule.rule, specificRule, rulesBucketConstructionStateList, index); + } + } + } + return map; + } + + function getRuleBucketIndex(row: number, column: number): number { + Debug.assert(row <= SyntaxKind.LastKeyword && column <= SyntaxKind.LastKeyword, "Must compute formatting context from tokens"); + return (row * mapRowLength) + column; + } + + const maskBitSize = 5; + const mask = 0b11111; // MaskBitSize bits + const mapRowLength = SyntaxKind.LastToken + 1; enum RulesPosition { IgnoreRulesSpecific = 0, - IgnoreRulesAny = MaskBitSize * 1, - ContextRulesSpecific = MaskBitSize * 2, - ContextRulesAny = MaskBitSize * 3, - NoContextRulesSpecific = MaskBitSize * 4, - NoContextRulesAny = MaskBitSize * 5 + IgnoreRulesAny = maskBitSize * 1, + ContextRulesSpecific = maskBitSize * 2, + ContextRulesAny = maskBitSize * 3, + NoContextRulesSpecific = maskBitSize * 4, + NoContextRulesAny = maskBitSize * 5 } - export class RulesBucketConstructionState { - private rulesInsertionIndexBitmap: number; - - constructor() { - //// The Rules list contains all the inserted rules into a rulebucket in the following order: - //// 1- Ignore rules with specific token combination - //// 2- Ignore rules with any token combination - //// 3- Context rules with specific token combination - //// 4- Context rules with any token combination - //// 5- Non-context rules with specific token combination - //// 6- Non-context rules with any token combination - //// - //// The member rulesInsertionIndexBitmap is used to describe the number of rules - //// in each sub-bucket (above) hence can be used to know the index of where to insert - //// the next rule. It's a bitmap which contains 6 different sections each is given 5 bits. - //// - //// 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. - this.rulesInsertionIndexBitmap = 0; - } - - public GetInsertionIndex(maskPosition: RulesPosition): number { - let index = 0; - - let pos = 0; - let indexBitmap = this.rulesInsertionIndexBitmap; - - while (pos <= maskPosition) { - index += (indexBitmap & Mask); - indexBitmap >>= MaskBitSize; - pos += MaskBitSize; - } - - return index; - } - - public IncreaseInsertionIndex(maskPosition: RulesPosition): void { - let value = (this.rulesInsertionIndexBitmap >> maskPosition) & Mask; - value++; - Debug.assert((value & Mask) === value, "Adding more rules into the sub-bucket than allowed. Maximum allowed is 32 rules."); - - let temp = this.rulesInsertionIndexBitmap & ~(Mask << maskPosition); - temp |= value << maskPosition; - - this.rulesInsertionIndexBitmap = temp; - } + // The Rules list contains all the inserted rules into a rulebucket in the following order: + // 1- Ignore rules with specific token combination + // 2- Ignore rules with any token combination + // 3- Context rules with specific token combination + // 4- Context rules with any token combination + // 5- Non-context rules with specific token combination + // 6- Non-context rules with any token combination + // + // The member rulesInsertionIndexBitmap is used to describe the number of rules + // in each sub-bucket (above) hence can be used to know the index of where to insert + // the next rule. It's a bitmap which contains 6 different sections each is given 5 bits. + // + // 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.Ignore + ? specificTokens ? RulesPosition.IgnoreRulesSpecific : RulesPosition.IgnoreRulesAny + : 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); + constructionState[rulesBucketIndex] = increaseInsertionIndex(state, position); } - export class RulesBucket { - private rules: Rule[]; - - constructor() { - this.rules = []; + function getInsertionIndex(indexBitmap: number, maskPosition: RulesPosition) { + let index = 0; + for (let pos = 0; pos <= maskPosition; pos += maskBitSize) { + index += indexBitmap & mask; + indexBitmap >>= maskBitSize; } + return index; + } - public Rules(): Rule[] { - return this.rules; - } - - public AddRule(rule: Rule, specificTokens: boolean, constructionState: RulesBucketConstructionState[], rulesBucketIndex: number): void { - let position: RulesPosition; - - if (rule.Operation.Action === RuleAction.Ignore) { - position = specificTokens ? - RulesPosition.IgnoreRulesSpecific : - RulesPosition.IgnoreRulesAny; - } - else if (!rule.Operation.Context.IsAny()) { - position = specificTokens ? - RulesPosition.ContextRulesSpecific : - RulesPosition.ContextRulesAny; - } - else { - position = specificTokens ? - RulesPosition.NoContextRulesSpecific : - RulesPosition.NoContextRulesAny; - } - - let state = constructionState[rulesBucketIndex]; - if (state === undefined) { - state = constructionState[rulesBucketIndex] = new RulesBucketConstructionState(); - } - const index = state.GetInsertionIndex(position); - this.rules.splice(index, 0, rule); - state.IncreaseInsertionIndex(position); - } + 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."); + return (indexBitmap & ~(mask << maskPosition)) | (value << maskPosition); } } \ No newline at end of file diff --git a/src/services/formatting/rulesProvider.ts b/src/services/formatting/rulesProvider.ts deleted file mode 100644 index fcf08541890..00000000000 --- a/src/services/formatting/rulesProvider.ts +++ /dev/null @@ -1,30 +0,0 @@ -/// - -/* @internal */ -namespace ts.formatting { - export class RulesProvider { - private globalRules: Rules; - private options: ts.FormatCodeSettings; - private rulesMap: RulesMap; - - constructor() { - this.globalRules = new Rules(); - const activeRules = this.globalRules.HighPriorityCommonRules.concat(this.globalRules.UserConfigurableRules).concat(this.globalRules.LowPriorityCommonRules); - this.rulesMap = new RulesMap(activeRules); - } - - public getRulesMap() { - return this.rulesMap; - } - - public getFormatOptions(): Readonly { - return this.options; - } - - public ensureUpToDate(options: ts.FormatCodeSettings) { - if (!this.options || !ts.compareDataObjects(this.options, options)) { - this.options = ts.clone(options); - } - } - } -} \ No newline at end of file diff --git a/src/services/formatting/smartIndenter.ts b/src/services/formatting/smartIndenter.ts index 7701cff182c..5afe4cb1d31 100644 --- a/src/services/formatting/smartIndenter.ts +++ b/src/services/formatting/smartIndenter.ts @@ -1,5 +1,3 @@ -/// - /* @internal */ namespace ts.formatting { export namespace SmartIndenter { diff --git a/src/services/formatting/tokenRange.ts b/src/services/formatting/tokenRange.ts deleted file mode 100644 index 29855279e25..00000000000 --- a/src/services/formatting/tokenRange.ts +++ /dev/null @@ -1,123 +0,0 @@ -/// - -/* @internal */ -namespace ts.formatting { - export namespace Shared { - const allTokens: SyntaxKind[] = []; - for (let token = SyntaxKind.FirstToken; token <= SyntaxKind.LastToken; token++) { - allTokens.push(token); - } - - class TokenValuesAccess implements TokenRange { - constructor(private readonly tokens: SyntaxKind[] = []) { } - - public GetTokens(): SyntaxKind[] { - return this.tokens; - } - - public Contains(token: SyntaxKind): boolean { - return this.tokens.indexOf(token) >= 0; - } - - public isSpecific() { return true; } - } - - class TokenSingleValueAccess implements TokenRange { - constructor(private readonly token: SyntaxKind) {} - - public GetTokens(): SyntaxKind[] { - return [this.token]; - } - - public Contains(tokenValue: SyntaxKind): boolean { - return tokenValue === this.token; - } - - public isSpecific() { return true; } - } - - class TokenAllAccess implements TokenRange { - public GetTokens(): SyntaxKind[] { - return allTokens; - } - - public Contains(): boolean { - return true; - } - - public toString(): string { - return "[allTokens]"; - } - - public isSpecific() { return false; } - } - - class TokenAllExceptAccess implements TokenRange { - constructor(private readonly except: SyntaxKind) {} - - public GetTokens(): SyntaxKind[] { - return allTokens.filter(t => t !== this.except); - } - - public Contains(token: SyntaxKind): boolean { - return token !== this.except; - } - - public isSpecific() { return false; } - } - - export interface TokenRange { - GetTokens(): SyntaxKind[]; - Contains(token: SyntaxKind): boolean; - isSpecific(): boolean; - } - - export namespace TokenRange { - export function FromToken(token: SyntaxKind): TokenRange { - return new TokenSingleValueAccess(token); - } - - export function FromTokens(tokens: SyntaxKind[]): TokenRange { - return new TokenValuesAccess(tokens); - } - - export function FromRange(from: SyntaxKind, to: SyntaxKind, except: SyntaxKind[] = []): TokenRange { - const tokens: SyntaxKind[] = []; - for (let token = from; token <= to; token++) { - if (ts.indexOf(except, token) < 0) { - tokens.push(token); - } - } - return new TokenValuesAccess(tokens); - } - - export function AnyExcept(token: SyntaxKind): TokenRange { - return new TokenAllExceptAccess(token); - } - - export const Any: TokenRange = new TokenAllAccess(); - export const AnyIncludingMultilineComments = TokenRange.FromTokens([...allTokens, SyntaxKind.MultiLineCommentTrivia]); - export const Keywords = TokenRange.FromRange(SyntaxKind.FirstKeyword, SyntaxKind.LastKeyword); - export const BinaryOperators = TokenRange.FromRange(SyntaxKind.FirstBinaryOperator, SyntaxKind.LastBinaryOperator); - export const BinaryKeywordOperators = TokenRange.FromTokens([ - SyntaxKind.InKeyword, SyntaxKind.InstanceOfKeyword, SyntaxKind.OfKeyword, SyntaxKind.AsKeyword, SyntaxKind.IsKeyword]); - export const UnaryPrefixOperators = TokenRange.FromTokens([ - SyntaxKind.PlusPlusToken, SyntaxKind.MinusMinusToken, SyntaxKind.TildeToken, SyntaxKind.ExclamationToken]); - export const UnaryPrefixExpressions = TokenRange.FromTokens([ - SyntaxKind.NumericLiteral, SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, - SyntaxKind.OpenBraceToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]); - export const UnaryPreincrementExpressions = TokenRange.FromTokens([ - SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]); - export const UnaryPostincrementExpressions = TokenRange.FromTokens([ - SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]); - export const UnaryPredecrementExpressions = TokenRange.FromTokens([ - SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]); - export const UnaryPostdecrementExpressions = TokenRange.FromTokens([ - SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]); - export const Comments = TokenRange.FromTokens([SyntaxKind.SingleLineCommentTrivia, SyntaxKind.MultiLineCommentTrivia]); - export const TypeNames = TokenRange.FromTokens([ - SyntaxKind.Identifier, SyntaxKind.NumberKeyword, SyntaxKind.StringKeyword, SyntaxKind.BooleanKeyword, - SyntaxKind.SymbolKeyword, SyntaxKind.VoidKeyword, SyntaxKind.AnyKeyword]); - } - } -} diff --git a/src/services/goToDefinition.ts b/src/services/goToDefinition.ts index cb2be7d484c..35f4d079e29 100644 --- a/src/services/goToDefinition.ts +++ b/src/services/goToDefinition.ts @@ -88,7 +88,7 @@ namespace ts.GoToDefinition { // } // bar(({pr/*goto*/op1})=>{}); if (isPropertyName(node) && isBindingElement(node.parent) && isObjectBindingPattern(node.parent.parent) && - (node === (node.parent.propertyName || node.parent.name))) { + (node === (node.parent.propertyName || node.parent.name))) { const type = typeChecker.getTypeAtLocation(node.parent.parent); if (type) { const propSymbols = getPropertySymbolsFromType(type, node); @@ -149,6 +149,28 @@ namespace ts.GoToDefinition { return getDefinitionFromSymbol(typeChecker, type.symbol, node); } + export function getDefinitionAndBoundSpan(program: Program, sourceFile: SourceFile, position: number): DefinitionInfoAndBoundSpan { + const definitions = getDefinitionAtPosition(program, sourceFile, position); + + if (!definitions || definitions.length === 0) { + return undefined; + } + + // Check if position is on triple slash reference. + const comment = findReferenceInPosition(sourceFile.referencedFiles, position) || findReferenceInPosition(sourceFile.typeReferenceDirectives, position); + if (comment) { + return { + definitions, + textSpan: createTextSpanFromBounds(comment.pos, comment.end) + }; + } + + const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true); + const textSpan = createTextSpan(node.getStart(), node.getWidth()); + + return { definitions, textSpan }; + } + // Go to the original declaration for cases: // // (1) when the aliased symbol was declared in the location(parent). diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 3e9913fc6c7..79b08780226 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -1,5 +1,6 @@ /* @internal */ namespace ts.JsDoc { + const singleLineTemplate = { newText: "/** */", caretOffset: 3 }; const jsDocTagNames = [ "augments", "author", @@ -19,6 +20,7 @@ namespace ts.JsDoc { "fileOverview", "function", "ignore", + "inheritDoc", "inner", "lends", "link", @@ -65,19 +67,44 @@ namespace ts.JsDoc { return documentationComment; } - export function getJsDocTagsFromDeclarations(declarations?: Declaration[]) { + export function getJsDocTagsFromDeclarations(declarations?: Declaration[]): JSDocTagInfo[] { // Only collect doc comments from duplicate declarations once. const tags: JSDocTagInfo[] = []; forEachUnique(declarations, declaration => { for (const tag of getJSDocTags(declaration)) { - if (tag.kind === SyntaxKind.JSDocTag) { - tags.push({ name: tag.tagName.text, text: tag.comment }); - } + tags.push({ name: tag.tagName.text, text: getCommentText(tag) }); } }); return tags; } + function getCommentText(tag: JSDocTag): string { + const { comment } = tag; + switch (tag.kind) { + case SyntaxKind.JSDocAugmentsTag: + return withNode((tag as JSDocAugmentsTag).class); + case SyntaxKind.JSDocTemplateTag: + return withList((tag as JSDocTemplateTag).typeParameters); + case SyntaxKind.JSDocTypeTag: + return withNode((tag as JSDocTypeTag).typeExpression); + case SyntaxKind.JSDocTypedefTag: + case SyntaxKind.JSDocPropertyTag: + case SyntaxKind.JSDocParameterTag: + const { name } = tag as JSDocTypedefTag | JSDocPropertyTag | JSDocParameterTag; + return name ? withNode(name) : comment; + default: + return comment; + } + + function withNode(node: Node) { + return `${node.getText()} ${comment}`; + } + + function withList(list: NodeArray): string { + return `${list.map(x => x.getText())} ${comment}`; + } + } + /** * Iterates through 'array' by index and performs the callback on each element of array until the callback * returns a truthy value, then returns that value. @@ -170,13 +197,9 @@ namespace ts.JsDoc { /** * Checks if position points to a valid position to add JSDoc comments, and if so, * returns the appropriate template. Otherwise returns an empty string. - * Valid positions are - * - outside of comments, statements, and expressions, and - * - preceding a: - * - function/constructor/method declaration - * - class declarations - * - variable statements - * - namespace declarations + * Invalid positions are + * - within comments, strings (including template literals and regex), and JSXText + * - within a token * * Hosts should ideally check that: * - The line is all whitespace up to 'position' before performing the insertion. @@ -187,7 +210,8 @@ 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): TextInsertion { + + export function getDocCommentTemplateAtPosition(newLine: string, sourceFile: SourceFile, position: number): TextInsertion | undefined { // Check if in a context where we don't want to perform any insertion if (isInString(sourceFile, position) || isInComment(sourceFile, position) || hasDocComment(sourceFile, position)) { return undefined; @@ -201,13 +225,21 @@ namespace ts.JsDoc { const commentOwnerInfo = getCommentOwnerInfo(tokenAtPos); if (!commentOwnerInfo) { - return undefined; + // if climbing the tree did not find a declaration with parameters, complete to a single line comment + return singleLineTemplate; } const { commentOwner, parameters } = commentOwnerInfo; - if (commentOwner.getStart() < position) { + + if (commentOwner.kind === SyntaxKind.JsxText) { return undefined; } + if (commentOwner.getStart() < position || parameters.length === 0) { + // if climbing the tree found a declaration with parameters but the request was made inside it + // or if there are no parameters, complete to a single line comment + return singleLineTemplate; + } + const posLineAndChar = sourceFile.getLineAndCharacterOfPosition(position); const lineStart = sourceFile.getLineStarts()[posLineAndChar.line]; @@ -215,21 +247,11 @@ namespace ts.JsDoc { const indentationStr = sourceFile.text.substr(lineStart, posLineAndChar.character).replace(/\S/i, () => " "); const isJavaScriptFile = hasJavaScriptFileExtension(sourceFile.fileName); - let docParams = ""; - if (parameters) { - for (let i = 0; i < parameters.length; i++) { - const currentName = parameters[i].name; - const paramName = currentName.kind === SyntaxKind.Identifier ? - (currentName).escapedText : - "param" + i; - if (isJavaScriptFile) { - docParams += `${indentationStr} * @param {any} ${paramName}${newLine}`; - } - else { - docParams += `${indentationStr} * @param ${paramName}${newLine}`; - } - } - } + const docParams = parameters.map(({name}, i) => { + const nameText = isIdentifier(name) ? name.text : `param${i}`; + const type = isJavaScriptFile ? "{any} " : ""; + return `${indentationStr} * @param ${type}${nameText}${newLine}`; + }).join(""); // A doc comment consists of the following // * The opening comment line @@ -251,43 +273,30 @@ namespace ts.JsDoc { interface CommentOwnerInfo { readonly commentOwner: Node; - readonly parameters?: ReadonlyArray; + readonly parameters: ReadonlyArray; } function getCommentOwnerInfo(tokenAtPos: Node): CommentOwnerInfo | undefined { - // TODO: add support for: - // - enums/enum members - // - interfaces - // - property declarations - // - potentially property assignments for (let commentOwner = tokenAtPos; commentOwner; commentOwner = commentOwner.parent) { switch (commentOwner.kind) { case SyntaxKind.FunctionDeclaration: case SyntaxKind.MethodDeclaration: case SyntaxKind.Constructor: - const { parameters } = commentOwner as FunctionDeclaration | MethodDeclaration | ConstructorDeclaration; + case SyntaxKind.MethodSignature: + const { parameters } = commentOwner as FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature; return { commentOwner, parameters }; - case SyntaxKind.ClassDeclaration: - return { commentOwner }; - case SyntaxKind.VariableStatement: { const varStatement = commentOwner; const varDeclarations = varStatement.declarationList.declarations; const parameters = varDeclarations.length === 1 && varDeclarations[0].initializer ? getParametersFromRightHandSideOfAssignment(varDeclarations[0].initializer) : undefined; - return { commentOwner, parameters }; + return parameters ? { commentOwner, parameters } : undefined; } case SyntaxKind.SourceFile: return undefined; - case SyntaxKind.ModuleDeclaration: - // If in walking up the tree, we hit a a nested namespace declaration, - // then we must be somewhere within a dotted namespace name; however we don't - // want to give back a JSDoc template for the 'b' or 'c' in 'namespace a.b.c { }'. - return commentOwner.parent.kind === SyntaxKind.ModuleDeclaration ? undefined : { commentOwner }; - case SyntaxKind.BinaryExpression: { const be = commentOwner as BinaryExpression; if (getSpecialPropertyAssignmentKind(be) === ts.SpecialPropertyAssignmentKind.None) { @@ -296,6 +305,11 @@ namespace ts.JsDoc { const parameters = isFunctionLike(be.right) ? be.right.parameters : emptyArray; return { commentOwner, parameters }; } + + case SyntaxKind.JsxText: { + const parameters: ReadonlyArray = emptyArray; + return { commentOwner, parameters }; + } } } } diff --git a/src/services/jsTyping.ts b/src/services/jsTyping.ts index e31201b951f..1c2f87fa428 100644 --- a/src/services/jsTyping.ts +++ b/src/services/jsTyping.ts @@ -115,7 +115,10 @@ namespace ts.JsTyping { // add typings for unresolved imports if (unresolvedImports) { - const module = deduplicate(unresolvedImports.map(moduleId => nodeCoreModules.has(moduleId) ? "node" : moduleId)); + const module = deduplicate( + unresolvedImports.map(moduleId => nodeCoreModules.has(moduleId) ? "node" : moduleId), + equateStringsCaseSensitive, + compareStringsCaseSensitive); addInferredTypings(module, "Inferred typings from unresolved imports"); } // Add the cached typing locations for inferred typings that are already installed @@ -257,7 +260,7 @@ namespace ts.JsTyping { NameContainsNonURISafeCharacters } - const MaxPackageNameLength = 214; + const maxPackageNameLength = 214; /** * Validates package name using rules defined at https://docs.npmjs.com/files/package.json @@ -266,7 +269,7 @@ namespace ts.JsTyping { if (!packageName) { return PackageNameValidationResult.EmptyName; } - if (packageName.length > MaxPackageNameLength) { + if (packageName.length > maxPackageNameLength) { return PackageNameValidationResult.NameTooLong; } if (packageName.charCodeAt(0) === CharacterCodes.dot) { @@ -292,7 +295,7 @@ namespace ts.JsTyping { case PackageNameValidationResult.EmptyName: return `Package name '${typing}' cannot be empty`; case PackageNameValidationResult.NameTooLong: - return `Package name '${typing}' should be less than ${MaxPackageNameLength} characters`; + return `Package name '${typing}' should be less than ${maxPackageNameLength} characters`; case PackageNameValidationResult.NameStartsWithDot: return `Package name '${typing}' cannot start with '.'`; case PackageNameValidationResult.NameStartsWithUnderscore: diff --git a/src/services/navigateTo.ts b/src/services/navigateTo.ts index 7fa177b6a30..762726adb77 100644 --- a/src/services/navigateTo.ts +++ b/src/services/navigateTo.ts @@ -173,14 +173,10 @@ namespace ts.NavigateTo { return bestMatchKind; } - function compareNavigateToItems(i1: RawNavigateToItem, i2: RawNavigateToItem): number { + function compareNavigateToItems(i1: RawNavigateToItem, i2: RawNavigateToItem) { // TODO(cyrusn): get the gamut of comparisons that VS already uses here. - // Right now we just sort by kind first, and then by name of the item. - // We first sort case insensitively. So "Aaa" will come before "bar". - // Then we sort case sensitively, so "aaa" will come before "Aaa". - return i1.matchKind - i2.matchKind || - ts.compareStringsCaseInsensitive(i1.name, i2.name) || - ts.compareStrings(i1.name, i2.name); + return compareValues(i1.matchKind, i2.matchKind) + || compareStringsCaseSensitiveUI(i1.name, i2.name); } function createNavigateToItem(rawItem: RawNavigateToItem): NavigateToItem { diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index bf34f28fed6..7d3b8e1845a 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -366,15 +366,9 @@ namespace ts.NavigationBar { children.sort(compareChildren); } - function compareChildren(child1: NavigationBarNode, child2: NavigationBarNode): number { - const name1 = tryGetName(child1.node), name2 = tryGetName(child2.node); - if (name1 && name2) { - const cmp = ts.compareStringsCaseInsensitive(name1, name2); - return cmp !== 0 ? cmp : navigationBarNodeKind(child1) - navigationBarNodeKind(child2); - } - else { - return name1 ? 1 : name2 ? -1 : navigationBarNodeKind(child1) - navigationBarNodeKind(child2); - } + function compareChildren(child1: NavigationBarNode, child2: NavigationBarNode) { + return compareStringsCaseSensitiveUI(tryGetName(child1.node), tryGetName(child2.node)) + || compareValues(navigationBarNodeKind(child1), navigationBarNodeKind(child2)); } /** diff --git a/src/services/pathCompletions.ts b/src/services/pathCompletions.ts index 780b14db719..a6dfb53da80 100644 --- a/src/services/pathCompletions.ts +++ b/src/services/pathCompletions.ts @@ -1,34 +1,27 @@ /* @internal */ namespace ts.Completions.PathCompletions { - export function getStringLiteralCompletionEntriesFromModuleNames(node: StringLiteral, compilerOptions: CompilerOptions, host: LanguageServiceHost, typeChecker: TypeChecker): CompletionInfo { + export function getStringLiteralCompletionsFromModuleNames(node: StringLiteral, compilerOptions: CompilerOptions, host: LanguageServiceHost, typeChecker: TypeChecker): CompletionEntry[] { const literalValue = normalizeSlashes(node.text); const scriptPath = node.getSourceFile().path; const scriptDirectory = getDirectoryPath(scriptPath); const span = getDirectoryFragmentTextSpan((node).text, node.getStart() + 1); - let entries: CompletionEntry[]; if (isPathRelativeToScript(literalValue) || isRootedDiskPath(literalValue)) { const extensions = getSupportedExtensions(compilerOptions); if (compilerOptions.rootDirs) { - entries = getCompletionEntriesForDirectoryFragmentWithRootDirs( + return getCompletionEntriesForDirectoryFragmentWithRootDirs( compilerOptions.rootDirs, literalValue, scriptDirectory, extensions, /*includeExtensions*/ false, span, compilerOptions, host, scriptPath); } else { - entries = getCompletionEntriesForDirectoryFragment( + return getCompletionEntriesForDirectoryFragment( literalValue, scriptDirectory, extensions, /*includeExtensions*/ false, span, host, scriptPath); } } else { // Check for node modules - entries = getCompletionEntriesForNonRelativeModules(literalValue, scriptDirectory, span, compilerOptions, host, typeChecker); + return getCompletionEntriesForNonRelativeModules(literalValue, scriptDirectory, span, compilerOptions, host, typeChecker); } - return { - isGlobalCompletion: false, - isMemberCompletion: false, - isNewIdentifierLocation: true, - entries - }; } /** @@ -37,14 +30,17 @@ namespace ts.Completions.PathCompletions { */ function getBaseDirectoriesFromRootDirs(rootDirs: string[], basePath: string, scriptPath: string, ignoreCase: boolean): string[] { // Make all paths absolute/normalized if they are not already - rootDirs = map(rootDirs, 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 = forEach(rootDirs, rootDirectory => + const relativeDirectory = firstDefined(rootDirs, rootDirectory => containsPath(rootDirectory, scriptPath, basePath, ignoreCase) ? scriptPath.substr(rootDirectory.length) : undefined); // Now find a path for each potential directory that is to be merged with the one containing the script - return deduplicate(map(rootDirs, rootDirectory => combinePaths(rootDirectory, relativeDirectory))); + return deduplicate( + rootDirs.map(rootDirectory => combinePaths(rootDirectory, relativeDirectory)), + equateStringsCaseSensitive, + compareStringsCaseSensitive); } function getCompletionEntriesForDirectoryFragmentWithRootDirs(rootDirs: string[], fragment: string, scriptPath: string, extensions: ReadonlyArray, includeExtensions: boolean, span: TextSpan, compilerOptions: CompilerOptions, host: LanguageServiceHost, exclude?: string): CompletionEntry[] { @@ -144,8 +140,8 @@ namespace ts.Completions.PathCompletions { let result: CompletionEntry[]; + const fileExtensions = getSupportedExtensions(compilerOptions); if (baseUrl) { - const fileExtensions = getSupportedExtensions(compilerOptions); const projectDir = compilerOptions.project || host.getCurrentDirectory(); const absolute = isRootedDiskPath(baseUrl) ? baseUrl : combinePaths(projectDir, baseUrl); result = getCompletionEntriesForDirectoryFragment(fragment, normalizePath(absolute), fileExtensions, /*includeExtensions*/ false, span, host); @@ -176,6 +172,15 @@ namespace ts.Completions.PathCompletions { result = []; } + if (compilerOptions.moduleResolution === ts.ModuleResolutionKind.NodeJs) { + forEachAncestorDirectory(scriptPath, ancestor => { + const nodeModules = combinePaths(ancestor, "node_modules"); + if (host.directoryExists(nodeModules)) { + getCompletionEntriesForDirectoryFragment(fragment, nodeModules, fileExtensions, /*includeExtensions*/ false, span, host, /*exclude*/ undefined, result); + } + }); + } + getCompletionEntriesFromTypings(host, compilerOptions, scriptPath, span, result); for (const moduleName of enumeratePotentialNonRelativeModules(fragment, scriptPath, compilerOptions, typeChecker, host)) { @@ -271,64 +276,38 @@ namespace ts.Completions.PathCompletions { } } - return deduplicate(nonRelativeModuleNames); + return deduplicate(nonRelativeModuleNames, equateStringsCaseSensitive, compareStringsCaseSensitive); } - export function getTripleSlashReferenceCompletion(sourceFile: SourceFile, position: number, compilerOptions: CompilerOptions, host: LanguageServiceHost): CompletionInfo { + export function getTripleSlashReferenceCompletion(sourceFile: SourceFile, position: number, compilerOptions: CompilerOptions, host: LanguageServiceHost): CompletionEntry[] | undefined { const token = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false); - if (!token) { - return undefined; - } - const commentRanges: CommentRange[] = getLeadingCommentRanges(sourceFile.text, token.pos); - - if (!commentRanges || !commentRanges.length) { - return undefined; - } - - const range = forEach(commentRanges, commentRange => position >= commentRange.pos && position <= commentRange.end && commentRange); - + const commentRanges = getLeadingCommentRanges(sourceFile.text, token.pos); + const range = commentRanges && find(commentRanges, commentRange => position >= commentRange.pos && position <= commentRange.end); if (!range) { return undefined; } - - const completionInfo: CompletionInfo = { - /** - * We don't want the editor to offer any other completions, such as snippets, inside a comment. - */ - isGlobalCompletion: false, - isMemberCompletion: false, - /** - * 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. - */ - isNewIdentifierLocation: true, - - entries: [] - }; - - const text = sourceFile.text.substr(range.pos, position - range.pos); - + const text = sourceFile.text.slice(range.pos, position); const match = tripleSlashDirectiveFragmentRegex.exec(text); - - if (match) { - const prefix = match[1]; - const kind = match[2]; - const toComplete = match[3]; - - const scriptPath = getDirectoryPath(sourceFile.path); - if (kind === "path") { - // Give completions for a relative path - const span: TextSpan = getDirectoryFragmentTextSpan(toComplete, range.pos + prefix.length); - completionInfo.entries = getCompletionEntriesForDirectoryFragment(toComplete, scriptPath, getSupportedExtensions(compilerOptions), /*includeExtensions*/ true, span, host, sourceFile.path); - } - else { - // Give completions based on the typings available - const span: TextSpan = { start: range.pos + prefix.length, length: match[0].length - prefix.length }; - completionInfo.entries = getCompletionEntriesFromTypings(host, compilerOptions, scriptPath, span); - } + if (!match) { + return undefined; } - return completionInfo; + const [, prefix, kind, toComplete] = match; + const scriptPath = getDirectoryPath(sourceFile.path); + switch (kind) { + case "path": { + // Give completions for a relative path + const span = getDirectoryFragmentTextSpan(toComplete, range.pos + prefix.length); + return getCompletionEntriesForDirectoryFragment(toComplete, scriptPath, getSupportedExtensions(compilerOptions), /*includeExtensions*/ true, span, host, sourceFile.path); + } + case "types": { + // Give completions based on the typings available + const span = createTextSpan(range.pos + prefix.length, match[0].length - prefix.length); + return getCompletionEntriesFromTypings(host, compilerOptions, scriptPath, span); + } + default: + return undefined; + } } function getCompletionEntriesFromTypings(host: LanguageServiceHost, options: CompilerOptions, scriptPath: string, span: TextSpan, result: CompletionEntry[] = []): CompletionEntry[] { @@ -341,10 +320,9 @@ namespace ts.Completions.PathCompletions { else if (host.getDirectories) { let typeRoots: ReadonlyArray; try { - // Wrap in try catch because getEffectiveTypeRoots touches the filesystem typeRoots = getEffectiveTypeRoots(options, host); } - catch (e) {} + catch { /* Wrap in try catch because getEffectiveTypeRoots touches the filesystem */ } if (typeRoots) { for (const root of typeRoots) { @@ -376,26 +354,15 @@ namespace ts.Completions.PathCompletions { } } - function findPackageJsons(currentDir: string, host: LanguageServiceHost): string[] { + function findPackageJsons(directory: string, host: LanguageServiceHost): string[] { const paths: string[] = []; - let currentConfigPath: string; - while (true) { - currentConfigPath = findConfigFile(currentDir, (f) => tryFileExists(host, f), "package.json"); - if (currentConfigPath) { - paths.push(currentConfigPath); - - currentDir = getDirectoryPath(currentConfigPath); - const parent = getDirectoryPath(currentDir); - if (currentDir === parent) { - break; - } - currentDir = parent; + forEachAncestorDirectory(directory, ancestor => { + const currentConfigPath = findConfigFile(ancestor, (f) => tryFileExists(host, f), "package.json"); + if (!currentConfigPath) { + return true; // break out } - else { - break; - } - } - + paths.push(currentConfigPath); + }); return paths; } @@ -516,7 +483,7 @@ namespace ts.Completions.PathCompletions { try { return directoryProbablyExists(path, host); } - catch (e) {} + catch { /*ignore*/ } return undefined; } @@ -524,7 +491,7 @@ namespace ts.Completions.PathCompletions { try { return toApply && toApply.apply(host, args); } - catch (e) {} + catch { /*ignore*/ } return undefined; } } diff --git a/src/services/patternMatcher.ts b/src/services/patternMatcher.ts index 04f9d906d35..db957816146 100644 --- a/src/services/patternMatcher.ts +++ b/src/services/patternMatcher.ts @@ -515,10 +515,10 @@ namespace ts { } // Assumes 'value' is already lowercase. - function indexOfIgnoringCase(string: string, value: string): number { - const n = string.length - value.length; + function indexOfIgnoringCase(str: string, value: string): number { + const n = str.length - value.length; for (let i = 0; i <= n; i++) { - if (startsWithIgnoringCase(string, value, i)) { + if (startsWithIgnoringCase(str, value, i)) { return i; } } @@ -527,9 +527,9 @@ namespace ts { } // Assumes 'value' is already lowercase. - function startsWithIgnoringCase(string: string, value: string, start: number): boolean { + function startsWithIgnoringCase(str: string, value: string, start: number): boolean { for (let i = 0; i < value.length; i++) { - const ch1 = toLowerCase(string.charCodeAt(i + start)); + const ch1 = toLowerCase(str.charCodeAt(i + start)); const ch2 = value.charCodeAt(i); if (ch1 !== ch2) { diff --git a/src/services/refactors/convertFunctionToEs6Class.ts b/src/services/refactors/convertFunctionToEs6Class.ts index f5951bd26e4..b66d14ee449 100644 --- a/src/services/refactors/convertFunctionToEs6Class.ts +++ b/src/services/refactors/convertFunctionToEs6Class.ts @@ -50,7 +50,7 @@ namespace ts.refactor.convertFunctionToES6Class { const { file: sourceFile } = context; const ctorSymbol = getConstructorSymbol(context); - const newLine = context.rulesProvider.getFormatOptions().newLineCharacter; + const newLine = context.formatContext.options.newLineCharacter; const deletedNodes: Node[] = []; const deletes: (() => any)[] = []; diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts index b18e12d2b96..f1a461b0088 100644 --- a/src/services/refactors/extractSymbol.ts +++ b/src/services/refactors/extractSymbol.ts @@ -122,28 +122,28 @@ namespace ts.refactor.extractSymbol { return { message, code: 0, category: DiagnosticCategory.Message, key: message }; } - export const CannotExtractRange: DiagnosticMessage = createMessage("Cannot extract range."); - export const CannotExtractImport: DiagnosticMessage = createMessage("Cannot extract import statement."); - export const CannotExtractSuper: DiagnosticMessage = createMessage("Cannot extract super call."); - 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 TypeWillNotBeVisibleInTheNewScope = createMessage("Type 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 CannotExtractAmbientBlock = createMessage("Cannot extract code from ambient contexts"); - export const CannotAccessVariablesFromNestedScopes = createMessage("Cannot access variables from nested scopes"); - export const CannotExtractToOtherFunctionLike = createMessage("Cannot extract method to a function-like scope that is not a function"); - 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 cannotExtractRange: DiagnosticMessage = createMessage("Cannot extract range."); + export const cannotExtractImport: DiagnosticMessage = createMessage("Cannot extract import statement."); + export const cannotExtractSuper: DiagnosticMessage = createMessage("Cannot extract super call."); + 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 typeWillNotBeVisibleInTheNewScope = createMessage("Type 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 cannotExtractAmbientBlock = createMessage("Cannot extract code from ambient contexts"); + export const cannotAccessVariablesFromNestedScopes = createMessage("Cannot access variables from nested scopes"); + export const cannotExtractToOtherFunctionLike = createMessage("Cannot extract method to a function-like scope that is not a function"); + 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"); } enum RangeFacts { @@ -198,7 +198,7 @@ namespace ts.refactor.extractSymbol { const { length } = span; if (length === 0) { - return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.CannotExtractEmpty)] }; + return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.cannotExtractEmpty)] }; } // Walk up starting from the the start position until we find a non-SourceFile node that subsumes the selected span. @@ -215,18 +215,18 @@ namespace ts.refactor.extractSymbol { if (!start || !end) { // cannot find either start or end node - return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.CannotExtractRange)] }; + return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.cannotExtractRange)] }; } if (start.parent !== end.parent) { // start and end nodes belong to different subtrees - return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.CannotExtractRange)] }; + return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.cannotExtractRange)] }; } if (start !== end) { // start and end should be statements and parent should be either block or a source file if (!isBlockLike(start.parent)) { - return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.CannotExtractRange)] }; + return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.cannotExtractRange)] }; } const statements: Statement[] = []; for (const statement of (start.parent).statements) { @@ -246,7 +246,7 @@ namespace ts.refactor.extractSymbol { if (isReturnStatement(start) && !start.expression) { // Makes no sense to extract an expression-less return statement. - return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.CannotExtractRange)] }; + return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.cannotExtractRange)] }; } // We have a single node (start) @@ -293,7 +293,7 @@ namespace ts.refactor.extractSymbol { function checkRootNode(node: Node): Diagnostic[] | undefined { if (isIdentifier(isExpressionStatement(node) ? node.expression : node)) { - return [createDiagnosticForNode(node, Messages.CannotExtractIdentifier)]; + return [createDiagnosticForNode(node, Messages.cannotExtractIdentifier)]; } return undefined; } @@ -331,12 +331,12 @@ namespace ts.refactor.extractSymbol { Continue = 1 << 1, Return = 1 << 2 } - if (!isStatement(nodeToCheck) && !(isPartOfExpression(nodeToCheck) && isExtractableExpression(nodeToCheck))) { - return [createDiagnosticForNode(nodeToCheck, Messages.StatementOrExpressionExpected)]; + if (!isStatement(nodeToCheck) && !(isExpressionNode(nodeToCheck) && isExtractableExpression(nodeToCheck))) { + return [createDiagnosticForNode(nodeToCheck, Messages.statementOrExpressionExpected)]; } - if (isInAmbientContext(nodeToCheck)) { - return [createDiagnosticForNode(nodeToCheck, Messages.CannotExtractAmbientBlock)]; + if (nodeToCheck.flags & NodeFlags.Ambient) { + return [createDiagnosticForNode(nodeToCheck, Messages.cannotExtractAmbientBlock)]; } // If we're in a class, see whether we're in a static region (static property initializer, static method, class constructor parameter default) @@ -362,7 +362,7 @@ namespace ts.refactor.extractSymbol { if (isDeclaration(node)) { const declaringNode = (node.kind === SyntaxKind.VariableDeclaration) ? node.parent.parent : node; if (hasModifier(declaringNode, ModifierFlags.Export)) { - (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.CannotExtractExportedEntity)); + (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.cannotExtractExportedEntity)); return true; } declarations.push(node.symbol); @@ -371,7 +371,7 @@ namespace ts.refactor.extractSymbol { // Some things can't be extracted in certain situations switch (node.kind) { case SyntaxKind.ImportDeclaration: - (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.CannotExtractImport)); + (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.cannotExtractImport)); return true; case SyntaxKind.SuperKeyword: // For a super *constructor call*, we have to be extracting the entire class, @@ -380,7 +380,7 @@ namespace ts.refactor.extractSymbol { // Super constructor call const containingClass = getContainingClass(node); if (containingClass.pos < span.start || containingClass.end >= (span.start + span.length)) { - (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.CannotExtractSuper)); + (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.cannotExtractSuper)); return true; } } @@ -396,7 +396,7 @@ namespace ts.refactor.extractSymbol { case SyntaxKind.ClassDeclaration: if (node.parent.kind === SyntaxKind.SourceFile && (node.parent as ts.SourceFile).externalModuleIndicator === undefined) { // You cannot extract global declarations - (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.FunctionWillNotBeVisibleInTheNewScope)); + (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.functionWillNotBeVisibleInTheNewScope)); } break; } @@ -452,13 +452,13 @@ 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 || (errors = [])).push(createDiagnosticForNode(node, Messages.CannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange)); + (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.cannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange)); } } else { if (!(permittedJumps & (node.kind === SyntaxKind.BreakStatement ? PermittedJumps.Break : PermittedJumps.Continue))) { // attempt to break or continue in a forbidden context - (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.CannotExtractRangeContainingConditionalBreakOrContinueStatements)); + (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements)); } } break; @@ -474,7 +474,7 @@ namespace ts.refactor.extractSymbol { rangeFacts |= RangeFacts.HasReturn; } else { - (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.CannotExtractRangeContainingConditionalReturnStatement)); + (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.cannotExtractRangeContainingConditionalReturnStatement)); } break; default: @@ -491,7 +491,7 @@ namespace ts.refactor.extractSymbol { if (isStatement(node)) { return [node]; } - else if (isPartOfExpression(node)) { + else if (isExpressionNode(node)) { // If our selection is the expression in an ExpressionStatement, expand // the selection to include the enclosing Statement (this stops us // from trying to care about the return value of the extracted function @@ -730,7 +730,7 @@ 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 = checker.typeToTypeNode(type, node, NodeBuilderFlags.NoTruncation); + typeNode = checker.typeToTypeNode(type, scope, NodeBuilderFlags.NoTruncation); } const paramDecl = createParameter( @@ -1177,30 +1177,11 @@ namespace ts.refactor.extractSymbol { {type: type1, declaration: declaration1}: {type: Type, declaration?: Declaration}, {type: type2, declaration: declaration2}: {type: Type, declaration?: Declaration}) { - if (declaration1) { - if (declaration2) { - const positionDiff = declaration1.pos - declaration2.pos; - if (positionDiff !== 0) { - return positionDiff; - } - } - else { - return 1; // Sort undeclared type parameters to the front. - } - } - else if (declaration2) { - return -1; // Sort undeclared type parameters to the front. - } - - const name1 = type1.symbol ? type1.symbol.getName() : ""; - const name2 = type2.symbol ? type2.symbol.getName() : ""; - const nameDiff = compareStrings(name1, name2); - if (nameDiff !== 0) { - return nameDiff; - } - - // IDs are guaranteed to be unique, so this ensures a total ordering. - return type1.id - type2.id; + return compareProperties(declaration1, declaration2, "pos", compareValues) + || compareStringsCaseSensitive( + type1.symbol ? type1.symbol.getName() : "", + type2.symbol ? type2.symbol.getName() : "") + || compareValues(type1.id, type2.id); } function getCalledExpression(scope: Node, range: TargetRange, functionNameText: string): Expression { @@ -1455,10 +1436,10 @@ namespace ts.refactor.extractSymbol { const statements = targetRange.range as ReadonlyArray; const start = first(statements).getStart(); const end = last(statements).end; - expressionDiagnostic = createFileDiagnostic(sourceFile, start, end - start, Messages.ExpressionExpected); + expressionDiagnostic = createFileDiagnostic(sourceFile, start, end - start, Messages.expressionExpected); } else if (checker.getTypeAtLocation(expression).flags & (TypeFlags.Void | TypeFlags.Never)) { - expressionDiagnostic = createDiagnosticForNode(expression, Messages.UselessConstantType); + expressionDiagnostic = createDiagnosticForNode(expression, Messages.uselessConstantType); } // initialize results @@ -1468,7 +1449,7 @@ namespace ts.refactor.extractSymbol { functionErrorsPerScope.push( isFunctionLikeDeclaration(scope) && scope.kind !== SyntaxKind.FunctionDeclaration - ? [createDiagnosticForNode(scope, Messages.CannotExtractToOtherFunctionLike)] + ? [createDiagnosticForNode(scope, Messages.cannotExtractToOtherFunctionLike)] : []); const constantErrors = []; @@ -1476,11 +1457,11 @@ namespace ts.refactor.extractSymbol { constantErrors.push(expressionDiagnostic); } if (isClassLike(scope) && isInJavaScriptFile(scope)) { - constantErrors.push(createDiagnosticForNode(scope, Messages.CannotExtractToJSClass)); + constantErrors.push(createDiagnosticForNode(scope, Messages.cannotExtractToJSClass)); } if (isArrowFunction(scope) && !isBlock(scope.body)) { // TODO (https://github.com/Microsoft/TypeScript/issues/18924): allow this - constantErrors.push(createDiagnosticForNode(scope, Messages.CannotExtractToExpressionArrowFunction)); + constantErrors.push(createDiagnosticForNode(scope, Messages.cannotExtractToExpressionArrowFunction)); } constantErrorsPerScope.push(constantErrors); } @@ -1548,7 +1529,7 @@ 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)); } let hasWrite = false; @@ -1568,17 +1549,17 @@ namespace ts.refactor.extractSymbol { Debug.assert(isReadonlyArray(targetRange.range) || exposedVariableDeclarations.length === 0); if (hasWrite && !isReadonlyArray(targetRange.range)) { - const diag = createDiagnosticForNode(targetRange.range, Messages.CannotWriteInExpression); + const diag = createDiagnosticForNode(targetRange.range, Messages.cannotWriteInExpression); functionErrorsPerScope[i].push(diag); 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); } @@ -1710,7 +1691,7 @@ 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); } @@ -1733,7 +1714,7 @@ 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); } diff --git a/src/services/refactors/installTypesForPackage.ts b/src/services/refactors/installTypesForPackage.ts index 5edc5570710..996645fc15d 100644 --- a/src/services/refactors/installTypesForPackage.ts +++ b/src/services/refactors/installTypesForPackage.ts @@ -12,8 +12,7 @@ namespace ts.refactor.installTypesForPackage { registerRefactor(installTypesForPackage); function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined { - const options = context.program.getCompilerOptions(); - if (options.noImplicitAny || options.strict) { + if (getStrictOptionValue(context.program.getCompilerOptions(), "noImplicitAny")) { // Then it will be available via `fixCannotFindModule`. return undefined; } diff --git a/src/services/refactors/refactors.ts b/src/services/refactors/refactors.ts index f4b56422a89..3858b198743 100644 --- a/src/services/refactors/refactors.ts +++ b/src/services/refactors/refactors.ts @@ -2,3 +2,4 @@ /// /// /// +/// diff --git a/src/services/refactors/useDefaultImport.ts b/src/services/refactors/useDefaultImport.ts new file mode 100644 index 00000000000..56faf082a49 --- /dev/null +++ b/src/services/refactors/useDefaultImport.ts @@ -0,0 +1,96 @@ +/* @internal */ +namespace ts.refactor.installTypesForPackage { + const actionName = "Convert to default import"; + + const useDefaultImport: Refactor = { + name: actionName, + description: getLocaleSpecificMessage(Diagnostics.Convert_to_default_import), + getEditsForAction, + getAvailableActions, + }; + + registerRefactor(useDefaultImport); + + function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined { + const { file, startPosition, program } = context; + + if (!program.getCompilerOptions().allowSyntheticDefaultImports) { + return undefined; + } + + const importInfo = getConvertibleImportAtPosition(file, startPosition); + if (!importInfo) { + return undefined; + } + + const module = ts.getResolvedModule(file, importInfo.moduleSpecifier.text); + const resolvedFile = program.getSourceFile(module.resolvedFileName); + if (!(resolvedFile.externalModuleIndicator && isExportAssignment(resolvedFile.externalModuleIndicator) && resolvedFile.externalModuleIndicator.isExportEquals)) { + return undefined; + } + + return [ + { + name: useDefaultImport.name, + description: useDefaultImport.description, + actions: [ + { + description: useDefaultImport.description, + name: actionName, + }, + ], + }, + ]; + } + + function getEditsForAction(context: RefactorContext, _actionName: string): RefactorEditInfo | undefined { + const { file, startPosition } = context; + Debug.assertEqual(actionName, _actionName); + const importInfo = getConvertibleImportAtPosition(file, startPosition); + if (!importInfo) { + return undefined; + } + const { importStatement, name, moduleSpecifier } = importInfo; + const newImportClause = createImportClause(name, /*namedBindings*/ undefined); + const newImportStatement = ts.createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, newImportClause, moduleSpecifier); + return { + edits: textChanges.ChangeTracker.with(context, t => t.replaceNode(file, importStatement, newImportStatement)), + renameFilename: undefined, + renameLocation: undefined, + }; + } + + function getConvertibleImportAtPosition( + file: SourceFile, + startPosition: number, + ): { importStatement: AnyImportSyntax, name: Identifier, moduleSpecifier: StringLiteral } | undefined { + let node = getTokenAtPosition(file, startPosition, /*includeJsDocComment*/ false); + while (true) { + switch (node.kind) { + case SyntaxKind.ImportEqualsDeclaration: + const eq = node as ImportEqualsDeclaration; + const { moduleReference } = eq; + return moduleReference.kind === SyntaxKind.ExternalModuleReference && isStringLiteral(moduleReference.expression) + ? { importStatement: eq, name: eq.name, moduleSpecifier: moduleReference.expression } + : undefined; + case SyntaxKind.ImportDeclaration: + const d = node as ImportDeclaration; + const { importClause } = d; + return !importClause.name && importClause.namedBindings.kind === SyntaxKind.NamespaceImport && isStringLiteral(d.moduleSpecifier) + ? { importStatement: d, name: importClause.namedBindings.name, moduleSpecifier: d.moduleSpecifier } + : undefined; + // For known child node kinds of convertible imports, try again with parent node. + case SyntaxKind.NamespaceImport: + case SyntaxKind.ExternalModuleReference: + case SyntaxKind.ImportKeyword: + case SyntaxKind.Identifier: + case SyntaxKind.StringLiteral: + case SyntaxKind.AsteriskToken: + break; + default: + return undefined; + } + node = node.parent; + } + } +} diff --git a/src/services/services.ts b/src/services/services.ts index d6e75868852..37298c8eba8 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -31,16 +31,14 @@ namespace ts { /** The version of the language service API */ - export const servicesVersion = "0.5"; - - /* @internal */ - let ruleProvider: formatting.RulesProvider; + export const servicesVersion = "0.7"; function createNode(kind: TKind, pos: number, end: number, parent?: Node): NodeObject | TokenObject | IdentifierObject { const node = isNodeKind(kind) ? new NodeObject(kind, pos, end) : kind === SyntaxKind.Identifier ? new IdentifierObject(SyntaxKind.Identifier, pos, end) : new TokenObject(kind, pos, end); node.parent = parent; + node.flags = parent.flags & NodeFlags.ContextFlags; return node; } @@ -276,7 +274,10 @@ namespace ts { } public getText(sourceFile?: SourceFile): string { - return (sourceFile || this.getSourceFile()).text.substring(this.getStart(), this.getEnd()); + if (!sourceFile) { + sourceFile = this.getSourceFile(); + } + return sourceFile.text.substring(this.getStart(sourceFile), this.getEnd()); } public getChildCount(): number { @@ -342,9 +343,29 @@ namespace ts { return this.declarations; } - getDocumentationComment(): SymbolDisplayPart[] { + getDocumentationComment(checker: TypeChecker | undefined): SymbolDisplayPart[] { if (this.documentationComment === undefined) { - this.documentationComment = JsDoc.getJsDocCommentsFromDeclarations(this.declarations); + if (this.declarations) { + this.documentationComment = JsDoc.getJsDocCommentsFromDeclarations(this.declarations); + + if (this.documentationComment.length === 0 || this.declarations.some(hasJSDocInheritDocTag)) { + if (checker) { + for (const declaration of this.declarations) { + const inheritedDocs = findInheritedJSDocComments(declaration, this.getName(), checker); + if (inheritedDocs.length > 0) { + if (this.documentationComment.length > 0) { + inheritedDocs.push(ts.lineBreakPart()); + } + this.documentationComment = concatenate(inheritedDocs, this.documentationComment); + break; + } + } + } + } + } + else { + this.documentationComment = []; + } } return this.documentationComment; @@ -473,7 +494,23 @@ namespace ts { getDocumentationComment(): SymbolDisplayPart[] { if (this.documentationComment === undefined) { - this.documentationComment = this.declaration ? JsDoc.getJsDocCommentsFromDeclarations([this.declaration]) : []; + if (this.declaration) { + this.documentationComment = JsDoc.getJsDocCommentsFromDeclarations([this.declaration]); + + if (this.documentationComment.length === 0 || hasJSDocInheritDocTag(this.declaration)) { + const inheritedDocs = findInheritedJSDocComments(this.declaration, this.declaration.symbol.getName(), this.checker); + if (this.documentationComment.length > 0) { + inheritedDocs.push(ts.lineBreakPart()); + } + this.documentationComment = concatenate( + inheritedDocs, + this.documentationComment + ); + } + } + else { + this.documentationComment = []; + } } return this.documentationComment; @@ -488,6 +525,58 @@ namespace ts { } } + /** + * Returns whether or not the given node has a JSDoc "inheritDoc" tag on it. + * @param node the Node in question. + * @returns `true` if `node` has a JSDoc "inheritDoc" tag on it, otherwise `false`. + */ + function hasJSDocInheritDocTag(node: Node) { + return ts.getJSDocTags(node).some(tag => tag.tagName.text === "inheritDoc"); + } + + /** + * Attempts to find JSDoc comments for possibly-inherited properties. Checks superclasses then traverses + * implemented interfaces until a symbol is found with the same name and with documentation. + * @param declaration The possibly-inherited declaration to find comments for. + * @param propertyName The name of the possibly-inherited property. + * @param typeChecker A TypeChecker, used to find inherited properties. + * @returns A filled array of documentation comments if any were found, otherwise an empty array. + */ + function findInheritedJSDocComments(declaration: Declaration, propertyName: string, typeChecker: TypeChecker): SymbolDisplayPart[] { + let foundDocs = false; + return flatMap(getAllSuperTypeNodes(declaration), superTypeNode => { + if (foundDocs) { + return emptyArray; + } + const superType = typeChecker.getTypeAtLocation(superTypeNode); + if (!superType) { + return emptyArray; + } + const baseProperty = typeChecker.getPropertyOfType(superType, propertyName); + if (!baseProperty) { + return emptyArray; + } + const inheritedDocs = baseProperty.getDocumentationComment(typeChecker); + foundDocs = inheritedDocs.length > 0; + return inheritedDocs; + }); + } + + /** + * Finds and returns the `TypeNode` for all super classes and implemented interfaces given a declaration. + * @param declaration The possibly-inherited declaration. + * @returns A filled array of `TypeNode`s containing all super classes and implemented interfaces if any exist, otherwise an empty array. + */ + function getAllSuperTypeNodes(declaration: Declaration): ReadonlyArray { + const container = declaration.parent; + if (!container || (!isClassDeclaration(container) && !isInterfaceDeclaration(container))) { + return emptyArray; + } + const extended = getClassExtendsHeritageClauseElement(container); + const types = extended ? [extended] : emptyArray; + return isClassLike(container) ? concatenate(types, getClassImplementsHeritageClauseElements(container)) : types; + } + class SourceFileObject extends NodeObject implements SourceFile { public kind: SyntaxKind.SourceFile; public _declarationBrand: any; @@ -724,9 +813,9 @@ namespace ts { case SyntaxKind.BinaryExpression: if (getSpecialPropertyAssignmentKind(node as BinaryExpression) !== SpecialPropertyAssignmentKind.None) { - addDeclaration(node as BinaryExpression); + addDeclaration(node as BinaryExpression); } - // falls through + // falls through default: forEachChild(node, visit); @@ -1065,7 +1154,6 @@ namespace ts { documentRegistry: DocumentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), host.getCurrentDirectory())): LanguageService { const syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host); - ruleProvider = ruleProvider || new formatting.RulesProvider(); let program: Program; let lastProjectVersion: string; let lastTypesRootVersion = 0; @@ -1095,11 +1183,6 @@ namespace ts { return sourceFile; } - function getRuleProvider(options: FormatCodeSettings) { - ruleProvider.ensureUpToDate(options); - return ruleProvider; - } - function synchronizeHostData(): void { // perform fast check if host supports it if (host.getProjectVersion) { @@ -1322,14 +1405,21 @@ namespace ts { return [...program.getOptionsDiagnostics(cancellationToken), ...program.getGlobalDiagnostics(cancellationToken)]; } - function getCompletionsAtPosition(fileName: string, position: number): CompletionInfo { + function getCompletionsAtPosition(fileName: string, position: number, options: GetCompletionsAtPositionOptions = { includeExternalModuleExports: false }): CompletionInfo { synchronizeHostData(); - return Completions.getCompletionsAtPosition(host, program.getTypeChecker(), log, program.getCompilerOptions(), getValidSourceFile(fileName), position, program.getSourceFiles()); + return Completions.getCompletionsAtPosition( + host, + program.getTypeChecker(), + log, + program.getCompilerOptions(), + getValidSourceFile(fileName), + position, + program.getSourceFiles(), + options); } function getCompletionEntryDetails(fileName: string, position: number, name: string, formattingOptions?: FormatCodeSettings, source?: string): CompletionEntryDetails { synchronizeHostData(); - const ruleProvider = formattingOptions ? getRuleProvider(formattingOptions) : undefined; return Completions.getCompletionEntryDetails( program.getTypeChecker(), log, @@ -1339,7 +1429,7 @@ namespace ts { { name, source }, program.getSourceFiles(), host, - ruleProvider); + formattingOptions && formatting.getFormatContext(formattingOptions)); } function getCompletionEntrySymbol(fileName: string, position: number, name: string, source?: string): Symbol { @@ -1387,7 +1477,7 @@ namespace ts { kindModifiers: ScriptElementKindModifier.none, textSpan: createTextSpan(node.getStart(), node.getWidth()), displayParts: typeToDisplayParts(typeChecker, type, getContainerNode(node)), - documentation: type.symbol ? type.symbol.getDocumentationComment() : undefined, + documentation: type.symbol ? type.symbol.getDocumentationComment(typeChecker) : undefined, tags: type.symbol ? type.symbol.getJsDocTags() : undefined }; } @@ -1428,6 +1518,11 @@ namespace ts { return GoToDefinition.getDefinitionAtPosition(program, getValidSourceFile(fileName), position); } + function getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan { + synchronizeHostData(); + return GoToDefinition.getDefinitionAndBoundSpan(program, getValidSourceFile(fileName), position); + } + function getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] { synchronizeHostData(); return GoToDefinition.getTypeDefinitionAtPosition(program.getTypeChecker(), getValidSourceFile(fileName), position); @@ -1733,32 +1828,27 @@ namespace ts { function getFormattingEditsForRange(fileName: string, start: number, end: number, options: FormatCodeOptions | FormatCodeSettings): TextChange[] { const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); - const settings = toEditorSettings(options); - return formatting.formatSelection(start, end, sourceFile, getRuleProvider(settings), settings); + return formatting.formatSelection(start, end, sourceFile, formatting.getFormatContext(toEditorSettings(options))); } function getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[] { - const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); - const settings = toEditorSettings(options); - return formatting.formatDocument(sourceFile, getRuleProvider(settings), settings); + return formatting.formatDocument(syntaxTreeCache.getCurrentSourceFile(fileName), formatting.getFormatContext(toEditorSettings(options))); } function getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[] { const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); - const settings = toEditorSettings(options); + const formatContext = formatting.getFormatContext(toEditorSettings(options)); if (!isInComment(sourceFile, position)) { - if (key === "{") { - return formatting.formatOnOpeningCurly(position, sourceFile, getRuleProvider(settings), settings); - } - else if (key === "}") { - return formatting.formatOnClosingCurly(position, sourceFile, getRuleProvider(settings), settings); - } - else if (key === ";") { - return formatting.formatOnSemicolon(position, sourceFile, getRuleProvider(settings), settings); - } - else if (key === "\n") { - return formatting.formatOnEnter(position, sourceFile, getRuleProvider(settings), settings); + switch (key) { + case "{": + return formatting.formatOnOpeningCurly(position, sourceFile, formatContext); + case "}": + return formatting.formatOnClosingCurly(position, sourceFile, formatContext); + case ";": + return formatting.formatOnSemicolon(position, sourceFile, formatContext); + case "\n": + return formatting.formatOnEnter(position, sourceFile, formatContext); } } @@ -1770,11 +1860,11 @@ namespace ts { const sourceFile = getValidSourceFile(fileName); const span = createTextSpanFromBounds(start, end); const newLineCharacter = getNewLineOrDefaultFromHost(host); - const rulesProvider = getRuleProvider(formatOptions); + const formatContext = formatting.getFormatContext(formatOptions); - return flatMap(deduplicate(errorCodes), errorCode => { + return flatMap(deduplicate(errorCodes, equateValues, compareValues), errorCode => { cancellationToken.throwIfCancellationRequested(); - return codefix.getFixes({ errorCode, sourceFile, span, program, newLineCharacter, host, cancellationToken, rulesProvider }); + return codefix.getFixes({ errorCode, sourceFile, span, program, newLineCharacter, host, cancellationToken, formatContext }); }); } @@ -1791,7 +1881,7 @@ namespace ts { } } - function getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion { + function getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion | undefined { return JsDoc.getDocCommentTemplateAtPosition(getNewLineOrDefaultFromHost(host), syntaxTreeCache.getCurrentSourceFile(fileName), position); } @@ -1980,9 +2070,7 @@ namespace ts { } function isNodeModulesFile(path: string): boolean { - const node_modulesFolderName = "/node_modules/"; - - return stringContains(path, node_modulesFolderName); + return stringContains(path, "/node_modules/"); } } @@ -2001,7 +2089,7 @@ namespace ts { program: getProgram(), newLineCharacter: formatOptions ? formatOptions.newLineCharacter : host.getNewLine(), host, - rulesProvider: getRuleProvider(formatOptions), + formatContext: formatting.getFormatContext(formatOptions), cancellationToken, }; } @@ -2040,6 +2128,7 @@ namespace ts { getSignatureHelpItems, getQuickInfoAtPosition, getDefinitionAtPosition, + getDefinitionAndBoundSpan, getImplementationAtPosition, getTypeDefinitionAtPosition, getReferencesAtPosition, diff --git a/src/services/shims.ts b/src/services/shims.ts index 6e979e22023..7c932361c10 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -106,7 +106,7 @@ namespace ts { /// // Note: This is being using by the host (VS) and is marshaled back and forth. // When changing this make sure the changes are reflected in the managed side as well - export interface IFileReference { + export interface ShimsFileReference { path: string; position: number; length: number; @@ -140,8 +140,8 @@ namespace ts { getEncodedSyntacticClassifications(fileName: string, start: number, length: number): string; getEncodedSemanticClassifications(fileName: string, start: number, length: number): string; - getCompletionsAtPosition(fileName: string, position: number): string; - getCompletionEntryDetails(fileName: string, position: number, entryName: string, options: string/*Services.FormatCodeOptions*/): string; + getCompletionsAtPosition(fileName: string, position: number, options: GetCompletionsAtPositionOptions | undefined): string; + getCompletionEntryDetails(fileName: string, position: number, entryName: string, options: string/*Services.FormatCodeOptions*/, source: string | undefined): string; getQuickInfoAtPosition(fileName: string, position: number): string; @@ -170,6 +170,8 @@ namespace ts { */ getDefinitionAtPosition(fileName: string, position: number): string; + getDefinitionAndBoundSpan(fileName: string, position: number): string; + /** * Returns a JSON-encoded value of the type: * { fileName: string; textSpan: { start: number; length: number}; kind: string; name: string; containerKind: string; containerName: string } @@ -772,6 +774,17 @@ namespace ts { ); } + /** + * Computes the definition location and file for the symbol + * at the requested position. + */ + public getDefinitionAndBoundSpan(fileName: string, position: number): string { + return this.forwardJSONCall( + `getDefinitionAndBoundSpan('${fileName}', ${position})`, + () => this.languageService.getDefinitionAndBoundSpan(fileName, position) + ); + } + /// GOTO Type /** @@ -885,20 +898,20 @@ namespace ts { * to provide at the given source position and providing a member completion * list if requested. */ - public getCompletionsAtPosition(fileName: string, position: number) { + public getCompletionsAtPosition(fileName: string, position: number, options: GetCompletionsAtPositionOptions | undefined) { return this.forwardJSONCall( - `getCompletionsAtPosition('${fileName}', ${position})`, - () => this.languageService.getCompletionsAtPosition(fileName, position) + `getCompletionsAtPosition('${fileName}', ${position}, ${options})`, + () => this.languageService.getCompletionsAtPosition(fileName, position, options) ); } /** Get a string based representation of a completion list entry details */ - public getCompletionEntryDetails(fileName: string, position: number, entryName: string, options: string/*Services.FormatCodeOptions*/) { + public getCompletionEntryDetails(fileName: string, position: number, entryName: string, options: string/*Services.FormatCodeOptions*/, source: string | undefined) { return this.forwardJSONCall( `getCompletionEntryDetails('${fileName}', ${position}, '${entryName}')`, () => { const localOptions: ts.FormatCodeOptions = JSON.parse(options); - return this.languageService.getCompletionEntryDetails(fileName, position, entryName, localOptions); + return this.languageService.getCompletionEntryDetails(fileName, position, entryName, localOptions, source); } ); } @@ -1091,11 +1104,11 @@ namespace ts { ); } - private convertFileReferences(refs: FileReference[]): IFileReference[] { + private convertFileReferences(refs: FileReference[]): ShimsFileReference[] { if (!refs) { return undefined; } - const result: IFileReference[] = []; + const result: ShimsFileReference[] = []; for (const ref of refs) { result.push({ path: normalizeSlashes(ref.fileName), diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index 7e8e748bb17..36c83f5f4af 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -400,7 +400,7 @@ namespace ts.SignatureHelp { suffixDisplayParts, separatorDisplayParts: [punctuationPart(SyntaxKind.CommaToken), spacePart()], parameters: signatureHelpParameters, - documentation: candidateSignature.getDocumentationComment(), + documentation: candidateSignature.getDocumentationComment(typeChecker), tags: candidateSignature.getJsDocTags() }; }); @@ -420,7 +420,7 @@ namespace ts.SignatureHelp { return { name: parameter.name, - documentation: parameter.getDocumentationComment(), + documentation: parameter.getDocumentationComment(typeChecker), displayParts, isOptional: typeChecker.isOptionalParameter(parameter.valueDeclaration) }; @@ -438,4 +438,4 @@ namespace ts.SignatureHelp { }; } } -} \ No newline at end of file +} diff --git a/src/services/symbolDisplay.ts b/src/services/symbolDisplay.ts index d38d21f1092..fe04342b8f7 100644 --- a/src/services/symbolDisplay.ts +++ b/src/services/symbolDisplay.ts @@ -75,10 +75,16 @@ namespace ts.SymbolDisplay { } return unionPropertyKind; } - if (location.parent && isJsxAttribute(location.parent)) { - return ScriptElementKind.jsxAttribute; + // If we requested completions after `x.` at the top-level, we may be at a source file location. + switch (location.parent && location.parent.kind) { + // If we've typed a character of the attribute name, will be 'JsxAttribute', else will be 'JsxOpeningElement'. + case SyntaxKind.JsxOpeningElement: + return location.kind === SyntaxKind.Identifier ? ScriptElementKind.memberVariableElement : ScriptElementKind.jsxAttribute; + case SyntaxKind.JsxAttribute: + return ScriptElementKind.jsxAttribute; + default: + return ScriptElementKind.memberVariableElement; } - return ScriptElementKind.memberVariableElement; } return ScriptElementKind.unknown; @@ -90,9 +96,16 @@ namespace ts.SymbolDisplay { : ScriptElementKindModifier.none; } + interface SymbolDisplayPartsDocumentationAndSymbolKind { + displayParts: SymbolDisplayPart[]; + documentation: SymbolDisplayPart[]; + symbolKind: ScriptElementKind; + tags: JSDocTagInfo[]; + } + // 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, - location: Node, semanticMeaning = getMeaningFromLocation(location)) { + location: Node, semanticMeaning = getMeaningFromLocation(location)): SymbolDisplayPartsDocumentationAndSymbolKind { const displayParts: SymbolDisplayPart[] = []; let documentation: SymbolDisplayPart[]; @@ -178,13 +191,14 @@ namespace ts.SymbolDisplay { // If it is call or construct signature of lambda's write type name displayParts.push(punctuationPart(SyntaxKind.ColonToken)); displayParts.push(spacePart()); + if (!(type.flags & TypeFlags.Object && (type).objectFlags & ObjectFlags.Anonymous) && type.symbol) { + addRange(displayParts, symbolToDisplayParts(typeChecker, type.symbol, enclosingDeclaration, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments)); + displayParts.push(lineBreakPart()); + } if (useConstructSignatures) { displayParts.push(keywordPart(SyntaxKind.NewKeyword)); displayParts.push(spacePart()); } - if (!(type.flags & TypeFlags.Object && (type).objectFlags & ObjectFlags.Anonymous) && type.symbol) { - addRange(displayParts, symbolToDisplayParts(typeChecker, type.symbol, enclosingDeclaration, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments)); - } addSignatureDisplayParts(signature, allSignatures, TypeFormatFlags.WriteArrowStyleSignature); break; @@ -431,7 +445,7 @@ namespace ts.SymbolDisplay { } if (!documentation) { - documentation = symbol.getDocumentationComment(); + documentation = symbol.getDocumentationComment(typeChecker); tags = symbol.getJsDocTags(); if (documentation.length === 0 && symbolFlags & SymbolFlags.Property) { // For some special property access expressions like `exports.foo = foo` or `module.exports.foo = foo` @@ -448,7 +462,7 @@ namespace ts.SymbolDisplay { continue; } - documentation = rhsSymbol.getDocumentationComment(); + documentation = rhsSymbol.getDocumentationComment(typeChecker); tags = rhsSymbol.getJsDocTags(); if (documentation.length > 0) { break; @@ -482,8 +496,10 @@ namespace ts.SymbolDisplay { addNewLineIfDisplayPartsExist(); if (symbolKind) { pushTypePart(symbolKind); - displayParts.push(spacePart()); - addFullSymbolName(symbol); + if (!some(symbol.declarations, d => isArrowFunction(d) || (isFunctionExpression(d) || isClassExpression(d)) && !d.name)) { + displayParts.push(spacePart()); + addFullSymbolName(symbol); + } } } @@ -515,7 +531,7 @@ namespace ts.SymbolDisplay { displayParts.push(textPart(allSignatures.length === 2 ? "overload" : "overloads")); displayParts.push(punctuationPart(SyntaxKind.CloseParenToken)); } - documentation = signature.getDocumentationComment(); + documentation = signature.getDocumentationComment(typeChecker); tags = signature.getJsDocTags(); } diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index bc3a8e27ef0..7c4e25537ef 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -188,7 +188,7 @@ namespace ts.textChanges { export interface TextChangesContext { newLineCharacter: string; - rulesProvider: formatting.RulesProvider; + formatContext: ts.formatting.FormatContext; } export class ChangeTracker { @@ -196,7 +196,7 @@ namespace ts.textChanges { private readonly newLineCharacter: string; public static fromContext(context: TextChangesContext): ChangeTracker { - return new ChangeTracker(context.newLineCharacter === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed, context.rulesProvider); + return new ChangeTracker(context.newLineCharacter === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed, context.formatContext); } public static with(context: TextChangesContext, cb: (tracker: ChangeTracker) => void): FileTextChanges[] { @@ -207,7 +207,7 @@ namespace ts.textChanges { constructor( private readonly newLine: NewLineKind, - private readonly rulesProvider: formatting.RulesProvider, + private readonly formatContext: ts.formatting.FormatContext, private readonly validator?: (text: NonFormattedText) => void) { this.newLineCharacter = getNewLineCharacter({ newLine }); } @@ -475,7 +475,7 @@ namespace ts.textChanges { options: {} }); // use the same indentation as 'after' item - const indentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn(afterStartLinePosition, afterStart, sourceFile, this.rulesProvider.getFormatOptions()); + 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); if (insertPos !== end && isLineBreak(sourceFile.text.charCodeAt(insertPos - 1))) { @@ -562,7 +562,7 @@ namespace ts.textChanges { this.validator(nonformattedText); } - const formatOptions = this.rulesProvider.getFormatOptions(); + const { options: formatOptions } = this.formatContext; const posStartsLine = getLineStartPositionForPosition(pos, sourceFile) === pos; const initialIndentation = @@ -578,7 +578,7 @@ namespace ts.textChanges { ? (formatOptions.indentSize || 0) : 0; - return applyFormatting(nonformattedText, sourceFile, initialIndentation, delta, this.rulesProvider); + return applyFormatting(nonformattedText, sourceFile, initialIndentation, delta, this.formatContext); } private static normalize(changes: Change[]): Change[] { @@ -605,14 +605,14 @@ namespace ts.textChanges { return { text: writer.getText(), node: assignPositionsToNode(node) }; } - function applyFormatting(nonFormattedText: NonFormattedText, sourceFile: SourceFile, initialIndentation: number, delta: number, rulesProvider: formatting.RulesProvider) { + function applyFormatting(nonFormattedText: NonFormattedText, sourceFile: SourceFile, initialIndentation: number, delta: number, formatContext: ts.formatting.FormatContext) { const lineMap = computeLineStarts(nonFormattedText.text); const file: SourceFileLike = { text: nonFormattedText.text, lineMap, getLineAndCharacterOfPosition: pos => computeLineAndCharacterOfPosition(lineMap, pos) }; - const changes = formatting.formatNodeGivenIndentation(nonFormattedText.node, file, sourceFile.languageVariant, initialIndentation, delta, rulesProvider); + const changes = formatting.formatNodeGivenIndentation(nonFormattedText.node, file, sourceFile.languageVariant, initialIndentation, delta, formatContext); return applyChanges(nonFormattedText.text, changes); } diff --git a/src/services/types.ts b/src/services/types.ts index c854eb8aacc..a9244982fbb 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -5,9 +5,11 @@ namespace ts { getChildAt(index: number, sourceFile?: SourceFile): Node; getChildren(sourceFile?: SourceFile): Node[]; /* @internal */ + // tslint:disable-next-line unified-signatures getChildren(sourceFile?: SourceFileLike): Node[]; getStart(sourceFile?: SourceFile, includeJsDocComment?: boolean): number; /* @internal */ + // tslint:disable-next-line unified-signatures getStart(sourceFile?: SourceFileLike, includeJsDocComment?: boolean): number; getFullStart(): number; getEnd(): number; @@ -32,7 +34,7 @@ namespace ts { getEscapedName(): __String; getName(): string; getDeclarations(): Declaration[] | undefined; - getDocumentationComment(): SymbolDisplayPart[]; + getDocumentationComment(typeChecker: TypeChecker | undefined): SymbolDisplayPart[]; getJsDocTags(): JSDocTagInfo[]; } @@ -55,7 +57,7 @@ namespace ts { getTypeParameters(): TypeParameter[] | undefined; getParameters(): Symbol[]; getReturnType(): Type; - getDocumentationComment(): SymbolDisplayPart[]; + getDocumentationComment(typeChecker: TypeChecker | undefined): SymbolDisplayPart[]; getJsDocTags(): JSDocTagInfo[]; } @@ -86,6 +88,7 @@ namespace ts { * snapshot is observably immutable. i.e. the same calls with the same parameters will return * the same values. */ + // tslint:disable-next-line interface-name export interface IScriptSnapshot { /** Gets a portion of the script snapshot specified by [start, end). */ getText(start: number, end: number): string; @@ -236,10 +239,16 @@ namespace ts { getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications; getEncodedSemanticClassifications(fileName: string, span: TextSpan): Classifications; - getCompletionsAtPosition(fileName: string, position: number): CompletionInfo; + getCompletionsAtPosition(fileName: string, position: number, options: GetCompletionsAtPositionOptions | undefined): CompletionInfo; // "options" and "source" are optional only for backwards-compatibility - getCompletionEntryDetails(fileName: string, position: number, name: string, options?: FormatCodeOptions | FormatCodeSettings, source?: string): CompletionEntryDetails; - getCompletionEntrySymbol(fileName: string, position: number, name: string, source?: string): Symbol; + getCompletionEntryDetails( + fileName: string, + position: number, + name: string, + options: FormatCodeOptions | FormatCodeSettings | undefined, + source: string | undefined, + ): CompletionEntryDetails; + getCompletionEntrySymbol(fileName: string, position: number, name: string, source: string | undefined): Symbol; getQuickInfoAtPosition(fileName: string, position: number): QuickInfo; @@ -253,6 +262,7 @@ namespace ts { findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[]; getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; + getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan; getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; getImplementationAtPosition(fileName: string, position: number): ImplementationLocation[]; @@ -302,6 +312,10 @@ namespace ts { dispose(): void; } + export interface GetCompletionsAtPositionOptions { + includeExternalModuleExports: boolean; + } + export interface ApplyCodeActionCommandResult { successMessage: string; } @@ -575,6 +589,11 @@ namespace ts { containerName: string; } + export interface DefinitionInfoAndBoundSpan { + definitions: ReadonlyArray; + textSpan: TextSpan; + } + export interface ReferencedSymbolDefinitionInfo extends DefinitionInfo { displayParts: SymbolDisplayPart[]; } diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 2b116eb1cd0..1ed44d29f95 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -178,7 +178,7 @@ namespace ts { switch (node.kind) { case SyntaxKind.ThisKeyword: - return !isPartOfExpression(node); + return !isExpressionNode(node); case SyntaxKind.ThisType: return true; } @@ -947,7 +947,7 @@ namespace ts { if (flags & ModifierFlags.Static) result.push(ScriptElementKindModifier.staticModifier); if (flags & ModifierFlags.Abstract) result.push(ScriptElementKindModifier.abstractModifier); if (flags & ModifierFlags.Export) result.push(ScriptElementKindModifier.exportedModifier); - if (isInAmbientContext(node)) result.push(ScriptElementKindModifier.ambientModifier); + if (node.flags & NodeFlags.Ambient) result.push(ScriptElementKindModifier.ambientModifier); return result.length > 0 ? result.join(",") : ScriptElementKindModifier.none; } @@ -1068,20 +1068,19 @@ namespace ts { return createTextSpanFromBounds(range.pos, range.end); } + export const typeKeywords: ReadonlyArray = [ + SyntaxKind.AnyKeyword, + SyntaxKind.BooleanKeyword, + SyntaxKind.NeverKeyword, + SyntaxKind.NumberKeyword, + SyntaxKind.ObjectKeyword, + SyntaxKind.StringKeyword, + SyntaxKind.SymbolKeyword, + SyntaxKind.VoidKeyword, + ]; + export function isTypeKeyword(kind: SyntaxKind): boolean { - switch (kind) { - case SyntaxKind.AnyKeyword: - case SyntaxKind.BooleanKeyword: - case SyntaxKind.NeverKeyword: - case SyntaxKind.NumberKeyword: - case SyntaxKind.ObjectKeyword: - case SyntaxKind.StringKeyword: - case SyntaxKind.SymbolKeyword: - case SyntaxKind.VoidKeyword: - return true; - default: - return false; - } + return contains(typeKeywords, kind); } /** True if the symbol is for an external module, as opposed to a namespace. */ @@ -1330,23 +1329,39 @@ namespace ts { export function getSourceFileImportLocation(node: SourceFile) { // For a source file, it is possible there are detached comments we should not skip const text = node.text; + const textLength = text.length; let ranges = getLeadingCommentRanges(text, 0); if (!ranges) return 0; let position = 0; // However we should still skip a pinned comment at the top if (ranges.length && ranges[0].kind === SyntaxKind.MultiLineCommentTrivia && isPinnedComment(text, ranges[0])) { - position = ranges[0].end + 1; + position = ranges[0].end; + advancePastLineBreak(); ranges = ranges.slice(1); } // As well as any triple slash references for (const range of ranges) { if (range.kind === SyntaxKind.SingleLineCommentTrivia && isRecognizedTripleSlashComment(node.text, range.pos, range.end)) { - position = range.end + 1; + position = range.end; + advancePastLineBreak(); continue; } break; } return position; + + function advancePastLineBreak() { + if (position < textLength) { + const charCode = text.charCodeAt(position); + if (isLineBreak(charCode)) { + position++; + + if (position < textLength && charCode === CharacterCodes.carriageReturn && text.charCodeAt(position) === CharacterCodes.lineFeed) { + position++; + } + } + } + } } /** @@ -1398,7 +1413,9 @@ namespace ts { addEmitFlags(node, EmitFlags.NoLeadingComments); const firstChild = forEachChild(node, child => child); - firstChild && suppressLeading(firstChild); + if (firstChild) { + suppressLeading(firstChild); + } } function suppressTrailing(node: Node) { @@ -1415,7 +1432,9 @@ namespace ts { } return undefined; }); - lastChild && suppressTrailing(lastChild); + if (lastChild) { + suppressTrailing(lastChild); + } } } } diff --git a/tests/baselines/reference/APISample_jsdoc.js b/tests/baselines/reference/APISample_jsdoc.js index c74e188f38b..f28b16d88b6 100644 --- a/tests/baselines/reference/APISample_jsdoc.js +++ b/tests/baselines/reference/APISample_jsdoc.js @@ -21,7 +21,7 @@ function parseCommentsIntoDefinition(this: any, } // the comments for a symbol - let comments = symbol.getDocumentationComment(); + let comments = symbol.getDocumentationComment(undefined); if (comments.length) { definition.description = comments.map(comment => comment.kind === "lineBreak" ? comment.text : comment.text.trim().replace(/\r\n/g, "\n")).join(""); @@ -131,7 +131,7 @@ function parseCommentsIntoDefinition(symbol, definition, otherAnnotations) { return; } // the comments for a symbol - var comments = symbol.getDocumentationComment(); + var comments = symbol.getDocumentationComment(undefined); if (comments.length) { definition.description = comments.map(function (comment) { return comment.kind === "lineBreak" ? comment.text : comment.text.trim().replace(/\r\n/g, "\n"); }).join(""); } diff --git a/tests/baselines/reference/abstractClassInLocalScopeIsAbstract.errors.txt b/tests/baselines/reference/abstractClassInLocalScopeIsAbstract.errors.txt index f5c5b417ea3..fa02cb21d34 100644 --- a/tests/baselines/reference/abstractClassInLocalScopeIsAbstract.errors.txt +++ b/tests/baselines/reference/abstractClassInLocalScopeIsAbstract.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/abstractClassInLocalScopeIsAbstract.ts(4,5): error TS2511: Cannot create an instance of the abstract class 'A'. +tests/cases/compiler/abstractClassInLocalScopeIsAbstract.ts(4,5): error TS2511: Cannot create an instance of an abstract class. ==== tests/cases/compiler/abstractClassInLocalScopeIsAbstract.ts (1 errors) ==== @@ -7,7 +7,7 @@ tests/cases/compiler/abstractClassInLocalScopeIsAbstract.ts(4,5): error TS2511: class B extends A {} new A(); ~~~~~~~ -!!! error TS2511: Cannot create an instance of the abstract class 'A'. +!!! error TS2511: Cannot create an instance of an abstract class. new B(); })() \ No newline at end of file diff --git a/tests/baselines/reference/abstractPropertyInConstructor.errors.txt b/tests/baselines/reference/abstractPropertyInConstructor.errors.txt index 461dd713d3b..0798d91ce78 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.errors.txt +++ b/tests/baselines/reference/abstractPropertyInConstructor.errors.txt @@ -5,7 +5,7 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(9,14): error TS2715: Abstr ==== tests/cases/compiler/abstractPropertyInConstructor.ts (3 errors) ==== abstract class AbstractClass { - constructor(str: string) { + constructor(str: string, other: AbstractClass) { this.method(parseInt(str)); let val = this.prop.toLowerCase(); ~~~~ @@ -20,9 +20,13 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(9,14): error TS2715: Abstr ~~ !!! error TS2715: Abstract property 'cb' in class 'AbstractClass' cannot be accessed in the constructor. + // OK, reference is inside function const innerFunction = () => { return this.prop; } + + // OK, references are to another instance + other.cb(other.prop); } abstract prop: string; @@ -34,4 +38,13 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(9,14): error TS2715: Abstr this.prop = this.prop + "!"; } } + + class User { + constructor(a: AbstractClass) { + a.prop; + a.cb("hi"); + a.method(12); + a.method2(); + } + } \ No newline at end of file diff --git a/tests/baselines/reference/abstractPropertyInConstructor.js b/tests/baselines/reference/abstractPropertyInConstructor.js index 18a2937a191..5a4feda110f 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.js +++ b/tests/baselines/reference/abstractPropertyInConstructor.js @@ -1,6 +1,6 @@ //// [abstractPropertyInConstructor.ts] abstract class AbstractClass { - constructor(str: string) { + constructor(str: string, other: AbstractClass) { this.method(parseInt(str)); let val = this.prop.toLowerCase(); @@ -9,9 +9,13 @@ abstract class AbstractClass { } this.cb(str); + // OK, reference is inside function const innerFunction = () => { return this.prop; } + + // OK, references are to another instance + other.cb(other.prop); } abstract prop: string; @@ -23,11 +27,20 @@ abstract class AbstractClass { this.prop = this.prop + "!"; } } + +class User { + constructor(a: AbstractClass) { + a.prop; + a.cb("hi"); + a.method(12); + a.method2(); + } +} //// [abstractPropertyInConstructor.js] var AbstractClass = /** @class */ (function () { - function AbstractClass(str) { + function AbstractClass(str, other) { var _this = this; this.method(parseInt(str)); var val = this.prop.toLowerCase(); @@ -35,12 +48,24 @@ var AbstractClass = /** @class */ (function () { this.prop = "Hello World"; } this.cb(str); + // OK, reference is inside function var innerFunction = function () { return _this.prop; }; + // OK, references are to another instance + other.cb(other.prop); } AbstractClass.prototype.method2 = function () { this.prop = this.prop + "!"; }; return AbstractClass; }()); +var User = /** @class */ (function () { + function User(a) { + a.prop; + a.cb("hi"); + a.method(12); + a.method2(); + } + return User; +}()); diff --git a/tests/baselines/reference/abstractPropertyInConstructor.symbols b/tests/baselines/reference/abstractPropertyInConstructor.symbols index 0d542ffb0a8..42cd3bb6827 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.symbols +++ b/tests/baselines/reference/abstractPropertyInConstructor.symbols @@ -2,69 +2,110 @@ abstract class AbstractClass { >AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) - constructor(str: string) { + constructor(str: string, other: AbstractClass) { >str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 1, 16)) +>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 1, 28)) +>AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) this.method(parseInt(str)); ->this.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 16, 37)) +>this.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37)) >this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 16, 37)) +>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37)) >parseInt : Symbol(parseInt, Decl(lib.d.ts, --, --)) >str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 1, 16)) let val = this.prop.toLowerCase(); >val : Symbol(val, Decl(abstractPropertyInConstructor.ts, 3, 11)) >this.prop.toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, --, --)) ->this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) >this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) >toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, --, --)) if (!str) { >str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 1, 16)) this.prop = "Hello World"; ->this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) >this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) } this.cb(str); ->this.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 15, 26)) +>this.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26)) >this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 15, 26)) +>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26)) >str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 1, 16)) + // OK, reference is inside function const innerFunction = () => { ->innerFunction : Symbol(innerFunction, Decl(abstractPropertyInConstructor.ts, 10, 13)) +>innerFunction : Symbol(innerFunction, Decl(abstractPropertyInConstructor.ts, 11, 13)) return this.prop; ->this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) >this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) } + + // OK, references are to another instance + other.cb(other.prop); +>other.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26)) +>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 1, 28)) +>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26)) +>other.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) +>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 1, 28)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) } abstract prop: string; ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) abstract cb: (s: string) => void; ->cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 15, 26)) ->s : Symbol(s, Decl(abstractPropertyInConstructor.ts, 16, 18)) +>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26)) +>s : Symbol(s, Decl(abstractPropertyInConstructor.ts, 20, 18)) abstract method(num: number): void; ->method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 16, 37)) ->num : Symbol(num, Decl(abstractPropertyInConstructor.ts, 18, 20)) +>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37)) +>num : Symbol(num, Decl(abstractPropertyInConstructor.ts, 22, 20)) method2() { ->method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 18, 39)) +>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 22, 39)) this.prop = this.prop + "!"; ->this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) >this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) ->this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) +>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) >this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) + } +} + +class User { +>User : Symbol(User, Decl(abstractPropertyInConstructor.ts, 27, 1)) + + constructor(a: AbstractClass) { +>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16)) +>AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) + + a.prop; +>a.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) +>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) + + a.cb("hi"); +>a.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26)) +>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16)) +>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26)) + + a.method(12); +>a.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37)) +>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16)) +>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37)) + + a.method2(); +>a.method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 22, 39)) +>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16)) +>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 22, 39)) } } diff --git a/tests/baselines/reference/abstractPropertyInConstructor.types b/tests/baselines/reference/abstractPropertyInConstructor.types index 0ffb5f1bdfd..6f8970a7702 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.types +++ b/tests/baselines/reference/abstractPropertyInConstructor.types @@ -2,8 +2,10 @@ abstract class AbstractClass { >AbstractClass : AbstractClass - constructor(str: string) { + constructor(str: string, other: AbstractClass) { >str : string +>other : AbstractClass +>AbstractClass : AbstractClass this.method(parseInt(str)); >this.method(parseInt(str)) : void @@ -41,6 +43,7 @@ abstract class AbstractClass { >cb : (s: string) => void >str : string + // OK, reference is inside function const innerFunction = () => { >innerFunction : () => string >() => { return this.prop; } : () => string @@ -50,6 +53,16 @@ abstract class AbstractClass { >this : this >prop : string } + + // OK, references are to another instance + other.cb(other.prop); +>other.cb(other.prop) : void +>other.cb : (s: string) => void +>other : AbstractClass +>cb : (s: string) => void +>other.prop : string +>other : AbstractClass +>prop : string } abstract prop: string; @@ -79,3 +92,37 @@ abstract class AbstractClass { } } +class User { +>User : User + + constructor(a: AbstractClass) { +>a : AbstractClass +>AbstractClass : AbstractClass + + a.prop; +>a.prop : string +>a : AbstractClass +>prop : string + + a.cb("hi"); +>a.cb("hi") : void +>a.cb : (s: string) => void +>a : AbstractClass +>cb : (s: string) => void +>"hi" : "hi" + + a.method(12); +>a.method(12) : void +>a.method : (num: number) => void +>a : AbstractClass +>method : (num: number) => void +>12 : 12 + + a.method2(); +>a.method2() : void +>a.method2 : () => void +>a : AbstractClass +>method2 : () => void + } +} + diff --git a/tests/baselines/reference/ambientDeclarationsExternal.js b/tests/baselines/reference/ambientDeclarationsExternal.js index fb531586467..ed413fb0d8e 100644 --- a/tests/baselines/reference/ambientDeclarationsExternal.js +++ b/tests/baselines/reference/ambientDeclarationsExternal.js @@ -24,7 +24,7 @@ var n: number; //// [decls.js] -// Ambient external import declaration referencing ambient external module using top level module name +// Ambient external import declaration referencing ambient external module using top level module name //// [consumer.js] "use strict"; exports.__esModule = true; diff --git a/tests/baselines/reference/anyAssignableToEveryType.js b/tests/baselines/reference/anyAssignableToEveryType.js index d6b2303de48..eff97905e4f 100644 --- a/tests/baselines/reference/anyAssignableToEveryType.js +++ b/tests/baselines/reference/anyAssignableToEveryType.js @@ -87,4 +87,4 @@ function foo(x, y, z) { // x = a; // y = a; // z = a; -//} +//} diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 44c8095b9fb..f98684b3c68 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -313,46 +313,49 @@ declare namespace ts { JsxSelfClosingElement = 250, JsxOpeningElement = 251, JsxClosingElement = 252, - JsxAttribute = 253, - JsxAttributes = 254, - JsxSpreadAttribute = 255, - JsxExpression = 256, - CaseClause = 257, - DefaultClause = 258, - HeritageClause = 259, - CatchClause = 260, - PropertyAssignment = 261, - ShorthandPropertyAssignment = 262, - SpreadAssignment = 263, - EnumMember = 264, - SourceFile = 265, - Bundle = 266, - JSDocTypeExpression = 267, - JSDocAllType = 268, - JSDocUnknownType = 269, - JSDocNullableType = 270, - JSDocNonNullableType = 271, - JSDocOptionalType = 272, - JSDocFunctionType = 273, - JSDocVariadicType = 274, - JSDocComment = 275, - JSDocTag = 276, - JSDocAugmentsTag = 277, - JSDocClassTag = 278, - JSDocParameterTag = 279, - JSDocReturnTag = 280, - JSDocTypeTag = 281, - JSDocTemplateTag = 282, - JSDocTypedefTag = 283, - JSDocPropertyTag = 284, - JSDocTypeLiteral = 285, - SyntaxList = 286, - NotEmittedStatement = 287, - PartiallyEmittedExpression = 288, - CommaListExpression = 289, - MergeDeclarationMarker = 290, - EndOfDeclarationMarker = 291, - Count = 292, + JsxFragment = 253, + JsxOpeningFragment = 254, + JsxClosingFragment = 255, + JsxAttribute = 256, + JsxAttributes = 257, + JsxSpreadAttribute = 258, + JsxExpression = 259, + CaseClause = 260, + DefaultClause = 261, + HeritageClause = 262, + CatchClause = 263, + PropertyAssignment = 264, + ShorthandPropertyAssignment = 265, + SpreadAssignment = 266, + EnumMember = 267, + SourceFile = 268, + Bundle = 269, + JSDocTypeExpression = 270, + JSDocAllType = 271, + JSDocUnknownType = 272, + JSDocNullableType = 273, + JSDocNonNullableType = 274, + JSDocOptionalType = 275, + JSDocFunctionType = 276, + JSDocVariadicType = 277, + JSDocComment = 278, + JSDocTypeLiteral = 279, + JSDocTag = 280, + JSDocAugmentsTag = 281, + JSDocClassTag = 282, + JSDocParameterTag = 283, + JSDocReturnTag = 284, + JSDocTypeTag = 285, + JSDocTemplateTag = 286, + JSDocTypedefTag = 287, + JSDocPropertyTag = 288, + SyntaxList = 289, + NotEmittedStatement = 290, + PartiallyEmittedExpression = 291, + CommaListExpression = 292, + MergeDeclarationMarker = 293, + EndOfDeclarationMarker = 294, + Count = 295, FirstAssignment = 58, LastAssignment = 70, FirstCompoundAssignment = 59, @@ -378,10 +381,10 @@ declare namespace ts { FirstBinaryOperator = 27, LastBinaryOperator = 70, FirstNode = 143, - FirstJSDocNode = 267, - LastJSDocNode = 285, - FirstJSDocTagNode = 276, - LastJSDocTagNode = 285, + FirstJSDocNode = 270, + LastJSDocNode = 288, + FirstJSDocTagNode = 280, + LastJSDocTagNode = 288, } enum NodeFlags { None = 0, @@ -408,7 +411,7 @@ declare namespace ts { BlockScoped = 3, ReachabilityCheckFlags = 384, ReachabilityAndEmitFlags = 1408, - ContextFlags = 2193408, + ContextFlags = 6387712, TypeExcludesFlags = 20480, } enum ModifierFlags { @@ -1061,6 +1064,20 @@ declare namespace ts { tagName: JsxTagNameExpression; attributes: JsxAttributes; } + interface JsxFragment extends PrimaryExpression { + kind: SyntaxKind.JsxFragment; + openingFragment: JsxOpeningFragment; + children: NodeArray; + closingFragment: JsxClosingFragment; + } + interface JsxOpeningFragment extends Expression { + kind: SyntaxKind.JsxOpeningFragment; + parent?: JsxFragment; + } + interface JsxClosingFragment extends Expression { + kind: SyntaxKind.JsxClosingFragment; + parent?: JsxFragment; + } interface JsxAttribute extends ObjectLiteralElement { kind: SyntaxKind.JsxAttribute; parent?: JsxAttributes; @@ -1088,7 +1105,7 @@ declare namespace ts { containsOnlyWhiteSpaces: boolean; parent?: JsxElement; } - type JsxChild = JsxText | JsxExpression | JsxElement | JsxSelfClosingElement; + type JsxChild = JsxText | JsxExpression | JsxElement | JsxSelfClosingElement | JsxFragment; interface Statement extends Node { _statementBrand: any; } @@ -1592,8 +1609,8 @@ declare namespace ts { } interface ScriptReferenceHost { getCompilerOptions(): CompilerOptions; - getSourceFile(fileName: string): SourceFile; - getSourceFileByPath(path: Path): SourceFile; + getSourceFile(fileName: string): SourceFile | undefined; + getSourceFileByPath(path: Path): SourceFile | undefined; getCurrentDirectory(): string; } interface ParseConfigHost { @@ -1606,9 +1623,7 @@ declare namespace ts { fileExists(path: string): boolean; readFile(path: string): string | undefined; } - interface WriteFileCallback { - (fileName: string, data: string, writeByteOrderMark: boolean, onError: ((message: string) => void) | undefined, sourceFiles: ReadonlyArray): void; - } + type WriteFileCallback = (fileName: string, data: string, writeByteOrderMark: boolean, onError: ((message: string) => void) | undefined, sourceFiles: ReadonlyArray) => void; class OperationCanceledException { } interface CancellationToken { @@ -2040,6 +2055,7 @@ declare namespace ts { ObjectLiteral = 128, EvolvingArray = 256, ObjectLiteralPatternWithComputedProperties = 512, + ContainsSpread = 1024, ClassOrInterface = 3, } interface ObjectType extends Type { @@ -3001,6 +3017,9 @@ declare namespace ts { function isJsxSelfClosingElement(node: Node): node is JsxSelfClosingElement; function isJsxOpeningElement(node: Node): node is JsxOpeningElement; function isJsxClosingElement(node: Node): node is JsxClosingElement; + function isJsxFragment(node: Node): node is JsxFragment; + function isJsxOpeningFragment(node: Node): node is JsxOpeningFragment; + function isJsxClosingFragment(node: Node): node is JsxClosingFragment; function isJsxAttribute(node: Node): node is JsxAttribute; function isJsxAttributes(node: Node): node is JsxAttributes; function isJsxSpreadAttribute(node: Node): node is JsxSpreadAttribute; @@ -3074,9 +3093,7 @@ declare namespace ts { function isGetAccessor(node: Node): node is GetAccessorDeclaration; } declare namespace ts { - interface ErrorCallback { - (message: DiagnosticMessage, length: number): void; - } + type ErrorCallback = (message: DiagnosticMessage, length: number) => void; interface Scanner { getStartPos(): number; getToken(): SyntaxKind; @@ -3254,11 +3271,10 @@ declare namespace ts { } declare namespace ts { function createNodeArray(elements?: ReadonlyArray, hasTrailingComma?: boolean): NodeArray; - function createLiteral(value: string): StringLiteral; + /** If a node is passed, creates a string literal whose source text is read from a source node during emit. */ + function createLiteral(value: string | StringLiteral | NumericLiteral | Identifier): StringLiteral; function createLiteral(value: number): NumericLiteral; function createLiteral(value: boolean): BooleanLiteral; - /** Create a string literal whose source text is read from a source node during emit. */ - function createLiteral(sourceNode: StringLiteral | NumericLiteral | Identifier): StringLiteral; function createLiteral(value: string | number | boolean): PrimaryExpression; function createNumericLiteral(value: string): NumericLiteral; function createIdentifier(text: string): Identifier; @@ -3500,6 +3516,8 @@ declare namespace ts { function updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, attributes: JsxAttributes): JsxOpeningElement; function createJsxClosingElement(tagName: JsxTagNameExpression): JsxClosingElement; function updateJsxClosingElement(node: JsxClosingElement, tagName: JsxTagNameExpression): JsxClosingElement; + function createJsxFragment(openingFragment: JsxOpeningFragment, children: ReadonlyArray, closingFragment: JsxClosingFragment): JsxFragment; + function updateJsxFragment(node: JsxFragment, openingFragment: JsxOpeningFragment, children: ReadonlyArray, closingFragment: JsxClosingFragment): JsxFragment; function createJsxAttribute(name: Identifier, initializer: StringLiteral | JsxExpression): JsxAttribute; function updateJsxAttribute(node: JsxAttribute, name: Identifier, initializer: StringLiteral | JsxExpression): JsxAttribute; function createJsxAttributes(properties: ReadonlyArray): JsxAttributes; @@ -3794,7 +3812,7 @@ declare namespace ts { getEscapedName(): __String; getName(): string; getDeclarations(): Declaration[] | undefined; - getDocumentationComment(): SymbolDisplayPart[]; + getDocumentationComment(typeChecker: TypeChecker | undefined): SymbolDisplayPart[]; getJsDocTags(): JSDocTagInfo[]; } interface Type { @@ -3815,7 +3833,7 @@ declare namespace ts { getTypeParameters(): TypeParameter[] | undefined; getParameters(): Symbol[]; getReturnType(): Type; - getDocumentationComment(): SymbolDisplayPart[]; + getDocumentationComment(typeChecker: TypeChecker | undefined): SymbolDisplayPart[]; getJsDocTags(): JSDocTagInfo[]; } interface SourceFile { @@ -3914,9 +3932,9 @@ declare namespace ts { getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications; getEncodedSemanticClassifications(fileName: string, span: TextSpan): Classifications; - getCompletionsAtPosition(fileName: string, position: number): CompletionInfo; - getCompletionEntryDetails(fileName: string, position: number, name: string, options?: FormatCodeOptions | FormatCodeSettings, source?: string): CompletionEntryDetails; - getCompletionEntrySymbol(fileName: string, position: number, name: string, source?: string): Symbol; + getCompletionsAtPosition(fileName: string, position: number, options: GetCompletionsAtPositionOptions | undefined): CompletionInfo; + getCompletionEntryDetails(fileName: string, position: number, name: string, options: FormatCodeOptions | FormatCodeSettings | undefined, source: string | undefined): CompletionEntryDetails; + getCompletionEntrySymbol(fileName: string, position: number, name: string, source: string | undefined): Symbol; getQuickInfoAtPosition(fileName: string, position: number): QuickInfo; getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): TextSpan; getBreakpointStatementAtPosition(fileName: string, position: number): TextSpan; @@ -3924,6 +3942,7 @@ declare namespace ts { getRenameInfo(fileName: string, position: number): RenameInfo; findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[]; getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; + getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan; getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; getImplementationAtPosition(fileName: string, position: number): ImplementationLocation[]; getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[]; @@ -3952,6 +3971,9 @@ declare namespace ts { getProgram(): Program; dispose(): void; } + interface GetCompletionsAtPositionOptions { + includeExternalModuleExports: boolean; + } interface ApplyCodeActionCommandResult { successMessage: string; } @@ -4187,6 +4209,10 @@ declare namespace ts { containerKind: ScriptElementKind; containerName: string; } + interface DefinitionInfoAndBoundSpan { + definitions: ReadonlyArray; + textSpan: TextSpan; + } interface ReferencedSymbolDefinitionInfo extends DefinitionInfo { displayParts: SymbolDisplayPart[]; } @@ -4598,7 +4624,7 @@ declare namespace ts { } declare namespace ts { /** The version of the language service API */ - const servicesVersion = "0.5"; + const servicesVersion = "0.7"; interface DisplayPartsSymbolWriter extends SymbolWriter { displayParts(): SymbolDisplayPart[]; } @@ -4752,17 +4778,17 @@ declare namespace ts.server { info(s: string): void; startGroup(): void; endGroup(): void; - msg(s: string, type?: Msg.Types): void; + msg(s: string, type?: Msg): void; getLogFileName(): string; } + enum Msg { + Err = "Err", + Info = "Info", + Perf = "Perf", + } namespace Msg { - type Err = "Err"; - const Err: Err; - type Info = "Info"; - const Info: Info; - type Perf = "Perf"; - const Perf: Perf; - type Types = Err | Info | Perf; + /** @deprecated Only here for backwards-compatibility. Prefer just `Msg`. */ + type Types = Msg; } function createInstallTypingsRequest(project: Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray, cachePath?: string): DiscoverTypings; namespace Errors { @@ -4822,6 +4848,7 @@ declare namespace ts.server.protocol { CompileOnSaveEmitFile = "compileOnSaveEmitFile", Configure = "configure", Definition = "definition", + DefinitionAndBoundSpan = "definitionAndBoundSpan", Implementation = "implementation", Exit = "exit", Format = "format", @@ -5341,12 +5368,19 @@ declare namespace ts.server.protocol { */ file: string; } + interface DefinitionInfoAndBoundSpan { + definitions: ReadonlyArray; + textSpan: TextSpan; + } /** * Definition response message. Gives text range for definition. */ interface DefinitionResponse extends Response { body?: FileSpan[]; } + interface DefinitionInfoAndBoundSpanReponse extends Response { + body?: DefinitionInfoAndBoundSpan; + } /** * Definition response message. Gives text range for definition. */ @@ -6015,6 +6049,11 @@ declare namespace ts.server.protocol { * Optional prefix to apply to possible completions. */ prefix?: string; + /** + * If enabled, TypeScript will search through all external modules' exports and add them to the completions list. + * This affects lone identifier completions but not completions on the right hand side of `obj.`. + */ + includeExternalModuleExports: boolean; } /** * Completions request; value of command field is "completions". @@ -6922,6 +6961,9 @@ declare namespace ts.server { private convertToDiagnosticsWithLinePosition(diagnostics, scriptInfo); private getDiagnosticsWorker(args, isSemantic, selector, includeLinePosition); private getDefinition(args, simplifiedResult); + private getDefinitionAndBoundSpan(args, simplifiedResult); + private mapDefinitionInfo(definitions, project); + private toFileSpan(fileName, textSpan, project); private getTypeDefinition(args); private getImplementation(args, simplifiedResult); private getOccurrences(args); @@ -6961,7 +7003,7 @@ declare namespace ts.server { private getFormattingEditsAfterKeystrokeFull(args); private getFormattingEditsAfterKeystroke(args); private getCompletions(args, simplifiedResult); - private getCompletionEntryDetails(args); + private getCompletionEntryDetails(args, simplifiedResult); private getCompileOnSaveAffectedFileList(args); private emitFile(args); private getSignatureHelpItems(args, simplifiedResult); @@ -6971,10 +7013,10 @@ declare namespace ts.server { private reload(args, reqSeq); private saveToTmp(fileName, tempFileName); private closeClientFile(fileName); - private decorateNavigationBarItems(items, scriptInfo); + private mapLocationNavigationBarItems(items, scriptInfo); private getNavigationBarItems(args, simplifiedResult); - private decorateNavigationTree(tree, scriptInfo); - private decorateSpan(span, scriptInfo); + private toLocationNavigationTree(tree, scriptInfo); + private toLocationTextSpan(span, scriptInfo); private getNavigationTree(args, simplifiedResult); private getNavigateToItems(args, simplifiedResult); private getSupportedCodeFixes(); @@ -7023,7 +7065,7 @@ declare namespace ts.server { constructor(host: ServerHost, fileName: NormalizedPath, scriptKind: ScriptKind, hasMixedContent: boolean, path: Path); isScriptOpen(): boolean; open(newText: string): void; - close(): void; + close(fileExists?: boolean): void; getSnapshot(): IScriptSnapshot; getFormatCodeSettings(): FormatCodeSettings; attachToProject(project: Project): boolean; @@ -7105,11 +7147,9 @@ declare namespace ts.server { create(createInfo: PluginCreateInfo): LanguageService; getExternalFiles?(proj: Project): string[]; } - interface PluginModuleFactory { - (mod: { - typescript: typeof ts; - }): PluginModule; - } + type PluginModuleFactory = (mod: { + typescript: typeof ts; + }) => PluginModule; /** * The project root can be script info - if root is present, * or it could be just normalized path if root wasnt present on the host(only for non inferred project) @@ -7379,9 +7419,7 @@ declare namespace ts.server { readonly dts: number; } type ProjectServiceEvent = ProjectsUpdatedInBackgroundEvent | ConfigFileDiagEvent | ProjectLanguageServiceStateEvent | ProjectInfoTelemetryEvent; - interface ProjectServiceEventHandler { - (event: ProjectServiceEvent): void; - } + type ProjectServiceEventHandler = (event: ProjectServiceEvent) => void; interface SafeList { [name: string]: { match: RegExp; @@ -7453,6 +7491,10 @@ declare namespace ts.server { * Open files: with value being project root path, and key being Path of the file that is open */ readonly openFiles: Map; + /** + * Map of open files that are opened without complete path but have projectRoot as current directory + */ + private readonly openFilesWithNonRootedDiskPath; private compilerOptionsForInferredProjects; private compilerOptionsForInferredProjectsPerProjectRoot; /** @@ -7593,6 +7635,10 @@ declare namespace ts.server { private watchClosedScriptInfo(info); private stopWatchingScriptInfo(info); getOrCreateScriptInfoForNormalizedPath(fileName: NormalizedPath, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, hostToQueryFileExistsOn?: DirectoryStructureHost): ScriptInfo; + private getOrCreateScriptInfoWorker(fileName, currentDirectory, openedByClient, fileContent?, scriptKind?, hasMixedContent?, hostToQueryFileExistsOn?); + /** + * 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): ScriptInfo; getScriptInfoForPath(fileName: Path): ScriptInfo; setHostConfiguration(args: protocol.ConfigureRequestArguments): void; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 2afef7d692c..98d7137ddeb 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -313,46 +313,49 @@ declare namespace ts { JsxSelfClosingElement = 250, JsxOpeningElement = 251, JsxClosingElement = 252, - JsxAttribute = 253, - JsxAttributes = 254, - JsxSpreadAttribute = 255, - JsxExpression = 256, - CaseClause = 257, - DefaultClause = 258, - HeritageClause = 259, - CatchClause = 260, - PropertyAssignment = 261, - ShorthandPropertyAssignment = 262, - SpreadAssignment = 263, - EnumMember = 264, - SourceFile = 265, - Bundle = 266, - JSDocTypeExpression = 267, - JSDocAllType = 268, - JSDocUnknownType = 269, - JSDocNullableType = 270, - JSDocNonNullableType = 271, - JSDocOptionalType = 272, - JSDocFunctionType = 273, - JSDocVariadicType = 274, - JSDocComment = 275, - JSDocTag = 276, - JSDocAugmentsTag = 277, - JSDocClassTag = 278, - JSDocParameterTag = 279, - JSDocReturnTag = 280, - JSDocTypeTag = 281, - JSDocTemplateTag = 282, - JSDocTypedefTag = 283, - JSDocPropertyTag = 284, - JSDocTypeLiteral = 285, - SyntaxList = 286, - NotEmittedStatement = 287, - PartiallyEmittedExpression = 288, - CommaListExpression = 289, - MergeDeclarationMarker = 290, - EndOfDeclarationMarker = 291, - Count = 292, + JsxFragment = 253, + JsxOpeningFragment = 254, + JsxClosingFragment = 255, + JsxAttribute = 256, + JsxAttributes = 257, + JsxSpreadAttribute = 258, + JsxExpression = 259, + CaseClause = 260, + DefaultClause = 261, + HeritageClause = 262, + CatchClause = 263, + PropertyAssignment = 264, + ShorthandPropertyAssignment = 265, + SpreadAssignment = 266, + EnumMember = 267, + SourceFile = 268, + Bundle = 269, + JSDocTypeExpression = 270, + JSDocAllType = 271, + JSDocUnknownType = 272, + JSDocNullableType = 273, + JSDocNonNullableType = 274, + JSDocOptionalType = 275, + JSDocFunctionType = 276, + JSDocVariadicType = 277, + JSDocComment = 278, + JSDocTypeLiteral = 279, + JSDocTag = 280, + JSDocAugmentsTag = 281, + JSDocClassTag = 282, + JSDocParameterTag = 283, + JSDocReturnTag = 284, + JSDocTypeTag = 285, + JSDocTemplateTag = 286, + JSDocTypedefTag = 287, + JSDocPropertyTag = 288, + SyntaxList = 289, + NotEmittedStatement = 290, + PartiallyEmittedExpression = 291, + CommaListExpression = 292, + MergeDeclarationMarker = 293, + EndOfDeclarationMarker = 294, + Count = 295, FirstAssignment = 58, LastAssignment = 70, FirstCompoundAssignment = 59, @@ -378,10 +381,10 @@ declare namespace ts { FirstBinaryOperator = 27, LastBinaryOperator = 70, FirstNode = 143, - FirstJSDocNode = 267, - LastJSDocNode = 285, - FirstJSDocTagNode = 276, - LastJSDocTagNode = 285, + FirstJSDocNode = 270, + LastJSDocNode = 288, + FirstJSDocTagNode = 280, + LastJSDocTagNode = 288, } enum NodeFlags { None = 0, @@ -408,7 +411,7 @@ declare namespace ts { BlockScoped = 3, ReachabilityCheckFlags = 384, ReachabilityAndEmitFlags = 1408, - ContextFlags = 2193408, + ContextFlags = 6387712, TypeExcludesFlags = 20480, } enum ModifierFlags { @@ -1061,6 +1064,20 @@ declare namespace ts { tagName: JsxTagNameExpression; attributes: JsxAttributes; } + interface JsxFragment extends PrimaryExpression { + kind: SyntaxKind.JsxFragment; + openingFragment: JsxOpeningFragment; + children: NodeArray; + closingFragment: JsxClosingFragment; + } + interface JsxOpeningFragment extends Expression { + kind: SyntaxKind.JsxOpeningFragment; + parent?: JsxFragment; + } + interface JsxClosingFragment extends Expression { + kind: SyntaxKind.JsxClosingFragment; + parent?: JsxFragment; + } interface JsxAttribute extends ObjectLiteralElement { kind: SyntaxKind.JsxAttribute; parent?: JsxAttributes; @@ -1088,7 +1105,7 @@ declare namespace ts { containsOnlyWhiteSpaces: boolean; parent?: JsxElement; } - type JsxChild = JsxText | JsxExpression | JsxElement | JsxSelfClosingElement; + type JsxChild = JsxText | JsxExpression | JsxElement | JsxSelfClosingElement | JsxFragment; interface Statement extends Node { _statementBrand: any; } @@ -1592,8 +1609,8 @@ declare namespace ts { } interface ScriptReferenceHost { getCompilerOptions(): CompilerOptions; - getSourceFile(fileName: string): SourceFile; - getSourceFileByPath(path: Path): SourceFile; + getSourceFile(fileName: string): SourceFile | undefined; + getSourceFileByPath(path: Path): SourceFile | undefined; getCurrentDirectory(): string; } interface ParseConfigHost { @@ -1606,9 +1623,7 @@ declare namespace ts { fileExists(path: string): boolean; readFile(path: string): string | undefined; } - interface WriteFileCallback { - (fileName: string, data: string, writeByteOrderMark: boolean, onError: ((message: string) => void) | undefined, sourceFiles: ReadonlyArray): void; - } + type WriteFileCallback = (fileName: string, data: string, writeByteOrderMark: boolean, onError: ((message: string) => void) | undefined, sourceFiles: ReadonlyArray) => void; class OperationCanceledException { } interface CancellationToken { @@ -2040,6 +2055,7 @@ declare namespace ts { ObjectLiteral = 128, EvolvingArray = 256, ObjectLiteralPatternWithComputedProperties = 512, + ContainsSpread = 1024, ClassOrInterface = 3, } interface ObjectType extends Type { @@ -2740,9 +2756,7 @@ declare namespace ts { let sys: System; } declare namespace ts { - interface ErrorCallback { - (message: DiagnosticMessage, length: number): void; - } + type ErrorCallback = (message: DiagnosticMessage, length: number) => void; interface Scanner { getStartPos(): number; getToken(): SyntaxKind; @@ -3056,6 +3070,9 @@ declare namespace ts { function isJsxSelfClosingElement(node: Node): node is JsxSelfClosingElement; function isJsxOpeningElement(node: Node): node is JsxOpeningElement; function isJsxClosingElement(node: Node): node is JsxClosingElement; + function isJsxFragment(node: Node): node is JsxFragment; + function isJsxOpeningFragment(node: Node): node is JsxOpeningFragment; + function isJsxClosingFragment(node: Node): node is JsxClosingFragment; function isJsxAttribute(node: Node): node is JsxAttribute; function isJsxAttributes(node: Node): node is JsxAttributes; function isJsxSpreadAttribute(node: Node): node is JsxSpreadAttribute; @@ -3201,11 +3218,10 @@ declare namespace ts { } declare namespace ts { function createNodeArray(elements?: ReadonlyArray, hasTrailingComma?: boolean): NodeArray; - function createLiteral(value: string): StringLiteral; + /** If a node is passed, creates a string literal whose source text is read from a source node during emit. */ + function createLiteral(value: string | StringLiteral | NumericLiteral | Identifier): StringLiteral; function createLiteral(value: number): NumericLiteral; function createLiteral(value: boolean): BooleanLiteral; - /** Create a string literal whose source text is read from a source node during emit. */ - function createLiteral(sourceNode: StringLiteral | NumericLiteral | Identifier): StringLiteral; function createLiteral(value: string | number | boolean): PrimaryExpression; function createNumericLiteral(value: string): NumericLiteral; function createIdentifier(text: string): Identifier; @@ -3447,6 +3463,8 @@ declare namespace ts { function updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, attributes: JsxAttributes): JsxOpeningElement; function createJsxClosingElement(tagName: JsxTagNameExpression): JsxClosingElement; function updateJsxClosingElement(node: JsxClosingElement, tagName: JsxTagNameExpression): JsxClosingElement; + function createJsxFragment(openingFragment: JsxOpeningFragment, children: ReadonlyArray, closingFragment: JsxClosingFragment): JsxFragment; + function updateJsxFragment(node: JsxFragment, openingFragment: JsxOpeningFragment, children: ReadonlyArray, closingFragment: JsxClosingFragment): JsxFragment; function createJsxAttribute(name: Identifier, initializer: StringLiteral | JsxExpression): JsxAttribute; function updateJsxAttribute(node: JsxAttribute, name: Identifier, initializer: StringLiteral | JsxExpression): JsxAttribute; function createJsxAttributes(properties: ReadonlyArray): JsxAttributes; @@ -3794,7 +3812,7 @@ declare namespace ts { getEscapedName(): __String; getName(): string; getDeclarations(): Declaration[] | undefined; - getDocumentationComment(): SymbolDisplayPart[]; + getDocumentationComment(typeChecker: TypeChecker | undefined): SymbolDisplayPart[]; getJsDocTags(): JSDocTagInfo[]; } interface Type { @@ -3815,7 +3833,7 @@ declare namespace ts { getTypeParameters(): TypeParameter[] | undefined; getParameters(): Symbol[]; getReturnType(): Type; - getDocumentationComment(): SymbolDisplayPart[]; + getDocumentationComment(typeChecker: TypeChecker | undefined): SymbolDisplayPart[]; getJsDocTags(): JSDocTagInfo[]; } interface SourceFile { @@ -3914,9 +3932,9 @@ declare namespace ts { getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications; getEncodedSemanticClassifications(fileName: string, span: TextSpan): Classifications; - getCompletionsAtPosition(fileName: string, position: number): CompletionInfo; - getCompletionEntryDetails(fileName: string, position: number, name: string, options?: FormatCodeOptions | FormatCodeSettings, source?: string): CompletionEntryDetails; - getCompletionEntrySymbol(fileName: string, position: number, name: string, source?: string): Symbol; + getCompletionsAtPosition(fileName: string, position: number, options: GetCompletionsAtPositionOptions | undefined): CompletionInfo; + getCompletionEntryDetails(fileName: string, position: number, name: string, options: FormatCodeOptions | FormatCodeSettings | undefined, source: string | undefined): CompletionEntryDetails; + getCompletionEntrySymbol(fileName: string, position: number, name: string, source: string | undefined): Symbol; getQuickInfoAtPosition(fileName: string, position: number): QuickInfo; getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): TextSpan; getBreakpointStatementAtPosition(fileName: string, position: number): TextSpan; @@ -3924,6 +3942,7 @@ declare namespace ts { getRenameInfo(fileName: string, position: number): RenameInfo; findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[]; getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; + getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan; getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; getImplementationAtPosition(fileName: string, position: number): ImplementationLocation[]; getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[]; @@ -3952,6 +3971,9 @@ declare namespace ts { getProgram(): Program; dispose(): void; } + interface GetCompletionsAtPositionOptions { + includeExternalModuleExports: boolean; + } interface ApplyCodeActionCommandResult { successMessage: string; } @@ -4187,6 +4209,10 @@ declare namespace ts { containerKind: ScriptElementKind; containerName: string; } + interface DefinitionInfoAndBoundSpan { + definitions: ReadonlyArray; + textSpan: TextSpan; + } interface ReferencedSymbolDefinitionInfo extends DefinitionInfo { displayParts: SymbolDisplayPart[]; } @@ -4598,7 +4624,7 @@ declare namespace ts { } declare namespace ts { /** The version of the language service API */ - const servicesVersion = "0.5"; + const servicesVersion = "0.7"; interface DisplayPartsSymbolWriter extends SymbolWriter { displayParts(): SymbolDisplayPart[]; } diff --git a/tests/baselines/reference/arityAndOrderCompatibility01.errors.txt b/tests/baselines/reference/arityAndOrderCompatibility01.errors.txt index 5a367a4122f..4d6fbd063ae 100644 --- a/tests/baselines/reference/arityAndOrderCompatibility01.errors.txt +++ b/tests/baselines/reference/arityAndOrderCompatibility01.errors.txt @@ -1,52 +1,49 @@ -tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(13,12): error TS2493: Tuple type '[string, number]' with length '2' cannot be assigned to tuple with length '3'. -tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(14,12): error TS2460: Type 'StrNum' has no property '2'. -tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(15,5): error TS2461: Type '{ 0: string; 1: number; }' is not an array type. -tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(15,12): error TS2460: Type '{ 0: string; 1: number; }' has no property '2'. -tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(16,5): error TS2322: Type '[string, number]' is not assignable to type '[number, number, number]'. +tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(15,12): error TS2493: Tuple type '[string, number]' with length '2' cannot be assigned to tuple with length '3'. +tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(16,12): error TS2460: Type 'StrNum' has no property '2'. +tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(17,5): error TS2461: Type '{ 0: string; 1: number; length: 2; }' is not an array type. +tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(17,12): error TS2460: Type '{ 0: string; 1: number; length: 2; }' has no property '2'. +tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(18,5): error TS2322: Type '[string, number]' is not assignable to type '[number, number, number]'. Property '2' is missing in type '[string, number]'. -tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(17,5): error TS2322: Type 'StrNum' is not assignable to type '[number, number, number]'. +tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(19,5): error TS2322: Type 'StrNum' is not assignable to type '[number, number, number]'. Property '2' is missing in type 'StrNum'. -tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(18,5): error TS2322: Type '{ 0: string; 1: number; }' is not assignable to type '[number, number, number]'. - Property '2' is missing in type '{ 0: string; 1: number; }'. -tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(19,5): error TS2322: Type '[string, number]' is not assignable to type '[string, number, number]'. +tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(20,5): error TS2322: Type '{ 0: string; 1: number; length: 2; }' is not assignable to type '[number, number, number]'. + Property '2' is missing in type '{ 0: string; 1: number; length: 2; }'. +tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(21,5): error TS2322: Type '[string, number]' is not assignable to type '[string, number, number]'. Property '2' is missing in type '[string, number]'. -tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(20,5): error TS2322: Type 'StrNum' is not assignable to type '[string, number, number]'. +tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(22,5): error TS2322: Type 'StrNum' is not assignable to type '[string, number, number]'. Property '2' is missing in type 'StrNum'. -tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(21,5): error TS2322: Type '{ 0: string; 1: number; }' is not assignable to type '[string, number, number]'. - Property '2' is missing in type '{ 0: string; 1: number; }'. -tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(22,5): error TS2322: Type '[string, number]' is not assignable to type '[number]'. +tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(23,5): error TS2322: Type '{ 0: string; 1: number; length: 2; }' is not assignable to type '[string, number, number]'. + Property '2' is missing in type '{ 0: string; 1: number; length: 2; }'. +tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(24,5): error TS2322: Type '[string, number]' is not assignable to type '[number]'. Types of property '0' are incompatible. Type 'string' is not assignable to type 'number'. -tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(23,5): error TS2322: Type 'StrNum' is not assignable to type '[number]'. +tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(25,5): error TS2322: Type 'StrNum' is not assignable to type '[number]'. Types of property '0' are incompatible. Type 'string' is not assignable to type 'number'. -tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(24,5): error TS2322: Type '{ 0: string; 1: number; }' is not assignable to type '[number]'. - Property 'length' is missing in type '{ 0: string; 1: number; }'. -tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(25,5): error TS2322: Type '[string, number]' is not assignable to type '[string]'. - Types of property 'pop' are incompatible. - Type '() => string | number' is not assignable to type '() => string'. - Type 'string | number' is not assignable to type 'string'. - Type 'number' is not assignable to type 'string'. -tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(26,5): error TS2322: Type 'StrNum' is not assignable to type '[string]'. - Types of property 'pop' are incompatible. - Type '() => string | number' is not assignable to type '() => string'. - Type 'string | number' is not assignable to type 'string'. - Type 'number' is not assignable to type 'string'. -tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(27,5): error TS2322: Type '{ 0: string; 1: number; }' is not assignable to type '[string]'. - Property 'length' is missing in type '{ 0: string; 1: number; }'. -tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(28,5): error TS2322: Type '[string, number]' is not assignable to type '[number, string]'. +tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(26,5): error TS2322: Type '{ 0: string; 1: number; length: 2; }' is not assignable to type '[number]'. + Property 'push' is missing in type '{ 0: string; 1: number; length: 2; }'. +tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(27,5): error TS2322: Type '[string, number]' is not assignable to type '[string]'. + Types of property 'length' are incompatible. + Type '2' is not assignable to type '1'. +tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(28,5): error TS2322: Type 'StrNum' is not assignable to type '[string]'. + Types of property 'length' are incompatible. + Type '2' is not assignable to type '1'. +tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(29,5): error TS2322: Type '{ 0: string; 1: number; length: 2; }' is not assignable to type '[string]'. + Property 'push' is missing in type '{ 0: string; 1: number; length: 2; }'. +tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(30,5): error TS2322: Type '[string, number]' is not assignable to type '[number, string]'. Type 'string' is not assignable to type 'number'. -tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(29,5): error TS2322: Type 'StrNum' is not assignable to type '[number, string]'. +tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(31,5): error TS2322: Type 'StrNum' is not assignable to type '[number, string]'. Types of property '0' are incompatible. Type 'string' is not assignable to type 'number'. -tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(30,5): error TS2322: Type '{ 0: string; 1: number; }' is not assignable to type '[number, string]'. - Property 'length' is missing in type '{ 0: string; 1: number; }'. +tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(32,5): error TS2322: Type '{ 0: string; 1: number; length: 2; }' is not assignable to type '[number, string]'. + Property 'push' is missing in type '{ 0: string; 1: number; length: 2; }'. ==== tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts (19 errors) ==== interface StrNum extends Array { 0: string; 1: number; + length: 2; } var x: [string, number]; @@ -54,6 +51,7 @@ tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(30,5): error var z: { 0: string; 1: number; + length: 2; } var [a, b, c] = x; @@ -64,9 +62,9 @@ tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(30,5): error !!! error TS2460: Type 'StrNum' has no property '2'. var [g, h, i] = z; ~~~~~~~~~ -!!! error TS2461: Type '{ 0: string; 1: number; }' is not an array type. +!!! error TS2461: Type '{ 0: string; 1: number; length: 2; }' is not an array type. ~ -!!! error TS2460: Type '{ 0: string; 1: number; }' has no property '2'. +!!! error TS2460: Type '{ 0: string; 1: number; length: 2; }' has no property '2'. var j1: [number, number, number] = x; ~~ !!! error TS2322: Type '[string, number]' is not assignable to type '[number, number, number]'. @@ -77,8 +75,8 @@ tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(30,5): error !!! error TS2322: Property '2' is missing in type 'StrNum'. var j3: [number, number, number] = z; ~~ -!!! error TS2322: Type '{ 0: string; 1: number; }' is not assignable to type '[number, number, number]'. -!!! error TS2322: Property '2' is missing in type '{ 0: string; 1: number; }'. +!!! error TS2322: Type '{ 0: string; 1: number; length: 2; }' is not assignable to type '[number, number, number]'. +!!! error TS2322: Property '2' is missing in type '{ 0: string; 1: number; length: 2; }'. var k1: [string, number, number] = x; ~~ !!! error TS2322: Type '[string, number]' is not assignable to type '[string, number, number]'. @@ -89,8 +87,8 @@ tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(30,5): error !!! error TS2322: Property '2' is missing in type 'StrNum'. var k3: [string, number, number] = z; ~~ -!!! error TS2322: Type '{ 0: string; 1: number; }' is not assignable to type '[string, number, number]'. -!!! error TS2322: Property '2' is missing in type '{ 0: string; 1: number; }'. +!!! error TS2322: Type '{ 0: string; 1: number; length: 2; }' is not assignable to type '[string, number, number]'. +!!! error TS2322: Property '2' is missing in type '{ 0: string; 1: number; length: 2; }'. var l1: [number] = x; ~~ !!! error TS2322: Type '[string, number]' is not assignable to type '[number]'. @@ -103,26 +101,22 @@ tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(30,5): error !!! error TS2322: Type 'string' is not assignable to type 'number'. var l3: [number] = z; ~~ -!!! error TS2322: Type '{ 0: string; 1: number; }' is not assignable to type '[number]'. -!!! error TS2322: Property 'length' is missing in type '{ 0: string; 1: number; }'. +!!! error TS2322: Type '{ 0: string; 1: number; length: 2; }' is not assignable to type '[number]'. +!!! error TS2322: Property 'push' is missing in type '{ 0: string; 1: number; length: 2; }'. var m1: [string] = x; ~~ !!! error TS2322: Type '[string, number]' is not assignable to type '[string]'. -!!! error TS2322: Types of property 'pop' are incompatible. -!!! error TS2322: Type '() => string | number' is not assignable to type '() => string'. -!!! error TS2322: Type 'string | number' is not assignable to type 'string'. -!!! error TS2322: Type 'number' is not assignable to type 'string'. +!!! error TS2322: Types of property 'length' are incompatible. +!!! error TS2322: Type '2' is not assignable to type '1'. var m2: [string] = y; ~~ !!! error TS2322: Type 'StrNum' is not assignable to type '[string]'. -!!! error TS2322: Types of property 'pop' are incompatible. -!!! error TS2322: Type '() => string | number' is not assignable to type '() => string'. -!!! error TS2322: Type 'string | number' is not assignable to type 'string'. -!!! error TS2322: Type 'number' is not assignable to type 'string'. +!!! error TS2322: Types of property 'length' are incompatible. +!!! error TS2322: Type '2' is not assignable to type '1'. var m3: [string] = z; ~~ -!!! error TS2322: Type '{ 0: string; 1: number; }' is not assignable to type '[string]'. -!!! error TS2322: Property 'length' is missing in type '{ 0: string; 1: number; }'. +!!! error TS2322: Type '{ 0: string; 1: number; length: 2; }' is not assignable to type '[string]'. +!!! error TS2322: Property 'push' is missing in type '{ 0: string; 1: number; length: 2; }'. var n1: [number, string] = x; ~~ !!! error TS2322: Type '[string, number]' is not assignable to type '[number, string]'. @@ -134,8 +128,8 @@ tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(30,5): error !!! error TS2322: Type 'string' is not assignable to type 'number'. var n3: [number, string] = z; ~~ -!!! error TS2322: Type '{ 0: string; 1: number; }' is not assignable to type '[number, string]'. -!!! error TS2322: Property 'length' is missing in type '{ 0: string; 1: number; }'. +!!! error TS2322: Type '{ 0: string; 1: number; length: 2; }' is not assignable to type '[number, string]'. +!!! error TS2322: Property 'push' is missing in type '{ 0: string; 1: number; length: 2; }'. var o1: [string, number] = x; var o2: [string, number] = y; var o3: [string, number] = y; diff --git a/tests/baselines/reference/arityAndOrderCompatibility01.js b/tests/baselines/reference/arityAndOrderCompatibility01.js index 2eb1bcf8bd8..bf7736a80c9 100644 --- a/tests/baselines/reference/arityAndOrderCompatibility01.js +++ b/tests/baselines/reference/arityAndOrderCompatibility01.js @@ -2,6 +2,7 @@ interface StrNum extends Array { 0: string; 1: number; + length: 2; } var x: [string, number]; @@ -9,6 +10,7 @@ var y: StrNum var z: { 0: string; 1: number; + length: 2; } var [a, b, c] = x; diff --git a/tests/baselines/reference/arityAndOrderCompatibility01.symbols b/tests/baselines/reference/arityAndOrderCompatibility01.symbols index c6ef08a845b..3a5d55dc1e6 100644 --- a/tests/baselines/reference/arityAndOrderCompatibility01.symbols +++ b/tests/baselines/reference/arityAndOrderCompatibility01.symbols @@ -5,109 +5,113 @@ interface StrNum extends Array { 0: string; 1: number; + length: 2; +>length : Symbol(StrNum.length, Decl(arityAndOrderCompatibility01.ts, 2, 14)) } var x: [string, number]; ->x : Symbol(x, Decl(arityAndOrderCompatibility01.ts, 5, 3)) +>x : Symbol(x, Decl(arityAndOrderCompatibility01.ts, 6, 3)) var y: StrNum ->y : Symbol(y, Decl(arityAndOrderCompatibility01.ts, 6, 3)) +>y : Symbol(y, Decl(arityAndOrderCompatibility01.ts, 7, 3)) >StrNum : Symbol(StrNum, Decl(arityAndOrderCompatibility01.ts, 0, 0)) var z: { ->z : Symbol(z, Decl(arityAndOrderCompatibility01.ts, 7, 3)) +>z : Symbol(z, Decl(arityAndOrderCompatibility01.ts, 8, 3)) 0: string; 1: number; + length: 2; +>length : Symbol(length, Decl(arityAndOrderCompatibility01.ts, 10, 14)) } var [a, b, c] = x; ->a : Symbol(a, Decl(arityAndOrderCompatibility01.ts, 12, 5)) ->b : Symbol(b, Decl(arityAndOrderCompatibility01.ts, 12, 7)) ->c : Symbol(c, Decl(arityAndOrderCompatibility01.ts, 12, 10)) ->x : Symbol(x, Decl(arityAndOrderCompatibility01.ts, 5, 3)) +>a : Symbol(a, Decl(arityAndOrderCompatibility01.ts, 14, 5)) +>b : Symbol(b, Decl(arityAndOrderCompatibility01.ts, 14, 7)) +>c : Symbol(c, Decl(arityAndOrderCompatibility01.ts, 14, 10)) +>x : Symbol(x, Decl(arityAndOrderCompatibility01.ts, 6, 3)) var [d, e, f] = y; ->d : Symbol(d, Decl(arityAndOrderCompatibility01.ts, 13, 5)) ->e : Symbol(e, Decl(arityAndOrderCompatibility01.ts, 13, 7)) ->f : Symbol(f, Decl(arityAndOrderCompatibility01.ts, 13, 10)) ->y : Symbol(y, Decl(arityAndOrderCompatibility01.ts, 6, 3)) +>d : Symbol(d, Decl(arityAndOrderCompatibility01.ts, 15, 5)) +>e : Symbol(e, Decl(arityAndOrderCompatibility01.ts, 15, 7)) +>f : Symbol(f, Decl(arityAndOrderCompatibility01.ts, 15, 10)) +>y : Symbol(y, Decl(arityAndOrderCompatibility01.ts, 7, 3)) var [g, h, i] = z; ->g : Symbol(g, Decl(arityAndOrderCompatibility01.ts, 14, 5)) ->h : Symbol(h, Decl(arityAndOrderCompatibility01.ts, 14, 7)) ->i : Symbol(i, Decl(arityAndOrderCompatibility01.ts, 14, 10)) ->z : Symbol(z, Decl(arityAndOrderCompatibility01.ts, 7, 3)) +>g : Symbol(g, Decl(arityAndOrderCompatibility01.ts, 16, 5)) +>h : Symbol(h, Decl(arityAndOrderCompatibility01.ts, 16, 7)) +>i : Symbol(i, Decl(arityAndOrderCompatibility01.ts, 16, 10)) +>z : Symbol(z, Decl(arityAndOrderCompatibility01.ts, 8, 3)) var j1: [number, number, number] = x; ->j1 : Symbol(j1, Decl(arityAndOrderCompatibility01.ts, 15, 3)) ->x : Symbol(x, Decl(arityAndOrderCompatibility01.ts, 5, 3)) +>j1 : Symbol(j1, Decl(arityAndOrderCompatibility01.ts, 17, 3)) +>x : Symbol(x, Decl(arityAndOrderCompatibility01.ts, 6, 3)) var j2: [number, number, number] = y; ->j2 : Symbol(j2, Decl(arityAndOrderCompatibility01.ts, 16, 3)) ->y : Symbol(y, Decl(arityAndOrderCompatibility01.ts, 6, 3)) +>j2 : Symbol(j2, Decl(arityAndOrderCompatibility01.ts, 18, 3)) +>y : Symbol(y, Decl(arityAndOrderCompatibility01.ts, 7, 3)) var j3: [number, number, number] = z; ->j3 : Symbol(j3, Decl(arityAndOrderCompatibility01.ts, 17, 3)) ->z : Symbol(z, Decl(arityAndOrderCompatibility01.ts, 7, 3)) +>j3 : Symbol(j3, Decl(arityAndOrderCompatibility01.ts, 19, 3)) +>z : Symbol(z, Decl(arityAndOrderCompatibility01.ts, 8, 3)) var k1: [string, number, number] = x; ->k1 : Symbol(k1, Decl(arityAndOrderCompatibility01.ts, 18, 3)) ->x : Symbol(x, Decl(arityAndOrderCompatibility01.ts, 5, 3)) +>k1 : Symbol(k1, Decl(arityAndOrderCompatibility01.ts, 20, 3)) +>x : Symbol(x, Decl(arityAndOrderCompatibility01.ts, 6, 3)) var k2: [string, number, number] = y; ->k2 : Symbol(k2, Decl(arityAndOrderCompatibility01.ts, 19, 3)) ->y : Symbol(y, Decl(arityAndOrderCompatibility01.ts, 6, 3)) +>k2 : Symbol(k2, Decl(arityAndOrderCompatibility01.ts, 21, 3)) +>y : Symbol(y, Decl(arityAndOrderCompatibility01.ts, 7, 3)) var k3: [string, number, number] = z; ->k3 : Symbol(k3, Decl(arityAndOrderCompatibility01.ts, 20, 3)) ->z : Symbol(z, Decl(arityAndOrderCompatibility01.ts, 7, 3)) +>k3 : Symbol(k3, Decl(arityAndOrderCompatibility01.ts, 22, 3)) +>z : Symbol(z, Decl(arityAndOrderCompatibility01.ts, 8, 3)) var l1: [number] = x; ->l1 : Symbol(l1, Decl(arityAndOrderCompatibility01.ts, 21, 3)) ->x : Symbol(x, Decl(arityAndOrderCompatibility01.ts, 5, 3)) +>l1 : Symbol(l1, Decl(arityAndOrderCompatibility01.ts, 23, 3)) +>x : Symbol(x, Decl(arityAndOrderCompatibility01.ts, 6, 3)) var l2: [number] = y; ->l2 : Symbol(l2, Decl(arityAndOrderCompatibility01.ts, 22, 3)) ->y : Symbol(y, Decl(arityAndOrderCompatibility01.ts, 6, 3)) +>l2 : Symbol(l2, Decl(arityAndOrderCompatibility01.ts, 24, 3)) +>y : Symbol(y, Decl(arityAndOrderCompatibility01.ts, 7, 3)) var l3: [number] = z; ->l3 : Symbol(l3, Decl(arityAndOrderCompatibility01.ts, 23, 3)) ->z : Symbol(z, Decl(arityAndOrderCompatibility01.ts, 7, 3)) +>l3 : Symbol(l3, Decl(arityAndOrderCompatibility01.ts, 25, 3)) +>z : Symbol(z, Decl(arityAndOrderCompatibility01.ts, 8, 3)) var m1: [string] = x; ->m1 : Symbol(m1, Decl(arityAndOrderCompatibility01.ts, 24, 3)) ->x : Symbol(x, Decl(arityAndOrderCompatibility01.ts, 5, 3)) +>m1 : Symbol(m1, Decl(arityAndOrderCompatibility01.ts, 26, 3)) +>x : Symbol(x, Decl(arityAndOrderCompatibility01.ts, 6, 3)) var m2: [string] = y; ->m2 : Symbol(m2, Decl(arityAndOrderCompatibility01.ts, 25, 3)) ->y : Symbol(y, Decl(arityAndOrderCompatibility01.ts, 6, 3)) +>m2 : Symbol(m2, Decl(arityAndOrderCompatibility01.ts, 27, 3)) +>y : Symbol(y, Decl(arityAndOrderCompatibility01.ts, 7, 3)) var m3: [string] = z; ->m3 : Symbol(m3, Decl(arityAndOrderCompatibility01.ts, 26, 3)) ->z : Symbol(z, Decl(arityAndOrderCompatibility01.ts, 7, 3)) +>m3 : Symbol(m3, Decl(arityAndOrderCompatibility01.ts, 28, 3)) +>z : Symbol(z, Decl(arityAndOrderCompatibility01.ts, 8, 3)) var n1: [number, string] = x; ->n1 : Symbol(n1, Decl(arityAndOrderCompatibility01.ts, 27, 3)) ->x : Symbol(x, Decl(arityAndOrderCompatibility01.ts, 5, 3)) +>n1 : Symbol(n1, Decl(arityAndOrderCompatibility01.ts, 29, 3)) +>x : Symbol(x, Decl(arityAndOrderCompatibility01.ts, 6, 3)) var n2: [number, string] = y; ->n2 : Symbol(n2, Decl(arityAndOrderCompatibility01.ts, 28, 3)) ->y : Symbol(y, Decl(arityAndOrderCompatibility01.ts, 6, 3)) +>n2 : Symbol(n2, Decl(arityAndOrderCompatibility01.ts, 30, 3)) +>y : Symbol(y, Decl(arityAndOrderCompatibility01.ts, 7, 3)) var n3: [number, string] = z; ->n3 : Symbol(n3, Decl(arityAndOrderCompatibility01.ts, 29, 3)) ->z : Symbol(z, Decl(arityAndOrderCompatibility01.ts, 7, 3)) +>n3 : Symbol(n3, Decl(arityAndOrderCompatibility01.ts, 31, 3)) +>z : Symbol(z, Decl(arityAndOrderCompatibility01.ts, 8, 3)) var o1: [string, number] = x; ->o1 : Symbol(o1, Decl(arityAndOrderCompatibility01.ts, 30, 3)) ->x : Symbol(x, Decl(arityAndOrderCompatibility01.ts, 5, 3)) +>o1 : Symbol(o1, Decl(arityAndOrderCompatibility01.ts, 32, 3)) +>x : Symbol(x, Decl(arityAndOrderCompatibility01.ts, 6, 3)) var o2: [string, number] = y; ->o2 : Symbol(o2, Decl(arityAndOrderCompatibility01.ts, 31, 3)) ->y : Symbol(y, Decl(arityAndOrderCompatibility01.ts, 6, 3)) +>o2 : Symbol(o2, Decl(arityAndOrderCompatibility01.ts, 33, 3)) +>y : Symbol(y, Decl(arityAndOrderCompatibility01.ts, 7, 3)) var o3: [string, number] = y; ->o3 : Symbol(o3, Decl(arityAndOrderCompatibility01.ts, 32, 3)) ->y : Symbol(y, Decl(arityAndOrderCompatibility01.ts, 6, 3)) +>o3 : Symbol(o3, Decl(arityAndOrderCompatibility01.ts, 34, 3)) +>y : Symbol(y, Decl(arityAndOrderCompatibility01.ts, 7, 3)) diff --git a/tests/baselines/reference/arityAndOrderCompatibility01.types b/tests/baselines/reference/arityAndOrderCompatibility01.types index 934c5c6966d..80e91fbd2e7 100644 --- a/tests/baselines/reference/arityAndOrderCompatibility01.types +++ b/tests/baselines/reference/arityAndOrderCompatibility01.types @@ -5,6 +5,8 @@ interface StrNum extends Array { 0: string; 1: number; + length: 2; +>length : 2 } var x: [string, number]; @@ -15,10 +17,12 @@ var y: StrNum >StrNum : StrNum var z: { ->z : { 0: string; 1: number; } +>z : { 0: string; 1: number; length: 2; } 0: string; 1: number; + length: 2; +>length : 2 } var [a, b, c] = x; @@ -37,7 +41,7 @@ var [g, h, i] = z; >g : string >h : number >i : any ->z : { 0: string; 1: number; } +>z : { 0: string; 1: number; length: 2; } var j1: [number, number, number] = x; >j1 : [number, number, number] @@ -49,7 +53,7 @@ var j2: [number, number, number] = y; var j3: [number, number, number] = z; >j3 : [number, number, number] ->z : { 0: string; 1: number; } +>z : { 0: string; 1: number; length: 2; } var k1: [string, number, number] = x; >k1 : [string, number, number] @@ -61,7 +65,7 @@ var k2: [string, number, number] = y; var k3: [string, number, number] = z; >k3 : [string, number, number] ->z : { 0: string; 1: number; } +>z : { 0: string; 1: number; length: 2; } var l1: [number] = x; >l1 : [number] @@ -73,7 +77,7 @@ var l2: [number] = y; var l3: [number] = z; >l3 : [number] ->z : { 0: string; 1: number; } +>z : { 0: string; 1: number; length: 2; } var m1: [string] = x; >m1 : [string] @@ -85,7 +89,7 @@ var m2: [string] = y; var m3: [string] = z; >m3 : [string] ->z : { 0: string; 1: number; } +>z : { 0: string; 1: number; length: 2; } var n1: [number, string] = x; >n1 : [number, string] @@ -97,7 +101,7 @@ var n2: [number, string] = y; var n3: [number, string] = z; >n3 : [number, string] ->z : { 0: string; 1: number; } +>z : { 0: string; 1: number; length: 2; } var o1: [string, number] = x; >o1 : [string, number] diff --git a/tests/baselines/reference/arrayLiteralExpressionContextualTyping.errors.txt b/tests/baselines/reference/arrayLiteralExpressionContextualTyping.errors.txt index 3e9777aea7c..8cb36b113a7 100644 --- a/tests/baselines/reference/arrayLiteralExpressionContextualTyping.errors.txt +++ b/tests/baselines/reference/arrayLiteralExpressionContextualTyping.errors.txt @@ -1,27 +1,37 @@ +tests/cases/conformance/expressions/contextualTyping/arrayLiteralExpressionContextualTyping.ts(6,5): error TS2322: Type '[number, number, number, number]' is not assignable to type '[number, number, number]'. + Types of property 'length' are incompatible. + Type '4' is not assignable to type '3'. +tests/cases/conformance/expressions/contextualTyping/arrayLiteralExpressionContextualTyping.ts(7,5): error TS2322: Type '[number, number, number, string]' is not assignable to type '[string | number, string | number, string | number]'. + Types of property 'length' are incompatible. + Type '4' is not assignable to type '3'. tests/cases/conformance/expressions/contextualTyping/arrayLiteralExpressionContextualTyping.ts(8,5): error TS2322: Type '[number, number, number, string]' is not assignable to type '[number, number, number]'. - Types of property 'pop' are incompatible. - Type '() => string | number' is not assignable to type '() => number'. - Type 'string | number' is not assignable to type 'number'. - Type 'string' is not assignable to type 'number'. + Types of property 'length' are incompatible. + Type '4' is not assignable to type '3'. tests/cases/conformance/expressions/contextualTyping/arrayLiteralExpressionContextualTyping.ts(14,5): error TS2322: Type 'number[]' is not assignable to type '[number, number, number]'. Property '0' is missing in type 'number[]'. -==== tests/cases/conformance/expressions/contextualTyping/arrayLiteralExpressionContextualTyping.ts (2 errors) ==== +==== tests/cases/conformance/expressions/contextualTyping/arrayLiteralExpressionContextualTyping.ts (4 errors) ==== // In a contextually typed array literal expression containing no spread elements, an element expression at index N is contextually typed by // the type of the property with the numeric name N in the contextual type, if any, or otherwise // the numeric index type of the contextual type, if any. var array = [1, 2, 3]; var array1 = [true, 2, 3]; // Contextual type by the numeric index type of the contextual type var tup: [number, number, number] = [1, 2, 3, 4]; + ~~~ +!!! error TS2322: Type '[number, number, number, number]' is not assignable to type '[number, number, number]'. +!!! error TS2322: Types of property 'length' are incompatible. +!!! error TS2322: Type '4' is not assignable to type '3'. var tup1: [number|string, number|string, number|string] = [1, 2, 3, "string"]; + ~~~~ +!!! error TS2322: Type '[number, number, number, string]' is not assignable to type '[string | number, string | number, string | number]'. +!!! error TS2322: Types of property 'length' are incompatible. +!!! error TS2322: Type '4' is not assignable to type '3'. var tup2: [number, number, number] = [1, 2, 3, "string"]; // Error ~~~~ !!! error TS2322: Type '[number, number, number, string]' is not assignable to type '[number, number, number]'. -!!! error TS2322: Types of property 'pop' are incompatible. -!!! error TS2322: Type '() => string | number' is not assignable to type '() => number'. -!!! error TS2322: Type 'string | number' is not assignable to type 'number'. -!!! error TS2322: Type 'string' is not assignable to type 'number'. +!!! error TS2322: Types of property 'length' are incompatible. +!!! error TS2322: Type '4' is not assignable to type '3'. // In a contextually typed array literal expression containing one or more spread elements, // an element expression at index N is contextually typed by the numeric index type of the contextual type, if any. diff --git a/tests/baselines/reference/arrayLiterals3.errors.txt b/tests/baselines/reference/arrayLiterals3.errors.txt index 3ebf4174f51..8c36d7d59c1 100644 --- a/tests/baselines/reference/arrayLiterals3.errors.txt +++ b/tests/baselines/reference/arrayLiterals3.errors.txt @@ -3,10 +3,8 @@ tests/cases/conformance/expressions/arrayLiterals/arrayLiterals3.ts(10,5): error tests/cases/conformance/expressions/arrayLiterals/arrayLiterals3.ts(11,5): error TS2322: Type '["string", number, boolean]' is not assignable to type '[boolean, string, number]'. Type '"string"' is not assignable to type 'boolean'. tests/cases/conformance/expressions/arrayLiterals/arrayLiterals3.ts(17,5): error TS2322: Type '[number, number, string, boolean]' is not assignable to type '[number, number]'. - Types of property 'pop' are incompatible. - Type '() => string | number | boolean' is not assignable to type '() => number'. - Type 'string | number | boolean' is not assignable to type 'number'. - Type 'string' is not assignable to type 'number'. + Types of property 'length' are incompatible. + Type '4' is not assignable to type '2'. tests/cases/conformance/expressions/arrayLiterals/arrayLiterals3.ts(32,5): error TS2322: Type '(number[] | string[])[]' is not assignable to type 'tup'. Property '0' is missing in type '(number[] | string[])[]'. tests/cases/conformance/expressions/arrayLiterals/arrayLiterals3.ts(33,5): error TS2322: Type 'number[]' is not assignable to type '[number, number, number]'. @@ -46,10 +44,8 @@ tests/cases/conformance/expressions/arrayLiterals/arrayLiterals3.ts(34,5): error var [b1, b2]: [number, number] = [1, 2, "string", true]; ~~~~~~~~ !!! error TS2322: Type '[number, number, string, boolean]' is not assignable to type '[number, number]'. -!!! error TS2322: Types of property 'pop' are incompatible. -!!! error TS2322: Type '() => string | number | boolean' is not assignable to type '() => number'. -!!! error TS2322: Type 'string | number | boolean' is not assignable to type 'number'. -!!! error TS2322: Type 'string' is not assignable to type 'number'. +!!! error TS2322: Types of property 'length' are incompatible. +!!! error TS2322: Type '4' is not assignable to type '2'. // The resulting type an array literal expression is determined as follows: // - the resulting type is an array type with an element type that is the union of the types of the diff --git a/tests/baselines/reference/arrayLiteralsWithRecursiveGenerics.types b/tests/baselines/reference/arrayLiteralsWithRecursiveGenerics.types index 9cdbe0a0a61..75013cdef09 100644 --- a/tests/baselines/reference/arrayLiteralsWithRecursiveGenerics.types +++ b/tests/baselines/reference/arrayLiteralsWithRecursiveGenerics.types @@ -55,8 +55,8 @@ var myList: MyList; >MyList : MyList var xs = [list, myList]; // {}[] ->xs : List[] ->[list, myList] : List[] +>xs : (List | MyList)[] +>[list, myList] : (List | MyList)[] >list : List >myList : MyList diff --git a/tests/baselines/reference/asyncFunctionDeclaration10_es2017.errors.txt b/tests/baselines/reference/asyncFunctionDeclaration10_es2017.errors.txt index 33cd913a2eb..12f9974484b 100644 --- a/tests/baselines/reference/asyncFunctionDeclaration10_es2017.errors.txt +++ b/tests/baselines/reference/asyncFunctionDeclaration10_es2017.errors.txt @@ -4,11 +4,12 @@ tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclarati tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration10_es2017.ts(1,33): error TS2304: Cannot find name 'await'. tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration10_es2017.ts(1,38): error TS1005: ';' expected. tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration10_es2017.ts(1,39): error TS1128: Declaration or statement expected. +tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration10_es2017.ts(1,41): error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration10_es2017.ts(1,49): error TS2532: Object is possibly 'undefined'. tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration10_es2017.ts(1,53): error TS1109: Expression expected. -==== tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration10_es2017.ts (8 errors) ==== +==== tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration10_es2017.ts (9 errors) ==== async function foo(a = await => await): Promise { ~~~~~~~~~ !!! error TS2371: A parameter initializer is only allowed in a function or constructor implementation. @@ -22,8 +23,11 @@ tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclarati !!! error TS1005: ';' expected. ~ !!! error TS1128: Declaration or statement expected. + ~~~~~~~~~~~~~~~ ~~~~ !!! error TS2532: Object is possibly 'undefined'. ~ !!! error TS1109: Expression expected. - } \ No newline at end of file + } + ~ +!!! error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. \ No newline at end of file diff --git a/tests/baselines/reference/asyncFunctionDeclaration10_es5.errors.txt b/tests/baselines/reference/asyncFunctionDeclaration10_es5.errors.txt index b974eacd882..155119784ba 100644 --- a/tests/baselines/reference/asyncFunctionDeclaration10_es5.errors.txt +++ b/tests/baselines/reference/asyncFunctionDeclaration10_es5.errors.txt @@ -4,11 +4,12 @@ tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration1 tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts(1,33): error TS2304: Cannot find name 'await'. tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts(1,38): error TS1005: ';' expected. tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts(1,39): error TS1128: Declaration or statement expected. +tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts(1,41): error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts(1,49): error TS2532: Object is possibly 'undefined'. tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts(1,53): error TS1109: Expression expected. -==== tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts (8 errors) ==== +==== tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts (9 errors) ==== async function foo(a = await => await): Promise { ~~~~~~~~~ !!! error TS2371: A parameter initializer is only allowed in a function or constructor implementation. @@ -22,8 +23,11 @@ tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration1 !!! error TS1005: ';' expected. ~ !!! error TS1128: Declaration or statement expected. + ~~~~~~~~~~~~~~~ ~~~~ !!! error TS2532: Object is possibly 'undefined'. ~ !!! error TS1109: Expression expected. - } \ No newline at end of file + } + ~ +!!! error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. \ No newline at end of file diff --git a/tests/baselines/reference/asyncFunctionDeclaration10_es6.errors.txt b/tests/baselines/reference/asyncFunctionDeclaration10_es6.errors.txt index b752ec94a45..7f5266f931e 100644 --- a/tests/baselines/reference/asyncFunctionDeclaration10_es6.errors.txt +++ b/tests/baselines/reference/asyncFunctionDeclaration10_es6.errors.txt @@ -4,11 +4,12 @@ tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration1 tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration10_es6.ts(1,33): error TS2304: Cannot find name 'await'. tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration10_es6.ts(1,38): error TS1005: ';' expected. tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration10_es6.ts(1,39): error TS1128: Declaration or statement expected. +tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration10_es6.ts(1,41): error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration10_es6.ts(1,49): error TS2532: Object is possibly 'undefined'. tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration10_es6.ts(1,53): error TS1109: Expression expected. -==== tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration10_es6.ts (8 errors) ==== +==== tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration10_es6.ts (9 errors) ==== async function foo(a = await => await): Promise { ~~~~~~~~~ !!! error TS2371: A parameter initializer is only allowed in a function or constructor implementation. @@ -22,8 +23,11 @@ tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration1 !!! error TS1005: ';' expected. ~ !!! error TS1128: Declaration or statement expected. + ~~~~~~~~~~~~~~~ ~~~~ !!! error TS2532: Object is possibly 'undefined'. ~ !!! error TS1109: Expression expected. - } \ No newline at end of file + } + ~ +!!! error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. \ No newline at end of file diff --git a/tests/baselines/reference/asyncFunctionDeclaration5_es2017.errors.txt b/tests/baselines/reference/asyncFunctionDeclaration5_es2017.errors.txt index 1fc74dfa0a2..2d110f68127 100644 --- a/tests/baselines/reference/asyncFunctionDeclaration5_es2017.errors.txt +++ b/tests/baselines/reference/asyncFunctionDeclaration5_es2017.errors.txt @@ -2,11 +2,12 @@ tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclarati tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration5_es2017.ts(1,20): error TS2304: Cannot find name 'await'. tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration5_es2017.ts(1,25): error TS1005: ';' expected. tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration5_es2017.ts(1,26): error TS1128: Declaration or statement expected. +tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration5_es2017.ts(1,28): error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration5_es2017.ts(1,36): error TS2532: Object is possibly 'undefined'. tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration5_es2017.ts(1,40): error TS1109: Expression expected. -==== tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration5_es2017.ts (6 errors) ==== +==== tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration5_es2017.ts (7 errors) ==== async function foo(await): Promise { ~~~~~ !!! error TS1138: Parameter declaration expected. @@ -16,8 +17,11 @@ tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclarati !!! error TS1005: ';' expected. ~ !!! error TS1128: Declaration or statement expected. + ~~~~~~~~~~~~~~~ ~~~~ !!! error TS2532: Object is possibly 'undefined'. ~ !!! error TS1109: Expression expected. - } \ No newline at end of file + } + ~ +!!! error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. \ No newline at end of file diff --git a/tests/baselines/reference/asyncFunctionDeclaration5_es5.errors.txt b/tests/baselines/reference/asyncFunctionDeclaration5_es5.errors.txt index 48299773218..6607ec7ff5c 100644 --- a/tests/baselines/reference/asyncFunctionDeclaration5_es5.errors.txt +++ b/tests/baselines/reference/asyncFunctionDeclaration5_es5.errors.txt @@ -2,11 +2,12 @@ tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration5 tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration5_es5.ts(1,20): error TS2304: Cannot find name 'await'. tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration5_es5.ts(1,25): error TS1005: ';' expected. tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration5_es5.ts(1,26): error TS1128: Declaration or statement expected. +tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration5_es5.ts(1,28): error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration5_es5.ts(1,36): error TS2532: Object is possibly 'undefined'. tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration5_es5.ts(1,40): error TS1109: Expression expected. -==== tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration5_es5.ts (6 errors) ==== +==== tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration5_es5.ts (7 errors) ==== async function foo(await): Promise { ~~~~~ !!! error TS1138: Parameter declaration expected. @@ -16,8 +17,11 @@ tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration5 !!! error TS1005: ';' expected. ~ !!! error TS1128: Declaration or statement expected. + ~~~~~~~~~~~~~~~ ~~~~ !!! error TS2532: Object is possibly 'undefined'. ~ !!! error TS1109: Expression expected. - } \ No newline at end of file + } + ~ +!!! error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. \ No newline at end of file diff --git a/tests/baselines/reference/asyncFunctionDeclaration5_es6.errors.txt b/tests/baselines/reference/asyncFunctionDeclaration5_es6.errors.txt index 2e907d13400..ccddf6d5c04 100644 --- a/tests/baselines/reference/asyncFunctionDeclaration5_es6.errors.txt +++ b/tests/baselines/reference/asyncFunctionDeclaration5_es6.errors.txt @@ -2,11 +2,12 @@ tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration5 tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration5_es6.ts(1,20): error TS2304: Cannot find name 'await'. tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration5_es6.ts(1,25): error TS1005: ';' expected. tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration5_es6.ts(1,26): error TS1128: Declaration or statement expected. +tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration5_es6.ts(1,28): error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration5_es6.ts(1,36): error TS2532: Object is possibly 'undefined'. tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration5_es6.ts(1,40): error TS1109: Expression expected. -==== tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration5_es6.ts (6 errors) ==== +==== tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration5_es6.ts (7 errors) ==== async function foo(await): Promise { ~~~~~ !!! error TS1138: Parameter declaration expected. @@ -16,8 +17,11 @@ tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration5 !!! error TS1005: ';' expected. ~ !!! error TS1128: Declaration or statement expected. + ~~~~~~~~~~~~~~~ ~~~~ !!! error TS2532: Object is possibly 'undefined'. ~ !!! error TS1109: Expression expected. - } \ No newline at end of file + } + ~ +!!! error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. \ No newline at end of file diff --git a/tests/baselines/reference/augmentedTypesClass3.js b/tests/baselines/reference/augmentedTypesClass3.js index d2ad63161b5..045109f8587 100644 --- a/tests/baselines/reference/augmentedTypesClass3.js +++ b/tests/baselines/reference/augmentedTypesClass3.js @@ -46,4 +46,4 @@ var c5c = /** @class */ (function () { c5c.prototype.foo = function () { }; return c5c; }()); -//import c5c = require(''); +//import c5c = require(''); diff --git a/tests/baselines/reference/augmentedTypesEnum.js b/tests/baselines/reference/augmentedTypesEnum.js index ff0ad93f817..edd4a92d767 100644 --- a/tests/baselines/reference/augmentedTypesEnum.js +++ b/tests/baselines/reference/augmentedTypesEnum.js @@ -100,4 +100,4 @@ var e6b; })(e6b || (e6b = {})); // should be error // enum then import, messes with error reporting //enum e7 { One } -//import e7 = require(''); // should be error +//import e7 = require(''); // should be error diff --git a/tests/baselines/reference/augmentedTypesEnum2.js b/tests/baselines/reference/augmentedTypesEnum2.js index 66fc96b62a0..0e6e70df263 100644 --- a/tests/baselines/reference/augmentedTypesEnum2.js +++ b/tests/baselines/reference/augmentedTypesEnum2.js @@ -41,4 +41,4 @@ var e2 = /** @class */ (function () { return e2; }()); //enum then enum - covered -//enum then import - covered +//enum then import - covered diff --git a/tests/baselines/reference/augmentedTypesFunction.js b/tests/baselines/reference/augmentedTypesFunction.js index 3c6066e5bb4..a2dd4a664a3 100644 --- a/tests/baselines/reference/augmentedTypesFunction.js +++ b/tests/baselines/reference/augmentedTypesFunction.js @@ -79,4 +79,4 @@ function y5b() { } function y5c() { } // function then import, messes with other errors //function y6() { } -//import y6 = require(''); +//import y6 = require(''); diff --git a/tests/baselines/reference/augmentedTypesInterface.js b/tests/baselines/reference/augmentedTypesInterface.js index b74da5bbfee..0409e157584 100644 --- a/tests/baselines/reference/augmentedTypesInterface.js +++ b/tests/baselines/reference/augmentedTypesInterface.js @@ -48,4 +48,4 @@ var i3; i3[i3["One"] = 0] = "One"; })(i3 || (i3 = {})); ; // error -//import i4 = require(''); // error +//import i4 = require(''); // error diff --git a/tests/baselines/reference/bestCommonTypeOfConditionalExpressions.types b/tests/baselines/reference/bestCommonTypeOfConditionalExpressions.types index f3ea48e637b..9a10984a522 100644 --- a/tests/baselines/reference/bestCommonTypeOfConditionalExpressions.types +++ b/tests/baselines/reference/bestCommonTypeOfConditionalExpressions.types @@ -47,7 +47,7 @@ var r = true ? 1 : 2; var r3 = true ? 1 : {}; >r3 : {} ->true ? 1 : {} : {} +>true ? 1 : {} : 1 | {} >true : true >1 : 1 >{} : {} diff --git a/tests/baselines/reference/capturedParametersInInitializers2.js b/tests/baselines/reference/capturedParametersInInitializers2.js index 2e833cac003..8982862af4f 100644 --- a/tests/baselines/reference/capturedParametersInInitializers2.js +++ b/tests/baselines/reference/capturedParametersInInitializers2.js @@ -19,11 +19,14 @@ function foo(y, x) { var _a; } function foo2(y, x) { - if (y === void 0) { y = /** @class */ (function () { - function class_2() { - this[x] = x; - } - return class_2; - }()); } + if (y === void 0) { y = (_a = /** @class */ (function () { + function class_2() { + this[_b] = x; + } + return class_2; + }()), + _b = x, + _a); } if (x === void 0) { x = 1; } + var _b, _a; } diff --git a/tests/baselines/reference/castingTuple.errors.txt b/tests/baselines/reference/castingTuple.errors.txt index eb6aac5f463..a17f8c2b082 100644 --- a/tests/baselines/reference/castingTuple.errors.txt +++ b/tests/baselines/reference/castingTuple.errors.txt @@ -1,13 +1,21 @@ -tests/cases/conformance/types/tuple/castingTuple.ts(28,10): error TS2352: Type '[number, string]' cannot be converted to type '[number, number]'. +tests/cases/conformance/types/tuple/castingTuple.ts(13,23): error TS2352: Type '[number, string]' cannot be converted to type '[number, string, boolean]'. + Property '2' is missing in type '[number, string]'. +tests/cases/conformance/types/tuple/castingTuple.ts(14,15): error TS2352: Type '[number, string, boolean]' cannot be converted to type '[number, string]'. + Types of property 'length' are incompatible. + Type '3' is not comparable to type '2'. +tests/cases/conformance/types/tuple/castingTuple.ts(15,14): error TS2352: Type '[number, string]' cannot be converted to type '[number, string, boolean]'. +tests/cases/conformance/types/tuple/castingTuple.ts(18,21): error TS2352: Type '[C, D]' cannot be converted to type '[C, D, A]'. + Property '2' is missing in type '[C, D]'. +tests/cases/conformance/types/tuple/castingTuple.ts(30,10): error TS2352: Type '[number, string]' cannot be converted to type '[number, number]'. Type 'string' is not comparable to type 'number'. -tests/cases/conformance/types/tuple/castingTuple.ts(29,10): error TS2352: Type '[C, D]' cannot be converted to type '[A, I]'. +tests/cases/conformance/types/tuple/castingTuple.ts(31,10): error TS2352: Type '[C, D]' cannot be converted to type '[A, I]'. Type 'C' is not comparable to type 'A'. Property 'a' is missing in type 'C'. -tests/cases/conformance/types/tuple/castingTuple.ts(30,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'array1' has type '{}[]' at tests/cases/conformance/types/tuple/castingTuple.ts 20:4, but here has type 'number[]'. -tests/cases/conformance/types/tuple/castingTuple.ts(31,1): error TS2304: Cannot find name 't4'. +tests/cases/conformance/types/tuple/castingTuple.ts(32,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'array1' has type '{}[]' at tests/cases/conformance/types/tuple/castingTuple.ts 22:4, but here has type 'number[]'. +tests/cases/conformance/types/tuple/castingTuple.ts(33,1): error TS2304: Cannot find name 't4'. -==== tests/cases/conformance/types/tuple/castingTuple.ts (4 errors) ==== +==== tests/cases/conformance/types/tuple/castingTuple.ts (8 errors) ==== interface I { } class A { a = 10; } class C implements I { c }; @@ -21,9 +29,23 @@ tests/cases/conformance/types/tuple/castingTuple.ts(31,1): error TS2304: Cannot var numStrTuple: [number, string] = [5, "foo"]; var emptyObjTuple = <[{}, {}]>numStrTuple; var numStrBoolTuple = <[number, string, boolean]>numStrTuple; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2352: Type '[number, string]' cannot be converted to type '[number, string, boolean]'. +!!! error TS2352: Property '2' is missing in type '[number, string]'. + var shorter = numStrBoolTuple as [number, string] + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2352: Type '[number, string, boolean]' cannot be converted to type '[number, string]'. +!!! error TS2352: Types of property 'length' are incompatible. +!!! error TS2352: Type '3' is not comparable to type '2'. + var longer = numStrTuple as [number, string, boolean] + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2352: Type '[number, string]' cannot be converted to type '[number, string, boolean]'. var classCDTuple: [C, D] = [new C(), new D()]; var interfaceIITuple = <[I, I]>classCDTuple; var classCDATuple = <[C, D, A]>classCDTuple; + ~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2352: Type '[C, D]' cannot be converted to type '[C, D, A]'. +!!! error TS2352: Property '2' is missing in type '[C, D]'. var eleFromCDA1 = classCDATuple[2]; // A var eleFromCDA2 = classCDATuple[5]; // C | D | A var t10: [E1, E2] = [E1.one, E2.one]; @@ -46,7 +68,7 @@ tests/cases/conformance/types/tuple/castingTuple.ts(31,1): error TS2304: Cannot !!! error TS2352: Property 'a' is missing in type 'C'. var array1 = numStrTuple; ~~~~~~ -!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'array1' has type '{}[]' at tests/cases/conformance/types/tuple/castingTuple.ts 20:4, but here has type 'number[]'. +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'array1' has type '{}[]' at tests/cases/conformance/types/tuple/castingTuple.ts 22:4, but here has type 'number[]'. t4[2] = 10; ~~ !!! error TS2304: Cannot find name 't4'. diff --git a/tests/baselines/reference/castingTuple.js b/tests/baselines/reference/castingTuple.js index 3744d40d8a5..a94246a19b8 100644 --- a/tests/baselines/reference/castingTuple.js +++ b/tests/baselines/reference/castingTuple.js @@ -12,6 +12,8 @@ enum E2 { one } var numStrTuple: [number, string] = [5, "foo"]; var emptyObjTuple = <[{}, {}]>numStrTuple; var numStrBoolTuple = <[number, string, boolean]>numStrTuple; +var shorter = numStrBoolTuple as [number, string] +var longer = numStrTuple as [number, string, boolean] var classCDTuple: [C, D] = [new C(), new D()]; var interfaceIITuple = <[I, I]>classCDTuple; var classCDATuple = <[C, D, A]>classCDTuple; @@ -89,6 +91,8 @@ var E2; var numStrTuple = [5, "foo"]; var emptyObjTuple = numStrTuple; var numStrBoolTuple = numStrTuple; +var shorter = numStrBoolTuple; +var longer = numStrTuple; var classCDTuple = [new C(), new D()]; var interfaceIITuple = classCDTuple; var classCDATuple = classCDTuple; diff --git a/tests/baselines/reference/castingTuple.symbols b/tests/baselines/reference/castingTuple.symbols index 61edfb4b376..3cf5face2a6 100644 --- a/tests/baselines/reference/castingTuple.symbols +++ b/tests/baselines/reference/castingTuple.symbols @@ -46,37 +46,45 @@ var numStrBoolTuple = <[number, string, boolean]>numStrTuple; >numStrBoolTuple : Symbol(numStrBoolTuple, Decl(castingTuple.ts, 12, 3)) >numStrTuple : Symbol(numStrTuple, Decl(castingTuple.ts, 10, 3)) +var shorter = numStrBoolTuple as [number, string] +>shorter : Symbol(shorter, Decl(castingTuple.ts, 13, 3)) +>numStrBoolTuple : Symbol(numStrBoolTuple, Decl(castingTuple.ts, 12, 3)) + +var longer = numStrTuple as [number, string, boolean] +>longer : Symbol(longer, Decl(castingTuple.ts, 14, 3)) +>numStrTuple : Symbol(numStrTuple, Decl(castingTuple.ts, 10, 3)) + var classCDTuple: [C, D] = [new C(), new D()]; ->classCDTuple : Symbol(classCDTuple, Decl(castingTuple.ts, 13, 3)) +>classCDTuple : Symbol(classCDTuple, Decl(castingTuple.ts, 15, 3)) >C : Symbol(C, Decl(castingTuple.ts, 1, 19)) >D : Symbol(D, Decl(castingTuple.ts, 2, 27)) >C : Symbol(C, Decl(castingTuple.ts, 1, 19)) >D : Symbol(D, Decl(castingTuple.ts, 2, 27)) var interfaceIITuple = <[I, I]>classCDTuple; ->interfaceIITuple : Symbol(interfaceIITuple, Decl(castingTuple.ts, 14, 3)) +>interfaceIITuple : Symbol(interfaceIITuple, Decl(castingTuple.ts, 16, 3)) >I : Symbol(I, Decl(castingTuple.ts, 0, 0)) >I : Symbol(I, Decl(castingTuple.ts, 0, 0)) ->classCDTuple : Symbol(classCDTuple, Decl(castingTuple.ts, 13, 3)) +>classCDTuple : Symbol(classCDTuple, Decl(castingTuple.ts, 15, 3)) var classCDATuple = <[C, D, A]>classCDTuple; ->classCDATuple : Symbol(classCDATuple, Decl(castingTuple.ts, 15, 3)) +>classCDATuple : Symbol(classCDATuple, Decl(castingTuple.ts, 17, 3)) >C : Symbol(C, Decl(castingTuple.ts, 1, 19)) >D : Symbol(D, Decl(castingTuple.ts, 2, 27)) >A : Symbol(A, Decl(castingTuple.ts, 0, 15)) ->classCDTuple : Symbol(classCDTuple, Decl(castingTuple.ts, 13, 3)) +>classCDTuple : Symbol(classCDTuple, Decl(castingTuple.ts, 15, 3)) var eleFromCDA1 = classCDATuple[2]; // A ->eleFromCDA1 : Symbol(eleFromCDA1, Decl(castingTuple.ts, 16, 3)) ->classCDATuple : Symbol(classCDATuple, Decl(castingTuple.ts, 15, 3)) +>eleFromCDA1 : Symbol(eleFromCDA1, Decl(castingTuple.ts, 18, 3)) +>classCDATuple : Symbol(classCDATuple, Decl(castingTuple.ts, 17, 3)) >2 : Symbol(2) var eleFromCDA2 = classCDATuple[5]; // C | D | A ->eleFromCDA2 : Symbol(eleFromCDA2, Decl(castingTuple.ts, 17, 3)) ->classCDATuple : Symbol(classCDATuple, Decl(castingTuple.ts, 15, 3)) +>eleFromCDA2 : Symbol(eleFromCDA2, Decl(castingTuple.ts, 19, 3)) +>classCDATuple : Symbol(classCDATuple, Decl(castingTuple.ts, 17, 3)) var t10: [E1, E2] = [E1.one, E2.one]; ->t10 : Symbol(t10, Decl(castingTuple.ts, 18, 3)) +>t10 : Symbol(t10, Decl(castingTuple.ts, 20, 3)) >E1 : Symbol(E1, Decl(castingTuple.ts, 5, 24)) >E2 : Symbol(E2, Decl(castingTuple.ts, 6, 15)) >E1.one : Symbol(E1.one, Decl(castingTuple.ts, 6, 9)) @@ -87,45 +95,45 @@ var t10: [E1, E2] = [E1.one, E2.one]; >one : Symbol(E2.one, Decl(castingTuple.ts, 7, 9)) var t11 = <[number, number]>t10; ->t11 : Symbol(t11, Decl(castingTuple.ts, 19, 3)) ->t10 : Symbol(t10, Decl(castingTuple.ts, 18, 3)) +>t11 : Symbol(t11, Decl(castingTuple.ts, 21, 3)) +>t10 : Symbol(t10, Decl(castingTuple.ts, 20, 3)) var array1 = <{}[]>emptyObjTuple; ->array1 : Symbol(array1, Decl(castingTuple.ts, 20, 3), Decl(castingTuple.ts, 29, 3)) +>array1 : Symbol(array1, Decl(castingTuple.ts, 22, 3), Decl(castingTuple.ts, 31, 3)) >emptyObjTuple : Symbol(emptyObjTuple, Decl(castingTuple.ts, 11, 3)) var unionTuple: [C, string | number] = [new C(), "foo"]; ->unionTuple : Symbol(unionTuple, Decl(castingTuple.ts, 21, 3)) +>unionTuple : Symbol(unionTuple, Decl(castingTuple.ts, 23, 3)) >C : Symbol(C, Decl(castingTuple.ts, 1, 19)) >C : Symbol(C, Decl(castingTuple.ts, 1, 19)) var unionTuple2: [C, string | number, D] = [new C(), "foo", new D()]; ->unionTuple2 : Symbol(unionTuple2, Decl(castingTuple.ts, 22, 3)) +>unionTuple2 : Symbol(unionTuple2, Decl(castingTuple.ts, 24, 3)) >C : Symbol(C, Decl(castingTuple.ts, 1, 19)) >D : Symbol(D, Decl(castingTuple.ts, 2, 27)) >C : Symbol(C, Decl(castingTuple.ts, 1, 19)) >D : Symbol(D, Decl(castingTuple.ts, 2, 27)) var unionTuple3: [number, string| number] = [10, "foo"]; ->unionTuple3 : Symbol(unionTuple3, Decl(castingTuple.ts, 23, 3)) +>unionTuple3 : Symbol(unionTuple3, Decl(castingTuple.ts, 25, 3)) var unionTuple4 = <[number, number]>unionTuple3; ->unionTuple4 : Symbol(unionTuple4, Decl(castingTuple.ts, 24, 3)) ->unionTuple3 : Symbol(unionTuple3, Decl(castingTuple.ts, 23, 3)) +>unionTuple4 : Symbol(unionTuple4, Decl(castingTuple.ts, 26, 3)) +>unionTuple3 : Symbol(unionTuple3, Decl(castingTuple.ts, 25, 3)) // error var t3 = <[number, number]>numStrTuple; ->t3 : Symbol(t3, Decl(castingTuple.ts, 27, 3)) +>t3 : Symbol(t3, Decl(castingTuple.ts, 29, 3)) >numStrTuple : Symbol(numStrTuple, Decl(castingTuple.ts, 10, 3)) var t9 = <[A, I]>classCDTuple; ->t9 : Symbol(t9, Decl(castingTuple.ts, 28, 3)) +>t9 : Symbol(t9, Decl(castingTuple.ts, 30, 3)) >A : Symbol(A, Decl(castingTuple.ts, 0, 15)) >I : Symbol(I, Decl(castingTuple.ts, 0, 0)) ->classCDTuple : Symbol(classCDTuple, Decl(castingTuple.ts, 13, 3)) +>classCDTuple : Symbol(classCDTuple, Decl(castingTuple.ts, 15, 3)) var array1 = numStrTuple; ->array1 : Symbol(array1, Decl(castingTuple.ts, 20, 3), Decl(castingTuple.ts, 29, 3)) +>array1 : Symbol(array1, Decl(castingTuple.ts, 22, 3), Decl(castingTuple.ts, 31, 3)) >numStrTuple : Symbol(numStrTuple, Decl(castingTuple.ts, 10, 3)) t4[2] = 10; diff --git a/tests/baselines/reference/castingTuple.types b/tests/baselines/reference/castingTuple.types index 23d2e51a576..0b9aa0a1487 100644 --- a/tests/baselines/reference/castingTuple.types +++ b/tests/baselines/reference/castingTuple.types @@ -52,6 +52,16 @@ var numStrBoolTuple = <[number, string, boolean]>numStrTuple; ><[number, string, boolean]>numStrTuple : [number, string, boolean] >numStrTuple : [number, string] +var shorter = numStrBoolTuple as [number, string] +>shorter : [number, string] +>numStrBoolTuple as [number, string] : [number, string] +>numStrBoolTuple : [number, string, boolean] + +var longer = numStrTuple as [number, string, boolean] +>longer : [number, string, boolean] +>numStrTuple as [number, string, boolean] : [number, string, boolean] +>numStrTuple : [number, string] + var classCDTuple: [C, D] = [new C(), new D()]; >classCDTuple : [C, D] >C : C diff --git a/tests/baselines/reference/checkJsxChildrenProperty14.errors.txt b/tests/baselines/reference/checkJsxChildrenProperty14.errors.txt new file mode 100644 index 00000000000..ecae349e19e --- /dev/null +++ b/tests/baselines/reference/checkJsxChildrenProperty14.errors.txt @@ -0,0 +1,56 @@ +tests/cases/conformance/jsx/file.tsx(42,27): error TS2322: Type '{ a: 10; b: "hi"; children: Element[]; }' is not assignable to type 'IntrinsicAttributes & SingleChildProp'. + Type '{ a: 10; b: "hi"; children: Element[]; }' is not assignable to type 'SingleChildProp'. + Types of property 'children' are incompatible. + Type 'Element[]' is not assignable to type 'Element'. + Property 'type' is missing in type 'Element[]'. + + +==== tests/cases/conformance/jsx/file.tsx (1 errors) ==== + import React = require('react'); + + interface Prop { + a: number, + b: string, + children: JSX.Element | JSX.Element[]; + } + + class Button extends React.Component { + render() { + return (
My Button
) + } + } + + function AnotherButton(p: any) { + return

Just Another Button

; + } + + function Comp(p: Prop) { + return
{p.b}
; + } + + // OK + let k1 = <>