diff --git a/.gitmodules b/.gitmodules index f7632c4abbd..fdf474a693d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -18,7 +18,19 @@ path = tests/cases/user/TypeScript-WeChat-Starter/TypeScript-WeChat-Starter url = https://github.com/Microsoft/TypeScript-WeChat-Starter.git ignore = all +[submodule "tests/cases/user/create-react-app/create-react-app"] + path = tests/cases/user/create-react-app/create-react-app + url = https://github.com/facebook/create-react-app.git + ignore = all [submodule "tests/cases/user/webpack/webpack"] path = tests/cases/user/webpack/webpack url = https://github.com/webpack/webpack.git ignore = all +[submodule "tests/cases/user/puppeteer/puppeteer"] + path = tests/cases/user/puppeteer/puppeteer + url = https://github.com/GoogleChrome/puppeteer.git + ignore = all +[submodule "tests/cases/user/axios-src/axios-src"] + path = tests/cases/user/axios-src/axios-src + url = https://github.com/axios/axios.git + ignore = all diff --git a/Gulpfile.ts b/Gulpfile.js similarity index 85% rename from Gulpfile.ts rename to Gulpfile.js index 1c6cfdd7ed1..afa7e775dcd 100644 --- a/Gulpfile.ts +++ b/Gulpfile.js @@ -1,35 +1,27 @@ /// -import * as cp from "child_process"; -import * as path from "path"; -import * as fs from "fs"; -import child_process = require("child_process"); -import originalGulp = require("gulp"); -import helpMaker = require("gulp-help"); -import runSequence = require("run-sequence"); -import concat = require("gulp-concat"); -import clone = require("gulp-clone"); -import newer = require("gulp-newer"); -import tsc = require("gulp-typescript"); -declare module "gulp-typescript" { - interface Settings { - pretty?: boolean; - newLine?: string; - noImplicitThis?: boolean; - stripInternal?: boolean; - types?: string[]; - } -} -import * as insert from "gulp-insert"; -import * as sourcemaps from "gulp-sourcemaps"; -import Q = require("q"); -import del = require("del"); -import mkdirP = require("mkdirp"); -import minimist = require("minimist"); -import browserify = require("browserify"); -import through2 = require("through2"); -import merge2 = require("merge2"); -import * as os from "os"; -import fold = require("travis-fold"); +// @ts-check +const cp = require("child_process"); +const path = require("path"); +const fs = require("fs"); +const child_process = require("child_process"); +const originalGulp = require("gulp"); +const helpMaker = require("gulp-help"); +const runSequence = require("run-sequence"); +const concat = require("gulp-concat"); +const clone = require("gulp-clone"); +const newer = require("gulp-newer"); +const tsc = require("gulp-typescript"); +const insert = require("gulp-insert"); +const sourcemaps = require("gulp-sourcemaps"); +const Q = require("q"); +const del = require("del"); +const mkdirP = require("mkdirp"); +const minimist = require("minimist"); +const browserify = require("browserify"); +const through2 = require("through2"); +const merge2 = require("merge2"); +const os = require("os"); +const fold = require("travis-fold"); const gulp = helpMaker(originalGulp); Error.stackTraceLimit = 1000; @@ -73,17 +65,26 @@ const cmdLineOptions = minimist(process.argv.slice(2), { }); const noop = () => {}; // tslint:disable-line no-empty -function exec(cmd: string, args: string[], complete: () => void = noop, error: (e: any, status: number) => void = noop) { +/** + * @param {string} cmd + * @param {string[]} args + * @param {() => void} complete + * @param {(e: *, status: number) => void} error + */ +function exec(cmd, args, complete = noop, error = noop) { console.log(`${cmd} ${args.join(" ")}`); // TODO (weswig): Update child_process types to add windowsVerbatimArguments to the type definition const subshellFlag = isWin ? "/c" : "-c"; const command = isWin ? [possiblyQuote(cmd), ...args] : [`${cmd} ${args.join(" ")}`]; - const ex = cp.spawn(isWin ? "cmd" : "/bin/sh", [subshellFlag, ...command], { stdio: "inherit", windowsVerbatimArguments: true } as any); + const ex = cp.spawn(isWin ? "cmd" : "/bin/sh", [subshellFlag, ...command], { stdio: "inherit", windowsVerbatimArguments: true }); ex.on("exit", (code) => code === 0 ? complete() : error(/*e*/ undefined, code)); ex.on("error", error); } -function possiblyQuote(cmd: string) { +/** + * @param {string} cmd + */ +function possiblyQuote(cmd) { return cmd.indexOf(" ") >= 0 ? `"${cmd}"` : cmd; } @@ -215,12 +216,17 @@ for (const i in libraryTargets) { .pipe(gulp.dest("."))); } -const configureNightlyJs = path.join(scriptsDirectory, "configureNightly.js"); -const configureNightlyTs = path.join(scriptsDirectory, "configureNightly.ts"); +const configurePreleleaseJs = path.join(scriptsDirectory, "configurePrerelease.js"); +const configurePreleleaseTs = path.join(scriptsDirectory, "configurePrerelease.ts"); const packageJson = "package.json"; const versionFile = path.join(compilerDirectory, "core.ts"); -function needsUpdate(source: string | string[], dest: string | string[]): boolean { +/** + * @param {string | string[]} source + * @param {string | string[]} dest + * @returns {boolean} + */ +function needsUpdate(source, dest) { if (typeof source === "string" && typeof dest === "string") { if (fs.existsSync(dest)) { const {mtime: outTime} = fs.statSync(dest); @@ -283,8 +289,13 @@ function needsUpdate(source: string | string[], dest: string | string[]): boolea return true; } -function getCompilerSettings(base: tsc.Settings, useBuiltCompiler?: boolean): tsc.Settings { - const copy: tsc.Settings = {}; +/** + * @param {tsc.Settings} base + * @param {boolean=} useBuiltCompiler + * @returns {tsc.Settings} + */ +function getCompilerSettings(base, useBuiltCompiler) { + const copy = /** @type {tsc.Settings} */ ({}); for (const key in base) { copy[key] = base[key]; } @@ -293,32 +304,34 @@ function getCompilerSettings(base: tsc.Settings, useBuiltCompiler?: boolean): ts } copy.newLine = "lf"; if (useBuiltCompiler === true) { - copy.typescript = require("./built/local/typescript.js"); + copy.typescript = /** @type {*} */ (require("./built/local/typescript.js")); } else if (useBuiltCompiler === false) { - copy.typescript = require("./lib/typescript.js"); + copy.typescript = /** @type {*} */ (require("./lib/typescript.js")); } return copy; } -gulp.task(configureNightlyJs, /*help*/ false, [], () => { - const settings: tsc.Settings = { +gulp.task(configurePreleleaseJs, /*help*/ false, [], () => { + /** @type {tsc.Settings} */ + const settings = { declaration: false, removeComments: true, noResolve: false, stripInternal: false, + module: "commonjs" }; - return gulp.src(configureNightlyTs) + return gulp.src(configurePreleleaseTs) .pipe(sourcemaps.init()) .pipe(tsc(settings)) - .pipe(sourcemaps.write(path.dirname(configureNightlyJs))) - .pipe(gulp.dest(path.dirname(configureNightlyJs))); + .pipe(sourcemaps.write(".")) + .pipe(gulp.dest("./scripts")); }); // Nightly management tasks -gulp.task("configure-nightly", "Runs scripts/configureNightly.ts to prepare a build for nightly publishing", [configureNightlyJs], (done) => { - exec(host, [configureNightlyJs, packageJson, versionFile], done, done); +gulp.task("configure-nightly", "Runs scripts/configurePrerelease.ts to prepare a build for nightly publishing", [configurePreleleaseJs], (done) => { + exec(host, [configurePreleleaseJs, "dev", packageJson, versionFile], done, done); }); gulp.task("publish-nightly", "Runs `npm publish --tag next` to create a new nightly build on npm", ["LKG"], () => { return runSequence("clean", "useDebugMode", "runtests-parallel", (done) => { @@ -331,7 +344,8 @@ const importDefinitelyTypedTestsJs = path.join(importDefinitelyTypedTestsDirecto const importDefinitelyTypedTestsTs = path.join(importDefinitelyTypedTestsDirectory, "importDefinitelyTypedTests.ts"); gulp.task(importDefinitelyTypedTestsJs, /*help*/ false, [], () => { - const settings: tsc.Settings = getCompilerSettings({ + /** @type {tsc.Settings} */ + const settings = getCompilerSettings({ declaration: false, removeComments: true, noResolve: false, @@ -362,20 +376,11 @@ const builtGeneratedDiagnosticMessagesJSON = path.join(builtLocalDirectory, "dia // processDiagnosticMessages script gulp.task(processDiagnosticMessagesJs, /*help*/ false, [], () => { - const settings: tsc.Settings = getCompilerSettings({ - target: "es5", - declaration: false, - removeComments: true, - noResolve: false, - stripInternal: false, - outFile: processDiagnosticMessagesJs - }, /*useBuiltCompiler*/ false); - return gulp.src(processDiagnosticMessagesTs) + const diagsProject = tsc.createProject('./scripts/processDiagnosticMessages.tsconfig.json'); + return diagsProject.src() .pipe(newer(processDiagnosticMessagesJs)) - .pipe(sourcemaps.init()) - .pipe(tsc(settings)) - .pipe(sourcemaps.write(".")) - .pipe(gulp.dest(".")); + .pipe(diagsProject()) + .pipe(gulp.dest(scriptsDirectory)); }); // The generated diagnostics map; built for the compiler and for the "generate-diagnostics" task @@ -402,7 +407,8 @@ const generateLocalizedDiagnosticMessagesJs = path.join(scriptsDirectory, "gener const generateLocalizedDiagnosticMessagesTs = path.join(scriptsDirectory, "generateLocalizedDiagnosticMessages.ts"); gulp.task(generateLocalizedDiagnosticMessagesJs, /*help*/ false, [], () => { - const settings: tsc.Settings = getCompilerSettings({ + /** @type {tsc.Settings} */ + const settings = getCompilerSettings({ target: "es5", declaration: false, removeComments: true, @@ -433,8 +439,12 @@ const nodePackageFile = path.join(builtLocalDirectory, "typescript.js"); const nodeDefinitionsFile = path.join(builtLocalDirectory, "typescript.d.ts"); const nodeStandaloneDefinitionsFile = path.join(builtLocalDirectory, "typescript_standalone.d.ts"); -let copyrightContent: string; -function prependCopyright(outputCopyright: boolean = !useDebugMode) { +/** @type {string} */ +let copyrightContent; +/** + * @param {boolean} outputCopyright + */ +function prependCopyright(outputCopyright = !useDebugMode) { return insert.prepend(outputCopyright ? (copyrightContent || (copyrightContent = fs.readFileSync(copyright).toString())) : ""); } @@ -526,9 +536,10 @@ const tsserverLibraryDefinitionFile = path.join(builtLocalDirectory, "tsserverli gulp.task(tsserverLibraryFile, /*help*/ false, [servicesFile, typesMapJson], (done) => { const serverLibraryProject = tsc.createProject("src/server/tsconfig.library.json", getCompilerSettings({ removeComments: false }, /*useBuiltCompiler*/ true)); - const {js, dts}: { js: NodeJS.ReadableStream, dts: NodeJS.ReadableStream } = serverLibraryProject.src() + /** @type {{ js: NodeJS.ReadableStream, dts: NodeJS.ReadableStream }} */ + const {js, dts} = serverLibraryProject.src() .pipe(sourcemaps.init()) - .pipe(newer({ dest: tsserverLibraryFile, extra: ["src/compiler/**/*.ts", "src/services/**/*.ts"] })) + .pipe(newer(/** @type {*} */({ dest: tsserverLibraryFile, extra: ["src/compiler/**/*.ts", "src/services/**/*.ts"] }))) .pipe(serverLibraryProject()); return merge2([ @@ -563,7 +574,8 @@ const specWord = path.join(docDirectory, "TypeScript Language Specification.docx const specMd = path.join(docDirectory, "spec.md"); gulp.task(word2mdJs, /*help*/ false, [], () => { - const settings: tsc.Settings = getCompilerSettings({ + /** @type {tsc.Settings} */ + const settings = getCompilerSettings({ outFile: word2mdJs }, /*useBuiltCompiler*/ false); return gulp.src(word2mdTs) @@ -642,7 +654,8 @@ function deleteTemporaryProjectOutput() { return del(path.join(localBaseline, "projectOutput/")); } -let savedNodeEnv: string; +/** @type {string} */ +let savedNodeEnv; function setNodeEnvToDevelopment() { savedNodeEnv = process.env.NODE_ENV; process.env.NODE_ENV = "development"; @@ -652,7 +665,12 @@ function restoreSavedNodeEnv() { process.env.NODE_ENV = savedNodeEnv; } -function runConsoleTests(defaultReporter: string, runInParallel: boolean, done: (e?: any) => void) { +/** + * @param {string} defaultReporter + * @param {boolean} runInParallel + * @param {(e?: any) => void} done + */ +function runConsoleTests(defaultReporter, runInParallel, done) { const lintFlag = cmdLineOptions.lint; cleanTestDirs((err) => { if (err) { console.error(err); failWithStatus(err, 1); } @@ -727,7 +745,11 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done: } }); - function failWithStatus(err?: any, status?: number) { + /** + * @param {any=} err + * @param {number=} status + */ + function failWithStatus(err, status) { if (err || status) { process.exit(typeof status === "number" ? status : 2); } @@ -743,7 +765,11 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done: } } - function finish(error?: any, errorStatus?: number) { + /** + * @param {any=} error + * @param {number=} errorStatus + */ + function finish(error, errorStatus) { restoreSavedNodeEnv(); deleteTestConfig().then(deleteTemporaryProjectOutput).then(() => { if (error !== undefined || errorStatus !== undefined) { @@ -773,7 +799,8 @@ gulp.task("runtests", const nodeServerOutFile = "tests/webTestServer.js"; const nodeServerInFile = "tests/webTestServer.ts"; gulp.task(nodeServerOutFile, /*help*/ false, [servicesFile], () => { - const settings: tsc.Settings = getCompilerSettings({ module: "commonjs" }, /*useBuiltCompiler*/ true); + /** @type {tsc.Settings} */ + const settings = getCompilerSettings({ module: "commonjs" }, /*useBuiltCompiler*/ true); return gulp.src(nodeServerInFile) .pipe(newer(nodeServerOutFile)) .pipe(sourcemaps.init()) @@ -782,16 +809,18 @@ gulp.task(nodeServerOutFile, /*help*/ false, [servicesFile], () => { .pipe(gulp.dest(path.dirname(nodeServerOutFile))); }); -import convertMap = require("convert-source-map"); -import sorcery = require("sorcery"); -import Vinyl = require("vinyl"); +const convertMap = require("convert-source-map"); +const sorcery = require("sorcery"); +const Vinyl = require("vinyl"); const bundlePath = path.resolve("built/local/bundle.js"); gulp.task("browserify", "Runs browserify on run.js to produce a file suitable for running tests in the browser", [servicesFile], (done) => { const testProject = tsc.createProject("src/harness/tsconfig.json", getCompilerSettings({ outFile: bundlePath, inlineSourceMap: true }, /*useBuiltCompiler*/ true)); - let originalMap: any; - let prebundledContent: string; + /** @type {*} */ + let originalMap; + /** @type {string} */ + let prebundledContent; browserify(testProject.src() .pipe(newer(bundlePath)) .pipe(sourcemaps.init()) @@ -855,8 +884,10 @@ gulp.task("browserify", "Runs browserify on run.js to produce a file suitable fo }); }); - -function cleanTestDirs(done: (e?: any) => void) { +/** + * @param {(e?: any) => void} done + */ +function cleanTestDirs(done) { // Clean the local baselines & Rwc baselines directories del([ localBaseline, @@ -872,8 +903,17 @@ function cleanTestDirs(done: (e?: any) => void) { }); } -// used to pass data from jake command line directly to run.js -function writeTestConfigFile(tests: string, runners: string, light: boolean, taskConfigsFolder?: string, workerCount?: number, stackTraceLimit?: string, timeout?: number) { +/** + * used to pass data from jake command line directly to run.js + * @param {string} tests + * @param {string} runners + * @param {boolean} light + * @param {string=} taskConfigsFolder + * @param {number=} workerCount + * @param {string=} stackTraceLimit + * @param {number=} timeout + */ +function writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, timeout) { const testConfigContents = JSON.stringify({ test: tests ? [tests] : undefined, runner: runners ? runners.split(",") : undefined, @@ -974,7 +1014,7 @@ gulp.task("baseline-accept-test262", "Makes the most recent test262 test results const webhostPath = "tests/webhost/webtsc.ts"; const webhostJsPath = "tests/webhost/webtsc.js"; gulp.task(webhostJsPath, /*help*/ false, [servicesFile], () => { - const settings: tsc.Settings = getCompilerSettings({ + const settings = getCompilerSettings({ outFile: webhostJsPath }, /*useBuiltCompiler*/ true); return gulp.src(webhostPath) @@ -994,7 +1034,7 @@ gulp.task("webhost", "Builds the tsc web host", [webhostJsPath], () => { const perftscPath = "tests/perftsc.ts"; const perftscJsPath = "built/local/perftsc.js"; gulp.task(perftscJsPath, /*help*/ false, [servicesFile], () => { - const settings: tsc.Settings = getCompilerSettings({ + const settings = getCompilerSettings({ outFile: perftscJsPath }, /*useBuiltCompiler*/ true); return gulp.src(perftscPath) @@ -1025,7 +1065,7 @@ gulp.task(loggedIOJsPath, /*help*/ false, [], (done) => { const instrumenterPath = path.join(harnessDirectory, "instrumenter.ts"); const instrumenterJsPath = path.join(builtLocalDirectory, "instrumenter.js"); gulp.task(instrumenterJsPath, /*help*/ false, [servicesFile], () => { - const settings: tsc.Settings = getCompilerSettings({ + const settings = getCompilerSettings({ module: "commonjs", target: "es5", lib: [ @@ -1052,7 +1092,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 = getCompilerSettings({ module: "commonjs", lib: ["es6"] }, /*useBuiltCompiler*/ false); const dest = path.join(builtLocalDirectory, "tslint"); return gulp.src("scripts/tslint/**/*.ts") .pipe(newer({ @@ -1065,51 +1105,6 @@ gulp.task("build-rules", "Compiles tslint rules to js", () => { .pipe(gulp.dest(dest)); }); -const lintTargets = [ - "Gulpfile.ts", - "src/compiler/**/*.ts", - "src/harness/**/*.ts", - "!src/harness/unittests/services/formatting/**/*.ts", - "src/server/**/*.ts", - "scripts/tslint/**/*.ts", - "src/services/**/*.ts", - "tests/*.ts", "tests/webhost/*.ts" // Note: does *not* descend recursively -]; - -function sendNextFile(files: {path: string}[], child: cp.ChildProcess, callback: (failures: number) => void, failures: number) { - const file = files.pop(); - if (file) { - console.log(`Linting '${file.path}'.`); - child.send({ kind: "file", name: file.path }); - } - else { - child.send({ kind: "close" }); - callback(failures); - } -} - -function spawnLintWorker(files: {path: string}[], callback: (failures: number) => void) { - const child = cp.fork("./scripts/parallel-lint"); - let failures = 0; - child.on("message", data => { - switch (data.kind) { - case "result": - if (data.failures > 0) { - failures += data.failures; - console.log(data.output); - } - sendNextFile(files, child, callback, failures); - break; - case "error": - console.error(data.error); - failures++; - sendNextFile(files, child, callback, failures); - break; - } - }); - sendNextFile(files, child, callback, failures); -} - gulp.task("lint", "Runs tslint on the compiler sources. Optional arguments are: --f[iles]=regex", ["build-rules"], () => { if (fold.isTravis()) console.log(fold.start("lint")); for (const project of ["scripts/tslint/tsconfig.json", "src/tsconfig-base.json"]) { diff --git a/Jakefile.js b/Jakefile.js index bda270b0b4c..3eb8736445b 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -491,7 +491,7 @@ compileFile(/*outfile*/configurePrereleaseJs, /*prereqs*/[configurePrereleaseTs], /*prefixes*/[], /*useBuiltCompiler*/ false, - { noOutFile: false, generateDeclarations: false, keepComments: false, noResolve: false, stripInternal: false }); + { noOutFile: true, generateDeclarations: false, keepComments: false, noResolve: false, stripInternal: false }); task("setDebugMode", function () { useDebugMode = true; diff --git a/package.json b/package.json index 5837f72317f..71b5ed71029 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,6 @@ "source-map-support": "latest", "through2": "latest", "travis-fold": "latest", - "ts-node": "latest", "tslint": "latest", "vinyl": "latest", "chalk": "latest", diff --git a/scripts/configurePrerelease.ts b/scripts/configurePrerelease.ts index d17ddb963b1..da1984c13e0 100644 --- a/scripts/configurePrerelease.ts +++ b/scripts/configurePrerelease.ts @@ -1,4 +1,9 @@ -/// +/// +import { normalize } from "path"; +import assert = require("assert"); +import { readFileSync, writeFileSync } from "fs"; +const args = process.argv.slice(2); + /** * A minimal description for a parsed package.json object. @@ -10,28 +15,27 @@ interface PackageJson { } function main(): void { - const sys = ts.sys; - if (sys.args.length < 3) { - sys.write("Usage:" + sys.newLine) - sys.write("\tnode configureNightly.js " + sys.newLine); + if (args.length < 3) { + console.log("Usage:"); + console.log("\tnode configureNightly.js "); return; } - const tag = sys.args[0]; + const tag = args[0]; if (tag !== "dev" && tag !== "insiders") { throw new Error(`Unexpected tag name '${tag}'.`); } // Acquire the version from the package.json file and modify it appropriately. - const packageJsonFilePath = ts.normalizePath(sys.args[1]); - const packageJsonValue: PackageJson = JSON.parse(sys.readFile(packageJsonFilePath)); + const packageJsonFilePath = normalize(args[1]); + const packageJsonValue: PackageJson = JSON.parse(readFileSync(packageJsonFilePath).toString()); const { majorMinor, patch } = parsePackageJsonVersion(packageJsonValue.version); const prereleasePatch = getPrereleasePatch(tag, patch); // Acquire and modify the source file that exposes the version string. - const tsFilePath = ts.normalizePath(sys.args[2]); - const tsFileContents = ts.sys.readFile(tsFilePath); + const tsFilePath = normalize(args[2]); + const tsFileContents = readFileSync(tsFilePath).toString(); const modifiedTsFileContents = updateTsFile(tsFilePath, tsFileContents, majorMinor, patch, prereleasePatch); // Ensure we are actually changing something - the user probably wants to know that the update failed. @@ -44,20 +48,20 @@ function main(): void { // Finally write the changes to disk. // Modify the package.json structure packageJsonValue.version = `${majorMinor}.${prereleasePatch}`; - sys.writeFile(packageJsonFilePath, JSON.stringify(packageJsonValue, /*replacer:*/ undefined, /*space:*/ 4)) - sys.writeFile(tsFilePath, modifiedTsFileContents); + writeFileSync(packageJsonFilePath, JSON.stringify(packageJsonValue, /*replacer:*/ undefined, /*space:*/ 4)) + writeFileSync(tsFilePath, modifiedTsFileContents); } function updateTsFile(tsFilePath: string, tsFileContents: string, majorMinor: string, patch: string, nightlyPatch: string): string { const majorMinorRgx = /export const versionMajorMinor = "(\d+\.\d+)"/; const majorMinorMatch = majorMinorRgx.exec(tsFileContents); - ts.Debug.assert(majorMinorMatch !== null, "", () => `The file seems to no longer have a string matching '${majorMinorRgx}'.`); + assert(majorMinorMatch !== null, `The file seems to no longer have a string matching '${majorMinorRgx}'.`); const parsedMajorMinor = majorMinorMatch[1]; - ts.Debug.assert(parsedMajorMinor === majorMinor, "versionMajorMinor does not match.", () => `${tsFilePath}: '${parsedMajorMinor}'; package.json: '${majorMinor}'`); + assert(parsedMajorMinor === majorMinor, `versionMajorMinor does not match. ${tsFilePath}: '${parsedMajorMinor}'; package.json: '${majorMinor}'`); const versionRgx = /export const version = `\$\{versionMajorMinor\}\.(\d)(-dev)?`;/; const patchMatch = versionRgx.exec(tsFileContents); - ts.Debug.assert(patchMatch !== null, "The file seems to no longer have a string matching", () => versionRgx.toString()); + assert(patchMatch !== null, "The file seems to no longer have a string matching " + versionRgx.toString()); const parsedPatch = patchMatch[1]; if (parsedPatch !== patch) { throw new Error(`patch does not match. ${tsFilePath}: '${parsedPatch}; package.json: '${patch}'`); @@ -69,7 +73,7 @@ function updateTsFile(tsFilePath: string, tsFileContents: string, majorMinor: st function parsePackageJsonVersion(versionString: string): { majorMinor: string, patch: string } { const versionRgx = /(\d+\.\d+)\.(\d+)($|\-)/; const match = versionString.match(versionRgx); - ts.Debug.assert(match !== null, "package.json 'version' should match", () => versionRgx.toString()); + assert(match !== null, "package.json 'version' should match " + versionRgx.toString()); return { majorMinor: match[1], patch: match[2] }; } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d009a956c43..f497ba82e47 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -24465,7 +24465,10 @@ namespace ts { checkImportBinding(importClause.namedBindings); } else { - forEach(importClause.namedBindings.elements, checkImportBinding); + const moduleExisted = resolveExternalModuleName(node, node.moduleSpecifier); + if (moduleExisted) { + forEach(importClause.namedBindings.elements, checkImportBinding); + } } } } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 0bef14e9dda..27e906b8a5a 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2994,18 +2994,19 @@ namespace ts { } /** Remove the *first* occurrence of `item` from the array. */ - export function unorderedRemoveItem(array: T[], item: T): void { - unorderedRemoveFirstItemWhere(array, element => element === item); + export function unorderedRemoveItem(array: T[], item: T) { + return unorderedRemoveFirstItemWhere(array, element => element === item); } /** Remove the *first* element satisfying `predicate`. */ - function unorderedRemoveFirstItemWhere(array: T[], predicate: (element: T) => boolean): void { + function unorderedRemoveFirstItemWhere(array: T[], predicate: (element: T) => boolean) { for (let i = 0; i < array.length; i++) { if (predicate(array[i])) { unorderedRemoveItemAt(array, i); - break; + return true; } } + return false; } export type GetCanonicalFileName = (fileName: string) => string; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index c665744b1ea..235788258af 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2943,10 +2943,6 @@ "category": "Message", "code": 6040 }, - "Compilation complete. Watching for file changes.": { - "category": "Message", - "code": 6042 - }, "Generates corresponding '.map' file.": { "category": "Message", "code": 6043 @@ -3522,11 +3518,11 @@ "code": 6192, "reportsUnnecessary": true }, - "Found 1 error.": { + "Found 1 error. Watching for file changes.": { "category": "Message", "code": 6193 }, - "Found {0} errors.": { + "Found {0} errors. Watching for file changes.": { "category": "Message", "code": 6194 }, diff --git a/src/compiler/resolutionCache.ts b/src/compiler/resolutionCache.ts index c2b96649cf2..35e056546c0 100644 --- a/src/compiler/resolutionCache.ts +++ b/src/compiler/resolutionCache.ts @@ -10,6 +10,7 @@ namespace ts { invalidateResolutionOfFile(filePath: Path): void; removeResolutionsOfFile(filePath: Path): void; + setFilesWithInvalidatedNonRelativeUnresolvedImports(filesWithUnresolvedImports: Map>): void; createHasInvalidatedResolution(forceAllFilesAsInvalidated?: boolean): HasInvalidatedResolution; startCachingPerDirectoryResolution(): void; @@ -74,6 +75,7 @@ namespace ts { export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootDirForResolution: string, logChangesWhenResolvingModule: boolean): ResolutionCache { let filesWithChangedSetOfUnresolvedImports: Path[] | undefined; let filesWithInvalidatedResolutions: Map | undefined; + let filesWithInvalidatedNonRelativeUnresolvedImports: Map> | undefined; let allFilesHaveInvalidatedResolution = false; const getCurrentDirectory = memoize(() => resolutionHost.getCurrentDirectory()); @@ -122,6 +124,7 @@ namespace ts { resolveTypeReferenceDirectives, removeResolutionsOfFile, invalidateResolutionOfFile, + setFilesWithInvalidatedNonRelativeUnresolvedImports, createHasInvalidatedResolution, updateTypeRootsWatch, closeTypeRootsWatch, @@ -165,6 +168,16 @@ namespace ts { return collected; } + function isFileWithInvalidatedNonRelativeUnresolvedImports(path: Path) { + if (!filesWithInvalidatedNonRelativeUnresolvedImports) { + return false; + } + + // Invalidated if file has unresolved imports + const value = filesWithInvalidatedNonRelativeUnresolvedImports.get(path); + return value && !!value.length; + } + function createHasInvalidatedResolution(forceAllFilesAsInvalidated?: boolean): HasInvalidatedResolution { if (allFilesHaveInvalidatedResolution || forceAllFilesAsInvalidated) { // Any file asked would have invalidated resolution @@ -173,7 +186,8 @@ namespace ts { } const collected = filesWithInvalidatedResolutions; filesWithInvalidatedResolutions = undefined; - return path => collected && collected.has(path); + return path => (collected && collected.has(path)) || + isFileWithInvalidatedNonRelativeUnresolvedImports(path); } function clearPerDirectoryResolutions() { @@ -184,6 +198,7 @@ namespace ts { function finishCachingPerDirectoryResolution() { allFilesHaveInvalidatedResolution = false; + filesWithInvalidatedNonRelativeUnresolvedImports = undefined; directoryWatchesOfFailedLookups.forEach((watcher, path) => { if (watcher.refCount === 0) { directoryWatchesOfFailedLookups.delete(path); @@ -237,13 +252,15 @@ namespace ts { const resolvedModules: R[] = []; const compilerOptions = resolutionHost.getCompilationSettings(); - + const hasInvalidatedNonRelativeUnresolvedImport = logChanges && isFileWithInvalidatedNonRelativeUnresolvedImports(path); const seenNamesInFile = createMap(); for (const name of names) { let resolution = resolutionsInFile.get(name); // Resolution is valid if it is present and not invalidated if (!seenNamesInFile.has(name) && - allFilesHaveInvalidatedResolution || !resolution || resolution.isInvalidated) { + allFilesHaveInvalidatedResolution || !resolution || resolution.isInvalidated || + // If the name is unresolved import that was invalidated, recalculate + (hasInvalidatedNonRelativeUnresolvedImport && !isExternalModuleNameRelative(name) && !getResolutionWithResolvedFileName(resolution))) { const existingResolution = resolution; const resolutionInDirectory = perDirectoryResolution.get(name); if (resolutionInDirectory) { @@ -284,7 +301,7 @@ namespace ts { if (oldResolution === newResolution) { return true; } - if (!oldResolution || !newResolution || oldResolution.isInvalidated) { + if (!oldResolution || !newResolution) { return false; } const oldResult = getResolutionWithResolvedFileName(oldResolution); @@ -577,6 +594,11 @@ namespace ts { ); } + function setFilesWithInvalidatedNonRelativeUnresolvedImports(filesMap: Map>) { + Debug.assert(filesWithInvalidatedNonRelativeUnresolvedImports === filesMap || filesWithInvalidatedNonRelativeUnresolvedImports === undefined); + filesWithInvalidatedNonRelativeUnresolvedImports = filesMap; + } + function invalidateResolutionOfFailedLookupLocation(fileOrDirectoryPath: Path, isCreatingWatchedDirectory: boolean) { let isChangedFailedLookupLocation: (location: string) => boolean; if (isCreatingWatchedDirectory) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 5eea26f1c69..7fabd5d0265 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1892,7 +1892,7 @@ namespace ts { kind: SyntaxKind.DebuggerStatement; } - export interface MissingDeclaration extends DeclarationStatement, ClassElement, ObjectLiteralElement, TypeElement { + export interface MissingDeclaration extends DeclarationStatement { kind: SyntaxKind.MissingDeclaration; name?: Identifier; } @@ -3193,7 +3193,8 @@ namespace ts { export type AnyValidImportOrReExport = | (ImportDeclaration | ExportDeclaration) & { moduleSpecifier: StringLiteral } | ImportEqualsDeclaration & { moduleReference: ExternalModuleReference & { expression: StringLiteral } } - | RequireOrImportCall; + | RequireOrImportCall + | ImportTypeNode & { argument: LiteralType }; /* @internal */ export type RequireOrImportCall = CallExpression & { arguments: [StringLiteralLike] }; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index f975e27dca3..3fe255fb612 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1710,8 +1710,10 @@ namespace ts { return (node.parent as ExternalModuleReference).parent as AnyValidImportOrReExport; case SyntaxKind.CallExpression: return node.parent as AnyValidImportOrReExport; + case SyntaxKind.LiteralType: + return cast(node.parent.parent, isImportTypeNode) as ImportTypeNode & { argument: LiteralType }; default: - return Debug.fail(Debug.showSyntaxKind(node)); + return Debug.fail(Debug.showSyntaxKind(node.parent)); } } @@ -4926,6 +4928,10 @@ namespace ts { return node.kind === SyntaxKind.LiteralType; } + export function isImportTypeNode(node: Node): node is ImportTypeNode { + return node.kind === SyntaxKind.ImportType; + } + // Binding patterns export function isObjectBindingPattern(node: Node): node is ObjectBindingPattern { @@ -5606,8 +5612,7 @@ namespace ts { || kind === SyntaxKind.GetAccessor || kind === SyntaxKind.SetAccessor || kind === SyntaxKind.IndexSignature - || kind === SyntaxKind.SemicolonClassElement - || kind === SyntaxKind.MissingDeclaration; + || kind === SyntaxKind.SemicolonClassElement; } export function isClassLike(node: Node): node is ClassLikeDeclaration { @@ -5638,8 +5643,7 @@ namespace ts { || kind === SyntaxKind.CallSignature || kind === SyntaxKind.PropertySignature || kind === SyntaxKind.MethodSignature - || kind === SyntaxKind.IndexSignature - || kind === SyntaxKind.MissingDeclaration; + || kind === SyntaxKind.IndexSignature; } export function isClassOrTypeElement(node: Node): node is ClassElement | TypeElement { @@ -5653,8 +5657,7 @@ namespace ts { || kind === SyntaxKind.SpreadAssignment || kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.GetAccessor - || kind === SyntaxKind.SetAccessor - || kind === SyntaxKind.MissingDeclaration; + || kind === SyntaxKind.SetAccessor; } // Type diff --git a/src/compiler/watch.ts b/src/compiler/watch.ts index 7f3d078b790..37aa0118801 100644 --- a/src/compiler/watch.ts +++ b/src/compiler/watch.ts @@ -29,9 +29,8 @@ namespace ts { /** @internal */ export const nonClearingMessageCodes: number[] = [ - Diagnostics.Compilation_complete_Watching_for_file_changes.code, - Diagnostics.Found_1_error.code, - Diagnostics.Found_0_errors.code + Diagnostics.Found_1_error_Watching_for_file_changes.code, + Diagnostics.Found_0_errors_Watching_for_file_changes.code ]; function clearScreenIfNotWatchingForFileChanges(system: System, diagnostic: Diagnostic, options: CompilerOptions) { @@ -231,10 +230,10 @@ namespace ts { const reportSummary = (errorCount: number) => { if (errorCount === 1) { - onWatchStatusChange(createCompilerDiagnostic(Diagnostics.Found_1_error, errorCount), newLine, compilerOptions); + onWatchStatusChange(createCompilerDiagnostic(Diagnostics.Found_1_error_Watching_for_file_changes, errorCount), newLine, compilerOptions); } else { - onWatchStatusChange(createCompilerDiagnostic(Diagnostics.Found_0_errors, errorCount, errorCount), newLine, compilerOptions); + onWatchStatusChange(createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errorCount, errorCount), newLine, compilerOptions); } }; @@ -644,7 +643,7 @@ namespace ts { if (host.afterProgramCreate) { host.afterProgramCreate(builderProgram); } - reportWatchDiagnostic(Diagnostics.Compilation_complete_Watching_for_file_changes); + return builderProgram; } diff --git a/src/harness/externalCompileRunner.ts b/src/harness/externalCompileRunner.ts index 1f945cfcc9c..3d07c69af85 100644 --- a/src/harness/externalCompileRunner.ts +++ b/src/harness/externalCompileRunner.ts @@ -66,7 +66,7 @@ abstract class ExternalCompileRunnerBase extends RunnerBase { if (fs.existsSync(path.join(cwd, "node_modules"))) { require("del").sync(path.join(cwd, "node_modules"), { force: true }); } - const install = cp.spawnSync(`npm`, ["i"], { cwd, timeout: timeout / 2, shell: true, stdio }); // NPM shouldn't take the entire timeout - if it takes a long time, it should be terminated and we should log the failure + const install = cp.spawnSync(`npm`, ["i", "--ignore-scripts"], { cwd, timeout: timeout / 2, shell: true, stdio }); // NPM shouldn't take the entire timeout - if it takes a long time, it should be terminated and we should log the failure if (install.status !== 0) throw new Error(`NPM Install for ${directoryName} failed: ${install.stderr.toString()}`); } const args = [path.join(__dirname, "tsc.js")]; diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index b479b5596a8..75915c915ed 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -2103,14 +2103,11 @@ Actual: ${stringify(fullActual)}`); this.raiseError("verifyRangesInImplementationList failed - expected to find at least one implementation location but got 0"); } - for (let i = 0; i < implementations.length; i++) { - for (let j = 0; j < implementations.length; j++) { - if (i !== j && implementationsAreEqual(implementations[i], implementations[j])) { - const { textSpan, fileName } = implementations[i]; - const end = textSpan.start + textSpan.length; - this.raiseError(`Duplicate implementations returned for range (${textSpan.start}, ${end}) in ${fileName}`); - } - } + const duplicate = findDuplicatedElement(implementations, implementationsAreEqual); + if (duplicate) { + const { textSpan, fileName } = duplicate; + const end = textSpan.start + textSpan.length; + this.raiseError(`Duplicate implementations returned for range (${textSpan.start}, ${end}) in ${fileName}`); } const ranges = this.getRanges(); @@ -2910,6 +2907,7 @@ Actual: ${stringify(fullActual)}`); } private verifyDocumentHighlights(expectedRanges: Range[], fileNames: ReadonlyArray = [this.activeFile.fileName]) { + fileNames = ts.map(fileNames, ts.normalizePath); const documentHighlights = this.getDocumentHighlightsAtCurrentPosition(fileNames) || []; for (const dh of documentHighlights) { @@ -2919,7 +2917,7 @@ Actual: ${stringify(fullActual)}`); } for (const fileName of fileNames) { - const expectedRangesInFile = expectedRanges.filter(r => r.fileName === fileName); + const expectedRangesInFile = expectedRanges.filter(r => ts.normalizePath(r.fileName) === fileName); const highlights = ts.find(documentHighlights, dh => dh.fileName === fileName); const spansInFile = highlights ? highlights.highlightSpans.sort((s1, s2) => s1.textSpan.start - s2.textSpan.start) : []; @@ -3219,14 +3217,14 @@ Actual: ${stringify(fullActual)}`); } } else if (ts.isString(indexOrName)) { - let name = indexOrName; + let name = ts.normalizePath(indexOrName); // names are stored in the compiler with this relative path, this allows people to use goTo.file on just the fileName name = name.indexOf("/") === -1 ? (this.basePath + "/" + name) : name; const availableNames: string[] = []; const result = ts.forEach(this.testData.files, file => { - const fn = file.fileName; + const fn = ts.normalizePath(file.fileName); if (fn) { if (fn === name) { return file; @@ -3755,6 +3753,16 @@ ${code} function stripWhitespace(s: string): string { return s.replace(/\s/g, ""); } + + function findDuplicatedElement(a: ReadonlyArray, equal: (a: T, b: T) => boolean): T { + for (let i = 0; i < a.length; i++) { + for (let j = i + 1; j < a.length; j++) { + if (equal(a[i], a[j])) { + return a[i]; + } + } + } + } } namespace FourSlashInterface { diff --git a/src/harness/tsconfig.json b/src/harness/tsconfig.json index 0d56447b28a..3ad653403cf 100644 --- a/src/harness/tsconfig.json +++ b/src/harness/tsconfig.json @@ -112,10 +112,8 @@ "../services/codefixes/fixInvalidImportSyntax.ts", "../services/codefixes/fixStrictClassInitialization.ts", "../services/codefixes/useDefaultImport.ts", - "../services/codefixes/fixes.ts", "../services/refactors/extractSymbol.ts", "../services/refactors/generateGetAccessorAndSetAccessor.ts", - "../services/refactors/refactors.ts", "../services/sourcemaps.ts", "../services/services.ts", "../services/breakpoints.ts", diff --git a/src/harness/unittests/tscWatchMode.ts b/src/harness/unittests/tscWatchMode.ts index 99bad3e3091..c8faba855dc 100644 --- a/src/harness/unittests/tscWatchMode.ts +++ b/src/harness/unittests/tscWatchMode.ts @@ -130,8 +130,8 @@ namespace ts.tscWatch { function createErrorsFoundCompilerDiagnostic(errors: ReadonlyArray) { return errors.length === 1 - ? createCompilerDiagnostic(Diagnostics.Found_1_error) - : createCompilerDiagnostic(Diagnostics.Found_0_errors, errors.length); + ? createCompilerDiagnostic(Diagnostics.Found_1_error_Watching_for_file_changes) + : createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errors.length); } function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray, disableConsoleClears?: boolean, logsBeforeErrors?: string[]) { @@ -142,8 +142,7 @@ namespace ts.tscWatch { logsBeforeErrors, errors, disableConsoleClears, - createErrorsFoundCompilerDiagnostic(errors), - createCompilerDiagnostic(Diagnostics.Compilation_complete_Watching_for_file_changes)); + createErrorsFoundCompilerDiagnostic(errors)); } function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) { @@ -154,8 +153,7 @@ namespace ts.tscWatch { logsBeforeErrors, errors, disableConsoleClears, - createErrorsFoundCompilerDiagnostic(errors), - createCompilerDiagnostic(Diagnostics.Compilation_complete_Watching_for_file_changes)); + createErrorsFoundCompilerDiagnostic(errors)); } function checkOutputErrorsIncrementalWithExit(host: WatchedSystem, errors: ReadonlyArray, expectedExitCode: ExitStatus, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) { diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index b167ed21b94..10912b4fb87 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -7294,7 +7294,6 @@ namespace ts.projectSystem { const host = createServerHost(files); const session = createSession(host); const projectService = session.getProjectService(); - debugger; session.executeCommandSeq({ command: protocol.CommandTypes.Open, arguments: { diff --git a/src/harness/unittests/typingsInstaller.ts b/src/harness/unittests/typingsInstaller.ts index 1a19c98f477..b6d5a20ef9a 100644 --- a/src/harness/unittests/typingsInstaller.ts +++ b/src/harness/unittests/typingsInstaller.ts @@ -999,14 +999,14 @@ namespace ts.projectSystem { proj.updateGraph(); assert.deepEqual( - proj.getCachedUnresolvedImportsPerFile_TestOnly().get(f1.path), + proj.cachedUnresolvedImportsPerFile.get(f1.path), ["foo", "foo", "foo", "@bar/router", "@bar/common", "@bar/common"] ); installer.installAll(/*expectedCount*/ 1); }); - it("should recompute resolutions after typings are installed", () => { + it("cached unresolved typings are not recomputed if program structure did not change", () => { const host = createServerHost([]); const session = createSession(host); const f = { @@ -1029,7 +1029,7 @@ namespace ts.projectSystem { const projectService = session.getProjectService(); checkNumberOfProjects(projectService, { inferredProjects: 1 }); const proj = projectService.inferredProjects[0]; - const version1 = proj.getCachedUnresolvedImportsPerFile_TestOnly().getVersion(); + const version1 = proj.lastCachedUnresolvedImportsList; // make a change that should not affect the structure of the program const changeRequest: server.protocol.ChangeRequest = { @@ -1047,8 +1047,8 @@ namespace ts.projectSystem { }; session.executeCommand(changeRequest); host.checkTimeoutQueueLengthAndRun(2); // This enqueues the updategraph and refresh inferred projects - const version2 = proj.getCachedUnresolvedImportsPerFile_TestOnly().getVersion(); - assert.notEqual(version1, version2, "set of unresolved imports should change"); + const version2 = proj.lastCachedUnresolvedImportsList; + assert.strictEqual(version1, version2, "set of unresolved imports should change"); }); it("expired cache entry (inferred project, should install typings)", () => { @@ -1621,4 +1621,75 @@ namespace ts.projectSystem { assert.deepEqual(commands, expectedCommands, "commands"); }); }); + + describe("recomputing resolutions of unresolved imports", () => { + const globalTypingsCacheLocation = "/tmp"; + const appPath = "/a/b/app.js" as Path; + const foooPath = "/a/b/node_modules/fooo/index.d.ts"; + function verifyResolvedModuleOfFooo(project: server.Project) { + const foooResolution = project.getLanguageService().getProgram().getSourceFileByPath(appPath).resolvedModules.get("fooo"); + assert.equal(foooResolution.resolvedFileName, foooPath); + return foooResolution; + } + + function verifyUnresolvedImportResolutions(appContents: string, typingNames: string[], typingFiles: FileOrFolder[]) { + const app: FileOrFolder = { + path: appPath, + content: `${appContents}import * as x from "fooo";` + }; + const fooo: FileOrFolder = { + path: foooPath, + content: `export var x: string;` + }; + const host = createServerHost([app, fooo]); + const installer = new (class extends Installer { + constructor() { + super(host, { globalTypingsCacheLocation, typesRegistry: createTypesRegistry("foo") }); + } + installWorker(_requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction) { + executeCommand(this, host, typingNames, typingFiles, cb); + } + })(); + const projectService = createProjectService(host, { typingsInstaller: installer }); + projectService.openClientFile(app.path); + projectService.checkNumberOfProjects({ inferredProjects: 1 }); + + const proj = projectService.inferredProjects[0]; + checkProjectActualFiles(proj, [app.path, fooo.path]); + const foooResolution1 = verifyResolvedModuleOfFooo(proj); + + installer.installAll(/*expectedCount*/ 1); + host.checkTimeoutQueueLengthAndRun(2); + checkProjectActualFiles(proj, typingFiles.map(f => f.path).concat(app.path, fooo.path)); + const foooResolution2 = verifyResolvedModuleOfFooo(proj); + assert.strictEqual(foooResolution1, foooResolution2); + } + + it("correctly invalidate the resolutions with typing names", () => { + verifyUnresolvedImportResolutions('import * as a from "foo";', ["foo"], [{ + path: `${globalTypingsCacheLocation}/node_modules/foo/index.d.ts`, + content: "export function a(): void;" + }]); + }); + + it("correctly invalidate the resolutions with typing names that are trimmed", () => { + const fooAA: FileOrFolder = { + path: `${globalTypingsCacheLocation}/node_modules/foo/a/a.d.ts`, + content: "export function a (): void;" + }; + const fooAB: FileOrFolder = { + path: `${globalTypingsCacheLocation}/node_modules/foo/a/b.d.ts`, + content: "export function b (): void;" + }; + const fooAC: FileOrFolder = { + path: `${globalTypingsCacheLocation}/node_modules/foo/a/c.d.ts`, + content: "export function c (): void;" + }; + verifyUnresolvedImportResolutions(` + import * as a from "foo/a/a"; + import * as b from "foo/a/b"; + import * as c from "foo/a/c"; + `, ["foo"], [fooAA, fooAB, fooAC]); + }); + }); } diff --git a/src/harness/virtualFileSystem.ts b/src/harness/virtualFileSystem.ts index 16267a092fc..698f99616ca 100644 --- a/src/harness/virtualFileSystem.ts +++ b/src/harness/virtualFileSystem.ts @@ -125,7 +125,7 @@ namespace Utils { addFile(path: string, content?: Harness.LanguageService.ScriptInfo) { const absolutePath = ts.normalizePath(ts.getNormalizedAbsolutePath(path, this.currentDirectory)); - const fileName = ts.getBaseFileName(path); + const fileName = ts.getBaseFileName(absolutePath); const directoryPath = ts.getDirectoryPath(absolutePath); const directory = this.addDirectory(directoryPath); return directory ? directory.addFile(fileName, content) : undefined; diff --git a/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl index db17f37967b..0ef1aeed0cc 100644 --- a/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -3906,6 +3906,15 @@ + + + + + + + + + @@ -6018,6 +6027,9 @@ + + + diff --git a/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl index 58326d7ccb6..b2ffdf585e0 100644 --- a/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -3894,6 +3894,15 @@ + + + + + + + + + @@ -6003,6 +6012,9 @@ + + + diff --git a/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl index 342918edc19..259d4b3b90e 100644 --- a/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -3906,6 +3906,15 @@ + + + + + + + + + @@ -6018,6 +6027,9 @@ + + + diff --git a/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl index 52881bd0f4e..d3663b384db 100644 --- a/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -3906,6 +3906,15 @@ + + + + + + + + + @@ -6018,6 +6027,9 @@ + + + diff --git a/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl index a0f54926f3f..43d2f167e96 100644 --- a/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -3897,6 +3897,15 @@ + + + + + + + + + @@ -6009,6 +6018,9 @@ + + + diff --git a/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl index 4b42ff8b2bf..0e70ff04cca 100644 --- a/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -3897,6 +3897,15 @@ + + + + + + + + + @@ -6009,6 +6018,9 @@ + + + diff --git a/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl index 473da1a4a01..3252fe24f15 100644 --- a/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -3887,6 +3887,15 @@ + + + + + + + + + @@ -5996,6 +6005,9 @@ + + + diff --git a/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl index b341aa7ea84..07d26979bf8 100644 --- a/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -3896,6 +3896,15 @@ + + + + + + + + + @@ -6008,6 +6017,9 @@ + + + diff --git a/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl index 1ac1d8a83e6..72116417c1b 100644 --- a/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -3890,6 +3890,15 @@ + + + + + + + + + @@ -6002,6 +6011,9 @@ + + + diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index c7903289a76..006c161ce56 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -312,7 +312,8 @@ namespace ts.server { export class ProjectService { - public readonly typingsCache: TypingsCache; + /*@internal*/ + readonly typingsCache: TypingsCache; private readonly documentRegistry: DocumentRegistry; @@ -523,13 +524,13 @@ namespace ts.server { } switch (response.kind) { case ActionSet: - project.resolutionCache.clear(); - this.typingsCache.updateTypingsForProject(response.projectName, response.compilerOptions, response.typeAcquisition, response.unresolvedImports, response.typings); + // Update the typing files and update the project + project.updateTypingFiles(this.typingsCache.updateTypingsForProject(response.projectName, response.compilerOptions, response.typeAcquisition, response.unresolvedImports, response.typings)); break; case ActionInvalidate: - project.resolutionCache.clear(); - this.typingsCache.deleteTypingsForProject(response.projectName); - break; + // Do not clear resolution cache, there was changes detected in typings, so enque typing request and let it get us correct results + this.typingsCache.enqueueInstallTypingsForProject(project, project.lastCachedUnresolvedImportsList, /*forceRefresh*/ true); + return; } this.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(project); } diff --git a/src/server/project.ts b/src/server/project.ts index 8e9ff1dfc9c..b79d9245898 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -55,34 +55,6 @@ namespace ts.server { projectErrors: ReadonlyArray; } - export class UnresolvedImportsMap { - readonly perFileMap = createMap>(); - private version = 0; - - public clear() { - this.perFileMap.clear(); - this.version = 0; - } - - public getVersion() { - return this.version; - } - - public remove(path: Path) { - this.perFileMap.delete(path); - this.version++; - } - - public get(path: Path) { - return this.perFileMap.get(path); - } - - public set(path: Path, value: ReadonlyArray) { - this.perFileMap.set(path, value); - this.version++; - } - } - export interface PluginCreateInfo { project: Project; languageService: LanguageService; @@ -116,8 +88,18 @@ namespace ts.server { private missingFilesMap: Map; private plugins: PluginModule[] = []; - private cachedUnresolvedImportsPerFile = new UnresolvedImportsMap(); - private lastCachedUnresolvedImportsList: SortedReadonlyArray; + /*@internal*/ + /** + * This is map from files to unresolved imports in it + * Maop does not contain entries for files that do not have unresolved imports + * This helps in containing the set of files to invalidate + */ + cachedUnresolvedImportsPerFile = createMap>(); + + /*@internal*/ + lastCachedUnresolvedImportsList: SortedReadonlyArray; + /*@internal*/ + private hasAddedorRemovedFiles = false; private lastFileExceededProgramSize: string | undefined; @@ -149,10 +131,10 @@ namespace ts.server { */ private lastReportedVersion = 0; /** - * Current project structure version. + * Current project's program version. (incremented everytime new program is created that is not complete reuse from the old one) * This property is changed in 'updateGraph' based on the set of files in program */ - private projectStructureVersion = 0; + private projectProgramVersion = 0; /** * Current version of the project state. It is changed when: * - new root file was added/removed @@ -167,7 +149,8 @@ namespace ts.server { /*@internal*/ hasChangedAutomaticTypeDirectiveNames = false; - private typingFiles: SortedReadonlyArray; + /*@internal*/ + typingFiles: SortedReadonlyArray = emptyArray; private readonly cancellationToken: ThrottledCancellationToken; @@ -181,10 +164,6 @@ namespace ts.server { return hasOneOrMoreJsAndNoTsFiles(this); } - public getCachedUnresolvedImportsPerFile_TestOnly() { - return this.cachedUnresolvedImportsPerFile; - } - public static resolveModule(moduleName: string, initialDir: string, host: ServerHost, log: (message: string) => void): {} { const resolvedPath = normalizeSlashes(host.resolvePath(combinePaths(initialDir, "node_modules"))); log(`Loading ${moduleName} from ${initialDir} (resolved to ${resolvedPath})`); @@ -742,7 +721,7 @@ namespace ts.server { else { this.resolutionCache.invalidateResolutionOfFile(info.path); } - this.cachedUnresolvedImportsPerFile.remove(info.path); + this.cachedUnresolvedImportsPerFile.delete(info.path); if (detachFromProject) { info.detachFromProject(this); @@ -763,16 +742,13 @@ namespace ts.server { } /* @internal */ - private extractUnresolvedImportsFromSourceFile(file: SourceFile, result: Push, ambientModules: string[]) { + private extractUnresolvedImportsFromSourceFile(file: SourceFile, ambientModules: string[]): ReadonlyArray { const cached = this.cachedUnresolvedImportsPerFile.get(file.path); if (cached) { - // found cached result - use it and return - for (const f of cached) { - result.push(f); - } - return; + // found cached result, return + return cached; } - let unresolvedImports: string[]; + let unresolvedImports: string[] | undefined; if (file.resolvedModules) { file.resolvedModules.forEach((resolvedModule, name) => { // pick unresolved non-relative names @@ -788,17 +764,23 @@ namespace ts.server { trimmed = trimmed.substr(0, i); } (unresolvedImports || (unresolvedImports = [])).push(trimmed); - result.push(trimmed); } }); } + this.cachedUnresolvedImportsPerFile.set(file.path, unresolvedImports || emptyArray); + return unresolvedImports || emptyArray; function isAmbientlyDeclaredModule(name: string) { return ambientModules.some(m => m === name); } } + /* @internal */ + onFileAddedOrRemoved() { + this.hasAddedorRemovedFiles = true; + } + /** * Updates set of files that contribute to this project * @returns: true if set of files in the project stays the same and false - otherwise. @@ -806,13 +788,15 @@ namespace ts.server { updateGraph(): boolean { this.resolutionCache.startRecordingFilesWithChangedResolutions(); - let hasChanges = this.updateGraphWorker(); + const hasNewProgram = this.updateGraphWorker(); + const hasAddedorRemovedFiles = this.hasAddedorRemovedFiles; + this.hasAddedorRemovedFiles = false; const changedFiles: ReadonlyArray = this.resolutionCache.finishRecordingFilesWithChangedResolutions() || emptyArray; for (const file of changedFiles) { // delete cached information for changed files - this.cachedUnresolvedImportsPerFile.remove(file); + this.cachedUnresolvedImportsPerFile.delete(file); } // update builder only if language service is enabled @@ -824,30 +808,35 @@ namespace ts.server { // 3. new files were added/removed, but compilation settings stays the same - collect unresolved imports for all new/modified files // (can reuse cached imports for files that were not changed) // 4. compilation settings were changed in the way that might affect module resolution - drop all caches and collect all data from the scratch - if (hasChanges || changedFiles.length) { - const result: string[] = []; + if (hasNewProgram || changedFiles.length) { + let result: string[] | undefined; const ambientModules = this.program.getTypeChecker().getAmbientModules().map(mod => stripQuotes(mod.getName())); for (const sourceFile of this.program.getSourceFiles()) { - this.extractUnresolvedImportsFromSourceFile(sourceFile, result, ambientModules); + const unResolved = this.extractUnresolvedImportsFromSourceFile(sourceFile, ambientModules); + if (unResolved !== emptyArray) { + (result || (result = [])).push(...unResolved); + } } - this.lastCachedUnresolvedImportsList = toDeduplicatedSortedArray(result); + this.lastCachedUnresolvedImportsList = result ? toDeduplicatedSortedArray(result) : emptyArray; } - const cachedTypings = this.projectService.typingsCache.getTypingsForProject(this, this.lastCachedUnresolvedImportsList, hasChanges); - if (!arrayIsEqualTo(this.typingFiles, cachedTypings)) { - this.typingFiles = cachedTypings; - this.markAsDirty(); - hasChanges = this.updateGraphWorker() || hasChanges; - } + this.projectService.typingsCache.enqueueInstallTypingsForProject(this, this.lastCachedUnresolvedImportsList, hasAddedorRemovedFiles); } else { this.lastCachedUnresolvedImportsList = undefined; } - if (hasChanges) { - this.projectStructureVersion++; + if (hasNewProgram) { + this.projectProgramVersion++; } - return !hasChanges; + return !hasNewProgram; + } + + /*@internal*/ + updateTypingFiles(typingFiles: SortedReadonlyArray) { + this.typingFiles = typingFiles; + // Invalidate files with unresolved imports + this.resolutionCache.setFilesWithInvalidatedNonRelativeUnresolvedImports(this.cachedUnresolvedImportsPerFile); } /* @internal */ @@ -876,9 +865,9 @@ namespace ts.server { // bump up the version if // - oldProgram is not set - this is a first time updateGraph is called // - newProgram is different from the old program and structure of the old program was not reused. - const hasChanges = this.program && (!oldProgram || (this.program !== oldProgram && !(oldProgram.structureIsReused & StructureIsReused.Completely))); + const hasNewProgram = this.program && (!oldProgram || (this.program !== oldProgram && !(oldProgram.structureIsReused & StructureIsReused.Completely))); this.hasChangedAutomaticTypeDirectiveNames = false; - if (hasChanges) { + if (hasNewProgram) { if (oldProgram) { for (const f of oldProgram.getSourceFiles()) { if (this.program.getSourceFileByPath(f.path)) { @@ -916,8 +905,8 @@ namespace ts.server { removed => this.detachScriptInfoFromProject(removed) ); const elapsed = timestamp() - start; - this.writeLog(`Finishing updateGraphWorker: Project: ${this.getProjectName()} Version: ${this.getProjectVersion()} structureChanged: ${hasChanges} Elapsed: ${elapsed}ms`); - return hasChanges; + this.writeLog(`Finishing updateGraphWorker: Project: ${this.getProjectName()} Version: ${this.getProjectVersion()} structureChanged: ${hasNewProgram} Elapsed: ${elapsed}ms`); + return hasNewProgram; } private detachScriptInfoFromProject(uncheckedFileName: string) { @@ -985,15 +974,13 @@ namespace ts.server { setCompilerOptions(compilerOptions: CompilerOptions) { if (compilerOptions) { compilerOptions.allowNonTsExtensions = true; - if (changesAffectModuleResolution(this.compilerOptions, compilerOptions)) { - // reset cached unresolved imports if changes in compiler options affected module resolution - this.cachedUnresolvedImportsPerFile.clear(); - this.lastCachedUnresolvedImportsList = undefined; - } const oldOptions = this.compilerOptions; this.compilerOptions = compilerOptions; this.setInternalCompilerOptionsForEmittingJsFiles(); if (changesAffectModuleResolution(oldOptions, compilerOptions)) { + // reset cached unresolved imports if changes in compiler options affected module resolution + this.cachedUnresolvedImportsPerFile.clear(); + this.lastCachedUnresolvedImportsList = undefined; this.resolutionCache.clear(); } this.markAsDirty(); @@ -1006,7 +993,7 @@ namespace ts.server { const info: protocol.ProjectVersionInfo = { projectName: this.getProjectName(), - version: this.projectStructureVersion, + version: this.projectProgramVersion, isInferred: this.projectKind === ProjectKind.Inferred, options: this.getCompilationSettings(), languageServiceDisabled: !this.languageServiceEnabled, @@ -1017,7 +1004,7 @@ namespace ts.server { // check if requested version is the same that we have reported last time if (this.lastReportedFileNames && lastKnownVersion === this.lastReportedVersion) { // if current structure version is the same - return info without any changes - if (this.projectStructureVersion === this.lastReportedVersion && !updatedFileNames) { + if (this.projectProgramVersion === this.lastReportedVersion && !updatedFileNames) { return { info, projectErrors: this.getGlobalProjectErrors() }; } // compute and return the difference @@ -1040,7 +1027,7 @@ namespace ts.server { } }); this.lastReportedFileNames = currentFiles; - this.lastReportedVersion = this.projectStructureVersion; + this.lastReportedVersion = this.projectProgramVersion; return { info, changes: { added, removed, updated }, projectErrors: this.getGlobalProjectErrors() }; } else { @@ -1049,7 +1036,7 @@ namespace ts.server { const externalFiles = this.getExternalFiles().map(f => toNormalizedPath(f)); const allFiles = projectFileNames.concat(externalFiles); this.lastReportedFileNames = arrayToSet(allFiles); - this.lastReportedVersion = this.projectStructureVersion; + this.lastReportedVersion = this.projectProgramVersion; return { info, files: allFiles, projectErrors: this.getGlobalProjectErrors() }; } } diff --git a/src/server/scriptInfo.ts b/src/server/scriptInfo.ts index db56973d796..589975769b1 100644 --- a/src/server/scriptInfo.ts +++ b/src/server/scriptInfo.ts @@ -304,6 +304,7 @@ namespace ts.server { const isNew = !this.isAttached(project); if (isNew) { this.containingProjects.push(project); + project.onFileAddedOrRemoved(); if (!project.getCompilerOptions().preserveSymlinks) { this.ensureRealPath(); } @@ -328,19 +329,24 @@ namespace ts.server { return; case 1: if (this.containingProjects[0] === project) { + project.onFileAddedOrRemoved(); this.containingProjects.pop(); } break; case 2: if (this.containingProjects[0] === project) { + project.onFileAddedOrRemoved(); this.containingProjects[0] = this.containingProjects.pop(); } else if (this.containingProjects[1] === project) { + project.onFileAddedOrRemoved(); this.containingProjects.pop(); } break; default: - unorderedRemoveItem(this.containingProjects, project); + if (unorderedRemoveItem(this.containingProjects, project)) { + project.onFileAddedOrRemoved(); + } break; } } diff --git a/src/server/session.ts b/src/server/session.ts index 1076d17e11f..27044ec369d 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -634,7 +634,8 @@ namespace ts.server { code: d.code, source: d.source, startLocation: scriptInfo && scriptInfo.positionToLineOffset(d.start), - endLocation: scriptInfo && scriptInfo.positionToLineOffset(d.start + d.length) + endLocation: scriptInfo && scriptInfo.positionToLineOffset(d.start + d.length), + reportsUnnecessary: d.reportsUnnecessary }); } diff --git a/src/server/tsconfig.json b/src/server/tsconfig.json index fe19cd418bd..dc732604ab6 100644 --- a/src/server/tsconfig.json +++ b/src/server/tsconfig.json @@ -108,10 +108,8 @@ "../services/codefixes/fixInvalidImportSyntax.ts", "../services/codefixes/fixStrictClassInitialization.ts", "../services/codefixes/useDefaultImport.ts", - "../services/codefixes/fixes.ts", "../services/refactors/extractSymbol.ts", "../services/refactors/generateGetAccessorAndSetAccessor.ts", - "../services/refactors/refactors.ts", "../services/sourcemaps.ts", "../services/services.ts", "../services/breakpoints.ts", diff --git a/src/server/tsconfig.library.json b/src/server/tsconfig.library.json index 54353daf5c6..dd0196fab76 100644 --- a/src/server/tsconfig.library.json +++ b/src/server/tsconfig.library.json @@ -114,10 +114,8 @@ "../services/codefixes/fixInvalidImportSyntax.ts", "../services/codefixes/fixStrictClassInitialization.ts", "../services/codefixes/useDefaultImport.ts", - "../services/codefixes/fixes.ts", "../services/refactors/extractSymbol.ts", "../services/refactors/generateGetAccessorAndSetAccessor.ts", - "../services/refactors/refactors.ts", "../services/sourcemaps.ts", "../services/services.ts", "../services/breakpoints.ts", diff --git a/src/server/typingsCache.ts b/src/server/typingsCache.ts index f2642230f2d..c255757481f 100644 --- a/src/server/typingsCache.ts +++ b/src/server/typingsCache.ts @@ -24,7 +24,7 @@ namespace ts.server { globalTypingsCacheLocation: undefined }; - class TypingsCacheEntry { + interface TypingsCacheEntry { readonly typeAcquisition: TypeAcquisition; readonly compilerOptions: CompilerOptions; readonly typings: SortedReadonlyArray; @@ -80,6 +80,7 @@ namespace ts.server { return !arrayIsEqualTo(imports1, imports2); } + /*@internal*/ export class TypingsCache { private readonly perProjectCache: Map = createMap(); @@ -94,15 +95,14 @@ namespace ts.server { return this.installer.installPackage(options); } - getTypingsForProject(project: Project, unresolvedImports: SortedReadonlyArray, forceRefresh: boolean): SortedReadonlyArray { + enqueueInstallTypingsForProject(project: Project, unresolvedImports: SortedReadonlyArray, forceRefresh: boolean) { const typeAcquisition = project.getTypeAcquisition(); if (!typeAcquisition || !typeAcquisition.enable) { - return emptyArray; + return; } const entry = this.perProjectCache.get(project.getProjectName()); - const result: SortedReadonlyArray = entry ? entry.typings : emptyArray; if (forceRefresh || !entry || typeAcquisitionChanged(typeAcquisition, entry.typeAcquisition) || @@ -113,28 +113,25 @@ namespace ts.server { this.perProjectCache.set(project.getProjectName(), { compilerOptions: project.getCompilationSettings(), typeAcquisition, - typings: result, + typings: entry ? entry.typings : emptyArray, unresolvedImports, poisoned: true }); // something has been changed, issue a request to update typings this.installer.enqueueInstallTypingsRequest(project, typeAcquisition, unresolvedImports); } - return result; } updateTypingsForProject(projectName: string, compilerOptions: CompilerOptions, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray, newTypings: string[]) { + const typings = toSortedArray(newTypings); this.perProjectCache.set(projectName, { compilerOptions, typeAcquisition, - typings: toSortedArray(newTypings), + typings, unresolvedImports, poisoned: false }); - } - - deleteTypingsForProject(projectName: string) { - this.perProjectCache.delete(projectName); + return !typeAcquisition || !typeAcquisition.enable ? emptyArray : typings; } onProjectClosed(project: Project) { diff --git a/src/server/typingsInstaller/typingsInstaller.ts b/src/server/typingsInstaller/typingsInstaller.ts index 8d482241d1b..f79564f6f98 100644 --- a/src/server/typingsInstaller/typingsInstaller.ts +++ b/src/server/typingsInstaller/typingsInstaller.ts @@ -64,11 +64,13 @@ namespace ts.server.typingsInstaller { onRequestCompleted: RequestCompletedAction; } + type ProjectWatchers = Map & { isInvoked?: boolean; }; + export abstract class TypingsInstaller { private readonly packageNameToTypingLocation: Map = createMap(); private readonly missingTypingsSet: Map = createMap(); private readonly knownCachesSet: Map = createMap(); - private readonly projectWatchers = createMap>(); + private readonly projectWatchers = createMap(); private safeList: JsTyping.SafeList | undefined; readonly pendingRunRequests: PendingRequest[] = []; @@ -378,8 +380,8 @@ namespace ts.server.typingsInstaller { this.projectWatchers.set(projectName, watchers); } + watchers.isInvoked = false; // handler should be invoked once for the entire set of files since it will trigger full rediscovery of typings - let isInvoked = false; const isLoggingEnabled = this.log.isEnabled(); mutateMap( watchers, @@ -392,11 +394,11 @@ namespace ts.server.typingsInstaller { } const watcher = this.installTypingHost.watchFile(file, (f, eventKind) => { if (isLoggingEnabled) { - this.log.writeLine(`FileWatcher:: Triggered with ${f} eventKind: ${FileWatcherEventKind[eventKind]}:: WatchInfo: ${file}:: handler is already invoked '${isInvoked}'`); + this.log.writeLine(`FileWatcher:: Triggered with ${f} eventKind: ${FileWatcherEventKind[eventKind]}:: WatchInfo: ${file}:: handler is already invoked '${watchers.isInvoked}'`); } - if (!isInvoked) { + if (!watchers.isInvoked) { + watchers.isInvoked = true; this.sendResponse({ projectName, kind: ActionInvalidate }); - isInvoked = true; } }, /*pollingInterval*/ 2000); return isLoggingEnabled ? { diff --git a/src/services/codefixes/convertFunctionToEs6Class.ts b/src/services/codefixes/convertFunctionToEs6Class.ts index bf20aeda72b..d137785a7e7 100644 --- a/src/services/codefixes/convertFunctionToEs6Class.ts +++ b/src/services/codefixes/convertFunctionToEs6Class.ts @@ -34,13 +34,14 @@ namespace ts.codefix { case SyntaxKind.VariableDeclaration: precedingNode = ctorDeclaration.parent.parent; + newClassDeclaration = createClassFromVariableDeclaration(ctorDeclaration as VariableDeclaration); if ((ctorDeclaration.parent).declarations.length === 1) { + copyComments(precedingNode, newClassDeclaration, sourceFile); deleteNode(precedingNode); } else { deleteNode(ctorDeclaration, /*inList*/ true); } - newClassDeclaration = createClassFromVariableDeclaration(ctorDeclaration as VariableDeclaration); break; } diff --git a/src/services/codefixes/convertToEs6Module.ts b/src/services/codefixes/convertToEs6Module.ts index 8ffba3218c0..a8df21dc96d 100644 --- a/src/services/codefixes/convertToEs6Module.ts +++ b/src/services/codefixes/convertToEs6Module.ts @@ -130,23 +130,23 @@ namespace ts.codefix { let foundImport = false; const newNodes = flatMap(declarationList.declarations, decl => { const { name, initializer } = decl; - if (isExportsOrModuleExportsOrAlias(sourceFile, initializer)) { - // `const alias = module.exports;` can be removed. - foundImport = true; - return []; - } - if (isRequireCall(initializer, /*checkArgumentIsStringLiteralLike*/ true)) { - foundImport = true; - return convertSingleImport(sourceFile, name, initializer.arguments[0], changes, checker, identifiers, target); - } - else if (isPropertyAccessExpression(initializer) && isRequireCall(initializer.expression, /*checkArgumentIsStringLiteralLike*/ true)) { - foundImport = true; - return convertPropertyAccessImport(name, initializer.name.text, initializer.expression.arguments[0], identifiers); - } - else { - // Move it out to its own variable statement. (This will not be used if `!foundImport`) - return createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList([decl], declarationList.flags)); + if (initializer) { + if (isExportsOrModuleExportsOrAlias(sourceFile, initializer)) { + // `const alias = module.exports;` can be removed. + foundImport = true; + return []; + } + else if (isRequireCall(initializer, /*checkArgumentIsStringLiteralLike*/ true)) { + foundImport = true; + return convertSingleImport(sourceFile, name, initializer.arguments[0], changes, checker, identifiers, target); + } + else if (isPropertyAccessExpression(initializer) && isRequireCall(initializer.expression, /*checkArgumentIsStringLiteralLike*/ true)) { + foundImport = true; + return convertPropertyAccessImport(name, initializer.name.text, initializer.expression.arguments[0], identifiers); + } } + // Move it out to its own variable statement. (This will not be used if `!foundImport`) + return createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList([decl], declarationList.flags)); }); if (foundImport) { // useNonAdjustedEndPosition to ensure we don't eat the newline after the statement. diff --git a/src/services/codefixes/fixes.ts b/src/services/codefixes/fixes.ts deleted file mode 100644 index bc845bd8dc0..00000000000 --- a/src/services/codefixes/fixes.ts +++ /dev/null @@ -1 +0,0 @@ -// Please delete me later. diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 7c5922035ea..60f53c2f527 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -130,8 +130,7 @@ namespace ts.FindAllReferences { const { node, name, kind, displayParts } = info; const sourceFile = node.getSourceFile(); - const textSpan = getTextSpan(isComputedPropertyName(node) ? node.expression : node, sourceFile); - return { containerKind: ScriptElementKind.unknown, containerName: "", fileName: sourceFile.fileName, kind, name, textSpan, displayParts }; + return { containerKind: ScriptElementKind.unknown, containerName: "", fileName: sourceFile.fileName, kind, name, textSpan: getTextSpan(isComputedPropertyName(node) ? node.expression : node, sourceFile), displayParts }; } function getDefinitionKindAndDisplayParts(symbol: Symbol, checker: TypeChecker, node: Node): { displayParts: SymbolDisplayPart[], kind: ScriptElementKind } { @@ -148,21 +147,23 @@ namespace ts.FindAllReferences { } const { node, isInString } = entry; + const sourceFile = node.getSourceFile(); return { - fileName: node.getSourceFile().fileName, - textSpan: getTextSpan(node), + fileName: sourceFile.fileName, + textSpan: getTextSpan(node, sourceFile), isWriteAccess: isWriteAccessForReference(node), isDefinition: node.kind === SyntaxKind.DefaultKeyword || isAnyDeclarationName(node) || isLiteralComputedPropertyDeclarationName(node), - isInString + isInString, }; } function toImplementationLocation(entry: Entry, checker: TypeChecker): ImplementationLocation { if (entry.type === "node") { const { node } = entry; - return { textSpan: getTextSpan(node), fileName: node.getSourceFile().fileName, ...implementationKindDisplayParts(node, checker) }; + const sourceFile = node.getSourceFile(); + return { textSpan: getTextSpan(node, sourceFile), fileName: sourceFile.fileName, ...implementationKindDisplayParts(node, checker) }; } else { const { textSpan, fileName } = entry; @@ -199,17 +200,17 @@ namespace ts.FindAllReferences { } const { node, isInString } = entry; - const fileName = entry.node.getSourceFile().fileName; + const sourceFile = node.getSourceFile(); const writeAccess = isWriteAccessForReference(node); const span: HighlightSpan = { - textSpan: getTextSpan(node), + textSpan: getTextSpan(node, sourceFile), kind: writeAccess ? HighlightSpanKind.writtenReference : HighlightSpanKind.reference, isInString }; - return { fileName, span }; + return { fileName: sourceFile.fileName, span }; } - function getTextSpan(node: Node, sourceFile?: SourceFile): TextSpan { + function getTextSpan(node: Node, sourceFile: SourceFile): TextSpan { let start = node.getStart(sourceFile); let end = node.getEnd(); if (node.kind === SyntaxKind.StringLiteral) { @@ -424,7 +425,8 @@ namespace ts.FindAllReferences.Core { readonly text: string; readonly escapedText: __String; /** Only set if `options.implementations` is true. These are the symbols checked to get the implementations of a property access. */ - readonly parents: Symbol[] | undefined; + readonly parents: ReadonlyArray | undefined; + readonly allSearchSymbols: ReadonlyArray; /** * Whether a symbol is in the search set. @@ -500,14 +502,11 @@ namespace ts.FindAllReferences.Core { // here appears to be intentional). const { text = stripQuotes(unescapeLeadingUnderscores((getLocalSymbolForExportDefault(symbol) || symbol).escapedName)), - allSearchSymbols, + allSearchSymbols = [symbol], } = searchOptions; const escapedText = escapeLeadingUnderscores(text); const parents = this.options.implementations && getParentSymbolsOfPropertyAccess(location, symbol, this.checker); - return { - symbol, comingFrom, text, escapedText, parents, - includes: referenceSymbol => allSearchSymbols ? contains(allSearchSymbols, referenceSymbol) : referenceSymbol === symbol, - }; + return { symbol, comingFrom, text, escapedText, parents, allSearchSymbols, includes: sym => contains(allSearchSymbols, sym) }; } private readonly symbolIdToReferences: Entry[][] = []; @@ -534,13 +533,17 @@ namespace ts.FindAllReferences.Core { } // Source file ID → symbol ID → Whether the symbol has been searched for in the source file. - private readonly sourceFileToSeenSymbols: true[][] = []; + private readonly sourceFileToSeenSymbols: Map[] = []; /** Returns `true` the first time we search for a symbol in a file and `false` afterwards. */ - markSearchedSymbol(sourceFile: SourceFile, symbol: Symbol): boolean { + markSearchedSymbols(sourceFile: SourceFile, symbols: ReadonlyArray): boolean { const sourceId = getNodeId(sourceFile); - const symbolId = getSymbolId(symbol); - const seenSymbols = this.sourceFileToSeenSymbols[sourceId] || (this.sourceFileToSeenSymbols[sourceId] = []); - return !seenSymbols[symbolId] && (seenSymbols[symbolId] = true); + const seenSymbols = this.sourceFileToSeenSymbols[sourceId] || (this.sourceFileToSeenSymbols[sourceId] = createMap()); + + let anyNewSymbols = false; + for (const sym of symbols) { + anyNewSymbols = addToSeen(seenSymbols, getSymbolId(sym)) || anyNewSymbols; + } + return anyNewSymbols; } } @@ -804,7 +807,7 @@ namespace ts.FindAllReferences.Core { * searchLocation: a node where the search value */ function getReferencesInContainer(container: Node, sourceFile: SourceFile, search: Search, state: State, addReferencesHere: boolean): void { - if (!state.markSearchedSymbol(sourceFile, search.symbol)) { + if (!state.markSearchedSymbols(sourceFile, search.allSearchSymbols)) { return; } @@ -1028,10 +1031,6 @@ namespace ts.FindAllReferences.Core { } } - function getPropertyAccessExpressionFromRightHandSide(node: Node): PropertyAccessExpression { - return isRightSideOfPropertyAccess(node) && node.parent; - } - /** * `classSymbol` is the class where the constructor was defined. * Reference the constructor and all calls to `new this()`. @@ -1103,69 +1102,37 @@ namespace ts.FindAllReferences.Core { } // If we got a type reference, try and see if the reference applies to any expressions that can implement an interface - const containingTypeReference = getContainingTypeReference(refNode); - if (containingTypeReference && state.markSeenContainingTypeReference(containingTypeReference)) { - const parent = containingTypeReference.parent; - if (hasType(parent) && parent.type === containingTypeReference && hasInitializer(parent) && isImplementationExpression(parent.initializer)) { - addReference(parent.initializer); + // Find the first node whose parent isn't a type node -- i.e., the highest type node. + const typeNode = findAncestor(refNode, a => !isQualifiedName(a.parent) && !isTypeNode(a.parent) && !isTypeElement(a.parent)); + const typeHavingNode = typeNode.parent; + if (hasType(typeHavingNode) && typeHavingNode.type === typeNode && state.markSeenContainingTypeReference(typeHavingNode)) { + if (hasInitializer(typeHavingNode)) { + addIfImplementation(typeHavingNode.initializer); } - else if (isFunctionLike(parent) && parent.type === containingTypeReference && (parent as FunctionLikeDeclaration).body) { - const body = (parent as FunctionLikeDeclaration).body; + else if (isFunctionLike(typeHavingNode) && (typeHavingNode as FunctionLikeDeclaration).body) { + const body = (typeHavingNode as FunctionLikeDeclaration).body; if (body.kind === SyntaxKind.Block) { forEachReturnStatement(body, returnStatement => { - if (returnStatement.expression && isImplementationExpression(returnStatement.expression)) { - addReference(returnStatement.expression); - } + if (returnStatement.expression) addIfImplementation(returnStatement.expression); }); } - else if (isImplementationExpression(body)) { - addReference(body); + else { + addIfImplementation(body); } } - else if (isAssertionExpression(parent) && isImplementationExpression(parent.expression)) { - addReference(parent.expression); + else if (isAssertionExpression(typeHavingNode)) { + addIfImplementation(typeHavingNode.expression); } } + + function addIfImplementation(e: Expression): void { + if (isImplementationExpression(e)) addReference(e); + } } - function getSymbolsForClassAndInterfaceComponents(type: UnionOrIntersectionType, result: Symbol[] = []): Symbol[] { - for (const componentType of type.types) { - if (componentType.symbol && componentType.symbol.getFlags() & (SymbolFlags.Class | SymbolFlags.Interface)) { - result.push(componentType.symbol); - } - if (componentType.isUnionOrIntersection()) { - getSymbolsForClassAndInterfaceComponents(componentType, result); - } - } - return result; - } - - function getContainingTypeReference(node: Node): Node { - let topLevelTypeReference: Node; - - while (node) { - if (isTypeNode(node)) { - topLevelTypeReference = node; - } - node = node.parent; - } - - return topLevelTypeReference; - } - - function getContainingClassIfInHeritageClause(node: Node): ClassLikeDeclaration { - if (node && node.parent) { - if (node.kind === SyntaxKind.ExpressionWithTypeArguments - && node.parent.kind === SyntaxKind.HeritageClause - && isClassLike(node.parent.parent)) { - return node.parent.parent; - } - - else if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PropertyAccessExpression) { - return getContainingClassIfInHeritageClause(node.parent); - } - } - return undefined; + function getContainingClassIfInHeritageClause(node: Node): ClassLikeDeclaration | InterfaceDeclaration { + return isIdentifier(node) || isPropertyAccessExpression(node) ? getContainingClassIfInHeritageClause(node.parent) + : isExpressionWithTypeArguments(node) ? tryCast(node.parent.parent, isClassLike) : undefined; } /** @@ -1460,7 +1427,7 @@ namespace ts.FindAllReferences.Core { ? rootSymbol && !(getCheckFlags(sym) & CheckFlags.Synthetic) ? rootSymbol : sym : undefined, /*allowBaseTypes*/ rootSymbol => - !(search.parents && !some(search.parents, parent => explicitlyInheritsFrom(rootSymbol.parent, parent, state.inheritsFromCache, checker)))); + !(search.parents && !search.parents.some(parent => explicitlyInheritsFrom(rootSymbol.parent, parent, state.inheritsFromCache, checker)))); } /** Gets all symbols for one property. Does not get symbols for every property. */ @@ -1547,13 +1514,11 @@ namespace ts.FindAllReferences.Core { * symbol may have a different parent symbol if the local type's symbol does not declare the property * being accessed (i.e. it is declared in some parent class or interface) */ - function getParentSymbolsOfPropertyAccess(location: Node, symbol: Symbol, checker: TypeChecker): Symbol[] | undefined { - const propertyAccessExpression = getPropertyAccessExpressionFromRightHandSide(location); - const localParentType = propertyAccessExpression && checker.getTypeAtLocation(propertyAccessExpression.expression); - return localParentType && localParentType.symbol && localParentType.symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) && localParentType.symbol !== symbol.parent - ? [localParentType.symbol] - : localParentType && localParentType.isUnionOrIntersection() - ? getSymbolsForClassAndInterfaceComponents(localParentType) - : undefined; + function getParentSymbolsOfPropertyAccess(location: Node, symbol: Symbol, checker: TypeChecker): ReadonlyArray | undefined { + const propertyAccessExpression = isRightSideOfPropertyAccess(location) ? location.parent : undefined; + const lhsType = propertyAccessExpression && checker.getTypeAtLocation(propertyAccessExpression.expression); + const res = mapDefined(lhsType && (lhsType.isUnionOrIntersection() ? lhsType.types : lhsType.symbol === symbol.parent ? undefined : [lhsType]), t => + t.symbol && t.symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) ? t.symbol : undefined); + return res.length === 0 ? undefined : res; } } diff --git a/src/services/goToDefinition.ts b/src/services/goToDefinition.ts index 226fe74ef10..f97a8338b05 100644 --- a/src/services/goToDefinition.ts +++ b/src/services/goToDefinition.ts @@ -50,16 +50,7 @@ namespace ts.GoToDefinition { // assignment. This case and others are handled by the following code. if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) { const shorthandSymbol = typeChecker.getShorthandAssignmentValueSymbol(symbol.valueDeclaration); - if (!shorthandSymbol) { - return []; - } - - const shorthandDeclarations = shorthandSymbol.getDeclarations(); - const shorthandSymbolKind = SymbolDisplay.getSymbolKind(typeChecker, shorthandSymbol, node); - const shorthandSymbolName = typeChecker.symbolToString(shorthandSymbol); - const shorthandContainerName = typeChecker.symbolToString(symbol.parent, node); - return map(shorthandDeclarations, - declaration => createDefinitionInfo(declaration, shorthandSymbolKind, shorthandSymbolName, shorthandContainerName)); + return shorthandSymbol ? shorthandSymbol.declarations.map(decl => createDefinitionInfo(decl, typeChecker, shorthandSymbol, node)) : []; } // If the node is the name of a BindingElement within an ObjectBindingPattern instead of just returning the @@ -191,8 +182,7 @@ namespace ts.GoToDefinition { } function getDefinitionFromSymbol(typeChecker: TypeChecker, symbol: Symbol, node: Node): DefinitionInfo[] { - const { symbolName, symbolKind, containerName } = getSymbolInfo(typeChecker, symbol, node); - return getConstructSignatureDefinition() || getCallSignatureDefinition() || map(symbol.declarations, declaration => createDefinitionInfo(declaration, symbolKind, symbolName, containerName)); + return getConstructSignatureDefinition() || getCallSignatureDefinition() || map(symbol.declarations, declaration => createDefinitionInfo(declaration, typeChecker, symbol, node)); function getConstructSignatureDefinition(): DefinitionInfo[] | undefined { // Applicable only if we are in a new expression, or we are on a constructor declaration @@ -213,33 +203,24 @@ namespace ts.GoToDefinition { if (!signatureDeclarations) { return undefined; } - const declarations = signatureDeclarations.filter(selectConstructors ? isConstructorDeclaration : isSignatureDeclaration); + const declarations = signatureDeclarations.filter(selectConstructors ? isConstructorDeclaration : isFunctionLike); return declarations.length - ? [createDefinitionInfo(find(declarations, d => !!(d).body) || last(declarations), symbolKind, symbolName, containerName)] + ? [createDefinitionInfo(find(declarations, d => !!(d).body) || last(declarations), typeChecker, symbol, node)] : undefined; } } - function isSignatureDeclaration(node: Node): boolean { - switch (node.kind) { - case SyntaxKind.Constructor: - case SyntaxKind.ConstructSignature: - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.MethodSignature: - return true; - default: - return false; - } - } - /** Creates a DefinitionInfo from a Declaration, using the declaration's name if possible. */ - function createDefinitionInfo(node: Declaration, symbolKind: ScriptElementKind, symbolName: string, containerName: string): DefinitionInfo { - return createDefinitionInfoFromName(getNameOfDeclaration(node) || node, symbolKind, symbolName, containerName); + function createDefinitionInfo(declaration: Declaration, checker: TypeChecker, symbol: Symbol, node: Node): DefinitionInfo { + const symbolName = checker.symbolToString(symbol); // Do not get scoped name, just the name of the symbol + const symbolKind = SymbolDisplay.getSymbolKind(checker, symbol, node); + const containerName = symbol.parent ? checker.symbolToString(symbol.parent, node) : ""; + return createDefinitionInfoFromName(declaration, symbolKind, symbolName, containerName); } /** Creates a DefinitionInfo directly from the name of a declaration. */ - function createDefinitionInfoFromName(name: Node, symbolKind: ScriptElementKind, symbolName: string, containerName: string): DefinitionInfo { + function createDefinitionInfoFromName(declaration: Declaration, symbolKind: ScriptElementKind, symbolName: string, containerName: string): DefinitionInfo { + const name = getNameOfDeclaration(declaration) || declaration; const sourceFile = name.getSourceFile(); return { fileName: sourceFile.fileName, @@ -251,26 +232,12 @@ namespace ts.GoToDefinition { }; } - function getSymbolInfo(typeChecker: TypeChecker, symbol: Symbol, node: Node) { - return { - symbolName: typeChecker.symbolToString(symbol), // Do not get scoped name, just the name of the symbol - symbolKind: SymbolDisplay.getSymbolKind(typeChecker, symbol, node), - containerName: symbol.parent ? typeChecker.symbolToString(symbol.parent, node) : "" - }; - } - function createDefinitionFromSignatureDeclaration(typeChecker: TypeChecker, decl: SignatureDeclaration): DefinitionInfo { - const { symbolName, symbolKind, containerName } = getSymbolInfo(typeChecker, decl.symbol, decl); - return createDefinitionInfo(decl, symbolKind, symbolName, containerName); + return createDefinitionInfo(decl, typeChecker, decl.symbol, decl); } export function findReferenceInPosition(refs: ReadonlyArray, pos: number): FileReference | undefined { - for (const ref of refs) { - if (ref.pos <= pos && pos <= ref.end) { - return ref; - } - } - return undefined; + return find(refs, ref => ref.pos <= pos && pos <= ref.end); } function getDefinitionInfoForFileReference(name: string, targetFileName: string): DefinitionInfo { @@ -298,13 +265,7 @@ namespace ts.GoToDefinition { function tryGetSignatureDeclaration(typeChecker: TypeChecker, node: Node): SignatureDeclaration | undefined { const callLike = getAncestorCallLikeExpression(node); const signature = callLike && typeChecker.getResolvedSignature(callLike); - if (signature) { - const decl = signature.declaration; - if (decl && isSignatureDeclaration(decl)) { - return decl; - } - } // Don't go to a function type, go to the value having that type. - return undefined; + return tryCast(signature && signature.declaration, (d): d is SignatureDeclaration => isFunctionLike(d) && !isFunctionTypeNode(d)); } } diff --git a/src/services/importTracker.ts b/src/services/importTracker.ts index 82f9fc00af6..80f0721e642 100644 --- a/src/services/importTracker.ts +++ b/src/services/importTracker.ts @@ -33,7 +33,7 @@ namespace ts.FindAllReferences { interface AmbientModuleDeclaration extends ModuleDeclaration { body?: ModuleBlock; } type SourceFileLike = SourceFile | AmbientModuleDeclaration; // Identifier for the case of `const x = require("y")`. - type Importer = AnyImportOrReExport | Identifier; + type Importer = AnyImportOrReExport | ImportTypeNode | Identifier; type ImporterOrCallExpression = Importer | CallExpression; /** Returns import statements that directly reference the exporting module, and a list of files that may access the module through a namespace. */ @@ -215,6 +215,10 @@ namespace ts.FindAllReferences { return; } + if (decl.kind === SyntaxKind.ImportType) { + return; + } + // Ignore if there's a grammar error if (decl.moduleSpecifier.kind !== SyntaxKind.StringLiteral) { return; diff --git a/src/services/outliningElementsCollector.ts b/src/services/outliningElementsCollector.ts index 90c53d47561..65888305d81 100644 --- a/src/services/outliningElementsCollector.ts +++ b/src/services/outliningElementsCollector.ts @@ -21,7 +21,17 @@ namespace ts.OutliningElementsCollector { if (span) out.push(span); depthRemaining--; - n.forEachChild(walk); + if (isIfStatement(n) && n.elseStatement && isIfStatement(n.elseStatement)) { + // Consider an 'else if' to be on the same depth as the 'if'. + walk(n.expression); + walk(n.thenStatement); + depthRemaining++; + walk(n.elseStatement); + depthRemaining--; + } + else { + n.forEachChild(walk); + } depthRemaining++; }); } diff --git a/src/services/refactors/refactors.ts b/src/services/refactors/refactors.ts deleted file mode 100644 index bc845bd8dc0..00000000000 --- a/src/services/refactors/refactors.ts +++ /dev/null @@ -1 +0,0 @@ -// Please delete me later. diff --git a/src/services/services.ts b/src/services/services.ts index bed301e452f..a192231405a 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1673,7 +1673,7 @@ namespace ts { } function getDocumentHighlights(fileName: string, position: number, filesToSearch: ReadonlyArray): DocumentHighlights[] { - Debug.assert(contains(filesToSearch, fileName)); + Debug.assert(filesToSearch.some(f => normalizePath(f) === fileName)); synchronizeHostData(); const sourceFilesToSearch = map(filesToSearch, f => Debug.assertDefined(program.getSourceFile(f))); const sourceFile = getValidSourceFile(fileName); diff --git a/src/services/suggestionDiagnostics.ts b/src/services/suggestionDiagnostics.ts index 1fc1d671e43..d9f55a78d82 100644 --- a/src/services/suggestionDiagnostics.ts +++ b/src/services/suggestionDiagnostics.ts @@ -6,7 +6,7 @@ namespace ts { const diags: Diagnostic[] = []; if (sourceFile.commonJsModuleIndicator) { - diags.push(createDiagnosticForNode(sourceFile.commonJsModuleIndicator, Diagnostics.File_is_a_CommonJS_module_it_may_be_converted_to_an_ES6_module)); + diags.push(createDiagnosticForNode(getErrorNodeFromCommonJsIndicator(sourceFile.commonJsModuleIndicator), Diagnostics.File_is_a_CommonJS_module_it_may_be_converted_to_an_ES6_module)); } const isJsFile = isSourceFileJavaScript(sourceFile); @@ -61,4 +61,8 @@ namespace ts { return undefined; } } + + function getErrorNodeFromCommonJsIndicator(commonJsModuleIndicator: Node): Node { + return isBinaryExpression(commonJsModuleIndicator) ? commonJsModuleIndicator.left : commonJsModuleIndicator; + } } diff --git a/src/services/symbolDisplay.ts b/src/services/symbolDisplay.ts index 4693a5089f1..f79c048efad 100644 --- a/src/services/symbolDisplay.ts +++ b/src/services/symbolDisplay.ts @@ -26,6 +26,15 @@ namespace ts.SymbolDisplay { } function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(typeChecker: TypeChecker, symbol: Symbol, location: Node): ScriptElementKind { + const roots = typeChecker.getRootSymbols(symbol); + // If this is a method from a mapped type, leave as a method so long as it still has a call signature. + if (roots.length === 1 + && first(roots).flags & SymbolFlags.Method + // Ensure the mapped version is still a method, as opposed to `{ [K in keyof I]: number }`. + && typeChecker.getTypeOfSymbolAtLocation(symbol, location).getNonNullableType().getCallSignatures().length !== 0) { + return ScriptElementKind.memberFunctionElement; + } + if (typeChecker.isUndefinedSymbol(symbol)) { return ScriptElementKind.variableElement; } @@ -178,7 +187,7 @@ namespace ts.SymbolDisplay { } else if (symbolFlags & SymbolFlags.Alias) { symbolKind = ScriptElementKind.alias; - pushTypePart(symbolKind); + pushSymbolKind(symbolKind); displayParts.push(spacePart()); if (useConstructSignatures) { displayParts.push(keywordPart(SyntaxKind.NewKeyword)); @@ -258,7 +267,7 @@ namespace ts.SymbolDisplay { // Special case for class expressions because we would like to indicate that // the class name is local to the class body (similar to function expression) // (local class) class - pushTypePart(ScriptElementKind.localClassElement); + pushSymbolKind(ScriptElementKind.localClassElement); } else { // Class declaration has name which is not local. @@ -531,7 +540,7 @@ namespace ts.SymbolDisplay { function addAliasPrefixIfNecessary() { if (alias) { - pushTypePart(ScriptElementKind.alias); + pushSymbolKind(ScriptElementKind.alias); displayParts.push(spacePart()); } } @@ -549,12 +558,16 @@ namespace ts.SymbolDisplay { const fullSymbolDisplayParts = symbolToDisplayParts(typeChecker, symbolToDisplay, enclosingDeclaration || sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments | SymbolFormatFlags.UseOnlyExternalAliasing | SymbolFormatFlags.AllowAnyNodeKind); addRange(displayParts, fullSymbolDisplayParts); + + if (symbol.flags & SymbolFlags.Optional) { + displayParts.push(punctuationPart(SyntaxKind.QuestionToken)); + } } function addPrefixForAnyFunctionOrVar(symbol: Symbol, symbolKind: string) { prefixNextMeaning(); if (symbolKind) { - pushTypePart(symbolKind); + pushSymbolKind(symbolKind); if (symbol && !some(symbol.declarations, d => isArrowFunction(d) || (isFunctionExpression(d) || isClassExpression(d)) && !d.name)) { displayParts.push(spacePart()); addFullSymbolName(symbol); @@ -562,7 +575,7 @@ namespace ts.SymbolDisplay { } } - function pushTypePart(symbolKind: string) { + function pushSymbolKind(symbolKind: string) { switch (symbolKind) { case ScriptElementKind.variableElement: case ScriptElementKind.functionElement: diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index a54790df3be..31b35a44271 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -105,10 +105,8 @@ "codefixes/fixInvalidImportSyntax.ts", "codefixes/fixStrictClassInitialization.ts", "codefixes/useDefaultImport.ts", - "codefixes/fixes.ts", "refactors/extractSymbol.ts", "refactors/generateGetAccessorAndSetAccessor.ts", - "refactors/refactors.ts", "sourcemaps.ts", "services.ts", "breakpoints.ts", diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 9d63950cc66..1ba84a4d08f 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -1160,7 +1160,7 @@ declare namespace ts { interface DebuggerStatement extends Statement { kind: SyntaxKind.DebuggerStatement; } - interface MissingDeclaration extends DeclarationStatement, ClassElement, ObjectLiteralElement, TypeElement { + interface MissingDeclaration extends DeclarationStatement { kind: SyntaxKind.MissingDeclaration; name?: Identifier; } @@ -3175,6 +3175,7 @@ declare namespace ts { function isIndexedAccessTypeNode(node: Node): node is IndexedAccessTypeNode; function isMappedTypeNode(node: Node): node is MappedTypeNode; function isLiteralTypeNode(node: Node): node is LiteralTypeNode; + function isImportTypeNode(node: Node): node is ImportTypeNode; function isObjectBindingPattern(node: Node): node is ObjectBindingPattern; function isArrayBindingPattern(node: Node): node is ArrayBindingPattern; function isBindingElement(node: Node): node is BindingElement; @@ -7613,17 +7614,6 @@ declare namespace ts.server { readonly globalTypingsCacheLocation: string; } const nullTypingsInstaller: ITypingsInstaller; - class TypingsCache { - private readonly installer; - private readonly perProjectCache; - constructor(installer: ITypingsInstaller); - isKnownTypesPackageName(name: string): boolean; - installPackage(options: InstallPackageOptionsWithProject): Promise; - getTypingsForProject(project: Project, unresolvedImports: SortedReadonlyArray, forceRefresh: boolean): SortedReadonlyArray; - updateTypingsForProject(projectName: string, compilerOptions: CompilerOptions, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray, newTypings: string[]): void; - deleteTypingsForProject(projectName: string): void; - onProjectClosed(project: Project): void; - } } declare namespace ts.server { enum ProjectKind { @@ -7633,15 +7623,6 @@ declare namespace ts.server { } function allRootFilesAreJsOrDts(project: Project): boolean; function allFilesAreJsOrDts(project: Project): boolean; - class UnresolvedImportsMap { - readonly perFileMap: Map>; - private version; - clear(): void; - getVersion(): number; - remove(path: Path): void; - get(path: Path): ReadonlyArray; - set(path: Path, value: ReadonlyArray): void; - } interface PluginCreateInfo { project: Project; languageService: LanguageService; @@ -7674,8 +7655,6 @@ declare namespace ts.server { private externalFiles; private missingFilesMap; private plugins; - private cachedUnresolvedImportsPerFile; - private lastCachedUnresolvedImportsList; private lastFileExceededProgramSize; protected languageService: LanguageService; languageServiceEnabled: boolean; @@ -7695,10 +7674,10 @@ declare namespace ts.server { */ private lastReportedVersion; /** - * Current project structure version. + * Current project's program version. (incremented everytime new program is created that is not complete reuse from the old one) * This property is changed in 'updateGraph' based on the set of files in program */ - private projectStructureVersion; + private projectProgramVersion; /** * Current version of the project state. It is changed when: * - new root file was added/removed @@ -7706,11 +7685,9 @@ declare namespace ts.server { * This property is different from projectStructureVersion since in most cases edits don't affect set of files in the project */ private projectStateVersion; - private typingFiles; private readonly cancellationToken; isNonTsProject(): boolean; isJsOnlyProject(): boolean; - getCachedUnresolvedImportsPerFile_TestOnly(): UnresolvedImportsMap; static resolveModule(moduleName: string, initialDir: string, host: ServerHost, log: (message: string) => void): {}; isKnownTypesPackageName(name: string): boolean; installPackage(options: InstallPackageOptions): Promise; @@ -7971,7 +7948,6 @@ declare namespace ts.server { syntaxOnly?: boolean; } class ProjectService { - readonly typingsCache: TypingsCache; private readonly documentRegistry; /** * Container of all known scripts diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 8f6e3a70291..d93c09f1281 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -1160,7 +1160,7 @@ declare namespace ts { interface DebuggerStatement extends Statement { kind: SyntaxKind.DebuggerStatement; } - interface MissingDeclaration extends DeclarationStatement, ClassElement, ObjectLiteralElement, TypeElement { + interface MissingDeclaration extends DeclarationStatement { kind: SyntaxKind.MissingDeclaration; name?: Identifier; } @@ -3175,6 +3175,7 @@ declare namespace ts { function isIndexedAccessTypeNode(node: Node): node is IndexedAccessTypeNode; function isMappedTypeNode(node: Node): node is MappedTypeNode; function isLiteralTypeNode(node: Node): node is LiteralTypeNode; + function isImportTypeNode(node: Node): node is ImportTypeNode; function isObjectBindingPattern(node: Node): node is ObjectBindingPattern; function isArrayBindingPattern(node: Node): node is ArrayBindingPattern; function isBindingElement(node: Node): node is BindingElement; diff --git a/tests/baselines/reference/importEmptyFromModuleNotExisted.errors.txt b/tests/baselines/reference/importEmptyFromModuleNotExisted.errors.txt new file mode 100644 index 00000000000..99ccd49c489 --- /dev/null +++ b/tests/baselines/reference/importEmptyFromModuleNotExisted.errors.txt @@ -0,0 +1,8 @@ +tests/cases/conformance/es6/modules/importEmptyFromModuleNotExisted.ts(1,16): error TS2307: Cannot find module 'module-not-existed'. + + +==== tests/cases/conformance/es6/modules/importEmptyFromModuleNotExisted.ts (1 errors) ==== + import {} from 'module-not-existed' + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2307: Cannot find module 'module-not-existed'. + \ No newline at end of file diff --git a/tests/baselines/reference/importEmptyFromModuleNotExisted.js b/tests/baselines/reference/importEmptyFromModuleNotExisted.js new file mode 100644 index 00000000000..aa08db2e99e --- /dev/null +++ b/tests/baselines/reference/importEmptyFromModuleNotExisted.js @@ -0,0 +1,7 @@ +//// [importEmptyFromModuleNotExisted.ts] +import {} from 'module-not-existed' + + +//// [importEmptyFromModuleNotExisted.js] +"use strict"; +exports.__esModule = true; diff --git a/tests/baselines/reference/importEmptyFromModuleNotExisted.symbols b/tests/baselines/reference/importEmptyFromModuleNotExisted.symbols new file mode 100644 index 00000000000..ea0425ff26c --- /dev/null +++ b/tests/baselines/reference/importEmptyFromModuleNotExisted.symbols @@ -0,0 +1,4 @@ +=== tests/cases/conformance/es6/modules/importEmptyFromModuleNotExisted.ts === +import {} from 'module-not-existed' +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/importEmptyFromModuleNotExisted.types b/tests/baselines/reference/importEmptyFromModuleNotExisted.types new file mode 100644 index 00000000000..ea0425ff26c --- /dev/null +++ b/tests/baselines/reference/importEmptyFromModuleNotExisted.types @@ -0,0 +1,4 @@ +=== tests/cases/conformance/es6/modules/importEmptyFromModuleNotExisted.ts === +import {} from 'module-not-existed' +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/user/axios-src.log b/tests/baselines/reference/user/axios-src.log new file mode 100644 index 00000000000..ad8bc285bbb --- /dev/null +++ b/tests/baselines/reference/user/axios-src.log @@ -0,0 +1,44 @@ +Exit Code: 1 +Standard output: +lib/adapters/http.js(12,19): error TS2307: Cannot find module './../../package.json'. +lib/adapters/http.js(83,22): error TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'string'. + Type 'undefined' is not assignable to type 'string'. +lib/adapters/http.js(189,23): error TS2345: Argument of type 'null' is not assignable to parameter of type 'string | undefined'. +lib/adapters/http.js(195,44): error TS2345: Argument of type 'null' is not assignable to parameter of type 'string | undefined'. +lib/adapters/http.js(201,13): error TS2322: Type 'string' is not assignable to type 'Buffer'. +lib/adapters/http.js(213,40): error TS2345: Argument of type 'null' is not assignable to parameter of type 'string | undefined'. +lib/adapters/http.js(237,42): error TS2345: Argument of type 'null' is not assignable to parameter of type 'string | undefined'. +lib/adapters/xhr.js(29,16): error TS2339: Property 'XDomainRequest' does not exist on type 'Window'. +lib/adapters/xhr.js(31,28): error TS2339: Property 'XDomainRequest' does not exist on type 'Window'. +lib/adapters/xhr.js(80,7): error TS2322: Type 'null' is not assignable to type 'XMLHttpRequest'. +lib/adapters/xhr.js(92,7): error TS2322: Type 'null' is not assignable to type 'XMLHttpRequest'. +lib/adapters/xhr.js(99,51): error TS2345: Argument of type 'null' is not assignable to parameter of type 'string | undefined'. +lib/adapters/xhr.js(102,7): error TS2322: Type 'null' is not assignable to type 'XMLHttpRequest'. +lib/adapters/xhr.js(111,7): error TS2322: Type 'null' is not assignable to type 'XMLHttpRequest'. +lib/adapters/xhr.js(181,9): error TS2322: Type 'null' is not assignable to type 'XMLHttpRequest'. +lib/axios.js(23,3): error TS2554: Expected 3 arguments, but got 2. +lib/axios.js(25,3): error TS2322: Type '(...args: any[]) => any' is not assignable to type 'Axios'. + Property 'defaults' is missing in type '(...args: any[]) => any'. +lib/axios.js(32,7): error TS2339: Property 'Axios' does not exist on type 'Axios'. +lib/axios.js(35,7): error TS2339: Property 'create' does not exist on type 'Axios'. +lib/axios.js(40,7): error TS2339: Property 'Cancel' does not exist on type 'Axios'. +lib/axios.js(41,7): error TS2339: Property 'CancelToken' does not exist on type 'Axios'. +lib/axios.js(42,7): error TS2339: Property 'isCancel' does not exist on type 'Axios'. +lib/axios.js(45,7): error TS2339: Property 'all' does not exist on type 'Axios'. +lib/axios.js(48,7): error TS2339: Property 'spread' does not exist on type 'Axios'. +lib/cancel/CancelToken.js(37,12): error TS2339: Property 'reason' does not exist on type 'CancelToken'. +lib/cancel/CancelToken.js(38,16): error TS2339: Property 'reason' does not exist on type 'CancelToken'. +lib/core/enhanceError.js(14,9): error TS2339: Property 'config' does not exist on type 'Error'. +lib/core/enhanceError.js(16,11): error TS2339: Property 'code' does not exist on type 'Error'. +lib/core/enhanceError.js(18,9): error TS2339: Property 'request' does not exist on type 'Error'. +lib/core/enhanceError.js(19,9): error TS2339: Property 'response' does not exist on type 'Error'. +lib/core/settle.js(21,7): error TS2345: Argument of type 'null' is not assignable to parameter of type 'string | undefined'. +lib/helpers/btoa.js(11,13): error TS2339: Property 'code' does not exist on type 'Error'. +lib/helpers/btoa.js(31,13): error TS2532: Object is possibly 'undefined'. +lib/helpers/cookies.js(16,56): error TS2551: Property 'toGMTString' does not exist on type 'Date'. Did you mean 'toUTCString'? +lib/utils.js(244,20): error TS8029: JSDoc '@param' tag has name 'obj1', but there is no parameter with that name. It would match 'arguments' if it had an array type. +lib/utils.js(268,20): error TS8029: JSDoc '@param' tag has name 'obj1', but there is no parameter with that name. It would match 'arguments' if it had an array type. + + + +Standard error: diff --git a/tests/baselines/reference/user/create-react-app.log b/tests/baselines/reference/user/create-react-app.log new file mode 100644 index 00000000000..2fefa8b230e --- /dev/null +++ b/tests/baselines/reference/user/create-react-app.log @@ -0,0 +1,79 @@ +Exit Code: 1 +Standard output: +packages/babel-preset-react-app/dependencies.js(38,17): error TS2307: Cannot find module '@babel/preset-env'. +packages/babel-preset-react-app/dependencies.js(49,17): error TS2307: Cannot find module '@babel/preset-env'. +packages/babel-preset-react-app/index.js(52,17): error TS2307: Cannot find module '@babel/preset-env'. +packages/babel-preset-react-app/index.js(61,17): error TS2307: Cannot find module '@babel/preset-env'. +packages/babel-preset-react-app/index.js(74,17): error TS2307: Cannot find module '@babel/preset-react'. +packages/babel-preset-react-app/index.js(84,33): error TS2307: Cannot find module '@babel/preset-flow'. +packages/babel-preset-react-app/index.js(89,15): error TS2307: Cannot find module 'babel-plugin-macros'. +packages/babel-preset-react-app/index.js(93,15): error TS2307: Cannot find module '@babel/plugin-transform-destructuring'. +packages/babel-preset-react-app/index.js(98,17): error TS2307: Cannot find module '@babel/plugin-proposal-class-properties'. +packages/babel-preset-react-app/index.js(107,17): error TS2307: Cannot find module '@babel/plugin-proposal-object-rest-spread'. +packages/babel-preset-react-app/index.js(114,17): error TS2307: Cannot find module '@babel/plugin-transform-runtime'. +packages/babel-preset-react-app/index.js(123,17): error TS2307: Cannot find module 'babel-plugin-transform-react-remove-prop-types'. +packages/babel-preset-react-app/index.js(130,17): error TS2307: Cannot find module '@babel/plugin-transform-regenerator'. +packages/babel-preset-react-app/index.js(137,15): error TS2307: Cannot find module '@babel/plugin-syntax-dynamic-import'. +packages/babel-preset-react-app/index.js(140,17): error TS2307: Cannot find module 'babel-plugin-transform-dynamic-import'. +packages/confusing-browser-globals/test.js(14,1): error TS2304: Cannot find name 'it'. +packages/confusing-browser-globals/test.js(15,3): error TS2304: Cannot find name 'expect'. +packages/confusing-browser-globals/test.js(18,1): error TS2304: Cannot find name 'it'. +packages/confusing-browser-globals/test.js(19,3): error TS2304: Cannot find name 'expect'. +packages/create-react-app/createReactApp.js(37,37): error TS2307: Cannot find module 'validate-npm-package-name'. +packages/create-react-app/createReactApp.js(47,24): error TS2307: Cannot find module 'tar-pack'. +packages/create-react-app/createReactApp.js(49,28): error TS2307: Cannot find module 'hyperquest'. +packages/create-react-app/createReactApp.js(50,25): error TS2307: Cannot find module 'envinfo'. +packages/create-react-app/createReactApp.js(52,30): error TS2307: Cannot find module 'react-dev-utils/workspaceUtils'. +packages/create-react-app/createReactApp.js(53,29): error TS2307: Cannot find module './package.json'. +packages/create-react-app/createReactApp.js(771,20): error TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'string'. + Type 'undefined' is not assignable to type 'string'. +packages/create-react-app/index.js(45,5): error TS2365: Operator '<' cannot be applied to types 'string' and 'number'. +packages/eslint-config-react-app/index.js(24,33): error TS2307: Cannot find module 'confusing-browser-globals'. +packages/react-dev-utils/FileSizeReporter.js(13,24): error TS2307: Cannot find module 'filesize'. +packages/react-dev-utils/FileSizeReporter.js(14,25): error TS2307: Cannot find module 'recursive-readdir'. +packages/react-dev-utils/FileSizeReporter.js(16,24): error TS2307: Cannot find module 'gzip-size'. +packages/react-dev-utils/WebpackDevServerUtils.js(9,25): error TS2307: Cannot find module 'address'. +packages/react-dev-utils/WebpackDevServerUtils.js(14,24): error TS2307: Cannot find module 'detect-port-alt'. +packages/react-dev-utils/WebpackDevServerUtils.js(15,24): error TS2307: Cannot find module 'is-root'. +packages/react-dev-utils/__tests__/ignoredFiles.test.js(12,1): error TS2304: Cannot find name 'describe'. +packages/react-dev-utils/__tests__/ignoredFiles.test.js(13,3): error TS2304: Cannot find name 'it'. +packages/react-dev-utils/__tests__/ignoredFiles.test.js(18,5): error TS2304: Cannot find name 'expect'. +packages/react-dev-utils/__tests__/ignoredFiles.test.js(19,5): error TS2304: Cannot find name 'expect'. +packages/react-dev-utils/__tests__/ignoredFiles.test.js(22,3): error TS2304: Cannot find name 'it'. +packages/react-dev-utils/__tests__/ignoredFiles.test.js(26,5): error TS2304: Cannot find name 'expect'. +packages/react-dev-utils/__tests__/ignoredFiles.test.js(29,3): error TS2304: Cannot find name 'it'. +packages/react-dev-utils/__tests__/ignoredFiles.test.js(36,5): error TS2304: Cannot find name 'expect'. +packages/react-dev-utils/__tests__/ignoredFiles.test.js(37,5): error TS2304: Cannot find name 'expect'. +packages/react-dev-utils/__tests__/ignoredFiles.test.js(40,3): error TS2304: Cannot find name 'it'. +packages/react-dev-utils/__tests__/ignoredFiles.test.js(46,5): error TS2304: Cannot find name 'expect'. +packages/react-dev-utils/__tests__/ignoredFiles.test.js(49,3): error TS2304: Cannot find name 'it'. +packages/react-dev-utils/__tests__/ignoredFiles.test.js(53,5): error TS2304: Cannot find name 'expect'. +packages/react-dev-utils/browsersHelper.js(9,30): error TS2307: Cannot find module 'browserslist'. +packages/react-dev-utils/browsersHelper.js(13,23): error TS2307: Cannot find module 'pkg-up'. +packages/react-dev-utils/browsersHelper.js(59,22): error TS2554: Expected 1 arguments, but got 0. +packages/react-dev-utils/browsersHelper.js(61,36): error TS2345: Argument of type 'Buffer' is not assignable to parameter of type 'string'. +packages/react-dev-utils/browsersHelper.js(97,25): error TS2538: Type 'undefined' cannot be used as an index type. +packages/react-dev-utils/checkRequiredFiles.js(19,34): error TS2339: Property 'F_OK' does not exist on type 'typeof import("fs")'. +packages/react-dev-utils/checkRequiredFiles.js(23,32): error TS2345: Argument of type 'undefined' is not assignable to parameter of type 'string'. +packages/react-dev-utils/checkRequiredFiles.js(24,34): error TS2345: Argument of type 'undefined' is not assignable to parameter of type 'string'. +packages/react-dev-utils/getProcessForPort.js(29,6): error TS2339: Property 'split' does not exist on type 'Buffer'. +packages/react-dev-utils/getProcessForPort.js(49,21): error TS2339: Property 'replace' does not exist on type 'Buffer'. +packages/react-dev-utils/getProcessForPort.js(63,5): error TS2339: Property 'trim' does not exist on type 'Buffer'. +packages/react-dev-utils/openBrowser.js(13,19): error TS2307: Cannot find module 'opn'. +packages/react-dev-utils/webpackHotDevClient.js(19,22): error TS2307: Cannot find module 'sockjs-client'. +packages/react-dev-utils/webpackHotDevClient.js(24,28): error TS2307: Cannot find module 'react-error-overlay'. +packages/react-dev-utils/webpackHotDevClient.js(31,14): error TS2339: Property 'encodeURIComponent' does not exist on type 'Window'. +packages/react-dev-utils/webpackHotDevClient.js(33,14): error TS2339: Property 'encodeURIComponent' does not exist on type 'Window'. +packages/react-dev-utils/webpackHotDevClient.js(35,14): error TS2339: Property 'encodeURIComponent' does not exist on type 'Window'. +packages/react-dev-utils/webpackHotDevClient.js(53,12): error TS2339: Property 'hot' does not exist on type 'NodeModule'. +packages/react-dev-utils/webpackHotDevClient.js(53,33): error TS2339: Property 'hot' does not exist on type 'NodeModule'. +packages/react-dev-utils/webpackHotDevClient.js(54,10): error TS2339: Property 'hot' does not exist on type 'NodeModule'. +packages/react-dev-utils/webpackHotDevClient.js(223,40): error TS2304: Cannot find name '__webpack_hash__'. +packages/react-dev-utils/webpackHotDevClient.js(228,17): error TS2339: Property 'hot' does not exist on type 'NodeModule'. +packages/react-dev-utils/webpackHotDevClient.js(233,15): error TS2339: Property 'hot' does not exist on type 'NodeModule'. +packages/react-dev-utils/webpackHotDevClient.js(261,23): error TS2339: Property 'hot' does not exist on type 'NodeModule'. +packages/react-dev-utils/workspaceUtils.js(11,25): error TS2307: Cannot find module 'find-pkg'. + + + +Standard error: diff --git a/tests/baselines/reference/user/puppeteer.log b/tests/baselines/reference/user/puppeteer.log new file mode 100644 index 00000000000..b2a53a08dd3 --- /dev/null +++ b/tests/baselines/reference/user/puppeteer.log @@ -0,0 +1,40 @@ +Exit Code: 1 +Standard output: +lib/Coverage.js(109,15): error TS2503: Cannot find namespace 'Protocol'. +lib/Coverage.js(196,15): error TS2503: Cannot find namespace 'Protocol'. +lib/ElementHandle.js(24,15): error TS2503: Cannot find namespace 'Protocol'. +lib/ElementHandle.js(83,29): error TS2503: Cannot find namespace 'Protocol'. +lib/EmulationManager.js(36,16): error TS2503: Cannot find namespace 'Protocol'. +lib/ExecutionContext.js(22,15): error TS2503: Cannot find namespace 'Protocol'. +lib/ExecutionContext.js(132,15): error TS2503: Cannot find namespace 'Protocol'. +lib/FrameManager.js(28,15): error TS2503: Cannot find namespace 'Protocol'. +lib/FrameManager.js(54,15): error TS2503: Cannot find namespace 'Protocol'. +lib/FrameManager.js(76,15): error TS2503: Cannot find namespace 'Protocol'. +lib/FrameManager.js(127,15): error TS2503: Cannot find namespace 'Protocol'. +lib/FrameManager.js(773,15): error TS2503: Cannot find namespace 'Protocol'. +lib/NetworkManager.js(129,15): error TS2503: Cannot find namespace 'Protocol'. +lib/NetworkManager.js(174,15): error TS2503: Cannot find namespace 'Protocol'. +lib/NetworkManager.js(207,15): error TS2503: Cannot find namespace 'Protocol'. +lib/NetworkManager.js(224,15): error TS2503: Cannot find namespace 'Protocol'. +lib/NetworkManager.js(256,15): error TS2503: Cannot find namespace 'Protocol'. +lib/NetworkManager.js(270,15): error TS2503: Cannot find namespace 'Protocol'. +lib/NetworkManager.js(286,15): error TS2503: Cannot find namespace 'Protocol'. +lib/NetworkManager.js(313,15): error TS2503: Cannot find namespace 'Protocol'. +lib/NetworkManager.js(640,13): error TS2503: Cannot find namespace 'Protocol'. +lib/Page.js(66,15): error TS2503: Cannot find namespace 'Protocol'. +lib/Page.js(185,15): error TS2503: Cannot find namespace 'Protocol'. +lib/Page.js(394,22): error TS2503: Cannot find namespace 'Protocol'. +lib/Page.js(407,15): error TS2503: Cannot find namespace 'Protocol'. +lib/Page.js(731,19): error TS2503: Cannot find namespace 'Protocol'. +lib/externs.d.ts(16,26): error TS2503: Cannot find namespace 'Protocol'. +lib/externs.d.ts(16,69): error TS2503: Cannot find namespace 'Protocol'. +lib/externs.d.ts(17,28): error TS2503: Cannot find namespace 'Protocol'. +lib/externs.d.ts(17,81): error TS2503: Cannot find namespace 'Protocol'. +lib/externs.d.ts(17,121): error TS2503: Cannot find namespace 'Protocol'. +lib/helper.js(59,15): error TS2503: Cannot find namespace 'Protocol'. +lib/helper.js(77,15): error TS2503: Cannot find namespace 'Protocol'. +lib/helper.js(101,15): error TS2503: Cannot find namespace 'Protocol'. + + + +Standard error: diff --git a/tests/baselines/reference/user/uglify-js.log b/tests/baselines/reference/user/uglify-js.log index b467514604a..66a1267e755 100644 --- a/tests/baselines/reference/user/uglify-js.log +++ b/tests/baselines/reference/user/uglify-js.log @@ -6,65 +6,66 @@ node_modules/uglify-js/lib/ast.js(858,5): error TS2322: Type '{ [x: string]: any Object literal may only specify known properties, but '_visit' does not exist in type 'TreeWalker'. Did you mean to write 'visit'? node_modules/uglify-js/lib/compress.js(165,27): error TS2554: Expected 0 arguments, but got 1. node_modules/uglify-js/lib/compress.js(453,26): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(722,18): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(964,38): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. -node_modules/uglify-js/lib/compress.js(990,51): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'true | ((node: any) => any)' has no compatible call signatures. -node_modules/uglify-js/lib/compress.js(1074,53): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. -node_modules/uglify-js/lib/compress.js(1114,112): error TS2532: Object is possibly 'undefined'. -node_modules/uglify-js/lib/compress.js(1115,29): error TS2532: Object is possibly 'undefined'. -node_modules/uglify-js/lib/compress.js(1124,87): error TS2322: Type 'false' is not assignable to type 'number'. -node_modules/uglify-js/lib/compress.js(1132,29): error TS2322: Type 'false' is not assignable to type 'never'. -node_modules/uglify-js/lib/compress.js(1185,38): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(1278,38): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. -node_modules/uglify-js/lib/compress.js(1374,27): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(1406,26): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(1820,44): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(1998,19): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(2258,27): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(2998,23): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(3011,33): error TS2322: Type '"f"' is not assignable to type 'boolean'. -node_modules/uglify-js/lib/compress.js(3148,18): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(3158,33): error TS2339: Property 'add' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3162,32): error TS2339: Property 'add' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3168,40): error TS2339: Property 'add' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3177,41): error TS2339: Property 'add' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3194,14): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(3196,40): error TS2339: Property 'get' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3204,33): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. -node_modules/uglify-js/lib/compress.js(3278,63): error TS2339: Property 'get' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3467,23): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(3484,36): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. -node_modules/uglify-js/lib/compress.js(3490,38): error TS2339: Property 'set' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3494,40): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. -node_modules/uglify-js/lib/compress.js(3519,22): error TS2339: Property 'each' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3524,30): error TS2339: Property 'del' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3529,30): error TS2339: Property 'set' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3540,41): error TS2339: Property 'has' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3542,48): error TS2339: Property 'get' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3554,41): error TS2339: Property 'has' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3556,48): error TS2339: Property 'get' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3640,21): error TS2403: Subsequent variable declarations must have the same type. Variable 'defs' must be of type 'Dictionary', but here has type 'any'. -node_modules/uglify-js/lib/compress.js(3642,36): error TS2339: Property 'get' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3659,22): error TS2339: Property 'set' does not exist on type 'Dictionary'. -node_modules/uglify-js/lib/compress.js(3679,17): error TS2447: The '|=' operator is not allowed for boolean types. Consider using '||' instead. -node_modules/uglify-js/lib/compress.js(3704,30): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(3855,22): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(4133,17): error TS2403: Subsequent variable declarations must have the same type. Variable 'body' must be of type 'any[]', but here has type 'any'. -node_modules/uglify-js/lib/compress.js(4217,22): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(4545,30): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(4552,25): error TS2403: Subsequent variable declarations must have the same type. Variable 'code' must be of type 'string', but here has type '{ [x: string]: any; get: () => string; toString: () => string; indent: () => void; indentation: (...'. -node_modules/uglify-js/lib/compress.js(4556,36): error TS2532: Object is possibly 'undefined'. -node_modules/uglify-js/lib/compress.js(4561,41): error TS2339: Property 'get' does not exist on type 'string'. -node_modules/uglify-js/lib/compress.js(5040,18): error TS2454: Variable 'is_strict_comparison' is used before being assigned. -node_modules/uglify-js/lib/compress.js(5505,32): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(5565,24): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(5637,24): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(5643,26): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(5993,43): error TS2454: Variable 'property' is used before being assigned. -node_modules/uglify-js/lib/compress.js(6007,25): error TS2403: Subsequent variable declarations must have the same type. Variable 'value' must be of type 'number', but here has type 'any'. -node_modules/uglify-js/lib/compress.js(6010,46): error TS2339: Property 'has_side_effects' does not exist on type 'number'. -node_modules/uglify-js/lib/compress.js(6017,25): error TS2403: Subsequent variable declarations must have the same type. Variable 'value' must be of type 'number', but here has type 'any'. -node_modules/uglify-js/lib/compress.js(6070,19): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(734,18): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(976,38): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. +node_modules/uglify-js/lib/compress.js(1002,51): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'true | ((node: any) => any)' has no compatible call signatures. +node_modules/uglify-js/lib/compress.js(1086,53): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. +node_modules/uglify-js/lib/compress.js(1126,112): error TS2532: Object is possibly 'undefined'. +node_modules/uglify-js/lib/compress.js(1127,29): error TS2532: Object is possibly 'undefined'. +node_modules/uglify-js/lib/compress.js(1136,87): error TS2322: Type 'false' is not assignable to type 'number'. +node_modules/uglify-js/lib/compress.js(1144,29): error TS2322: Type 'false' is not assignable to type 'never'. +node_modules/uglify-js/lib/compress.js(1197,38): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(1290,38): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. +node_modules/uglify-js/lib/compress.js(1386,27): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(1418,26): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(1832,44): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(2024,19): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(2284,27): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(3024,23): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(3037,33): error TS2322: Type '"f"' is not assignable to type 'boolean'. +node_modules/uglify-js/lib/compress.js(3174,18): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(3184,33): error TS2339: Property 'add' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3188,32): error TS2339: Property 'add' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3194,40): error TS2339: Property 'add' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3203,41): error TS2339: Property 'add' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3220,14): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(3222,40): error TS2339: Property 'get' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3230,33): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. +node_modules/uglify-js/lib/compress.js(3304,63): error TS2339: Property 'get' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3493,23): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(3510,36): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. +node_modules/uglify-js/lib/compress.js(3516,38): error TS2339: Property 'set' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3520,40): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. +node_modules/uglify-js/lib/compress.js(3545,22): error TS2339: Property 'each' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3550,30): error TS2339: Property 'del' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3555,30): error TS2339: Property 'set' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3566,41): error TS2339: Property 'has' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3568,48): error TS2339: Property 'get' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3580,41): error TS2339: Property 'has' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3582,48): error TS2339: Property 'get' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3688,21): error TS2403: Subsequent variable declarations must have the same type. Variable 'defs' must be of type 'Dictionary', but here has type 'any'. +node_modules/uglify-js/lib/compress.js(3690,36): error TS2339: Property 'get' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3719,22): error TS2339: Property 'set' does not exist on type 'Dictionary'. +node_modules/uglify-js/lib/compress.js(3739,17): error TS2447: The '|=' operator is not allowed for boolean types. Consider using '||' instead. +node_modules/uglify-js/lib/compress.js(3764,30): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(3902,18): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(4201,17): error TS2403: Subsequent variable declarations must have the same type. Variable 'body' must be of type 'any[]', but here has type 'any'. +node_modules/uglify-js/lib/compress.js(4285,22): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(4613,30): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(4620,25): error TS2403: Subsequent variable declarations must have the same type. Variable 'code' must be of type 'string', but here has type '{ [x: string]: any; get: () => string; toString: () => string; indent: () => void; indentation: (...'. +node_modules/uglify-js/lib/compress.js(4624,36): error TS2532: Object is possibly 'undefined'. +node_modules/uglify-js/lib/compress.js(4629,41): error TS2339: Property 'get' does not exist on type 'string'. +node_modules/uglify-js/lib/compress.js(5114,18): error TS2454: Variable 'is_strict_comparison' is used before being assigned. +node_modules/uglify-js/lib/compress.js(5553,25): error TS2365: Operator '==' cannot be applied to types 'boolean' and '"f"'. +node_modules/uglify-js/lib/compress.js(5580,32): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(5640,24): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(5712,24): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(5718,26): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(6068,43): error TS2454: Variable 'property' is used before being assigned. +node_modules/uglify-js/lib/compress.js(6082,25): error TS2403: Subsequent variable declarations must have the same type. Variable 'value' must be of type 'number', but here has type 'any'. +node_modules/uglify-js/lib/compress.js(6085,46): error TS2339: Property 'has_side_effects' does not exist on type 'number'. +node_modules/uglify-js/lib/compress.js(6092,25): error TS2403: Subsequent variable declarations must have the same type. Variable 'value' must be of type 'number', but here has type 'any'. +node_modules/uglify-js/lib/compress.js(6145,19): error TS2554: Expected 0 arguments, but got 1. node_modules/uglify-js/lib/minify.js(166,75): error TS2339: Property 'compress' does not exist on type 'Compressor'. node_modules/uglify-js/lib/mozilla-ast.js(569,18): error TS2554: Expected 0 arguments, but got 1. node_modules/uglify-js/lib/output.js(473,22): error TS2554: Expected 0 arguments, but got 1. diff --git a/tests/cases/conformance/es6/modules/importEmptyFromModuleNotExisted.ts b/tests/cases/conformance/es6/modules/importEmptyFromModuleNotExisted.ts new file mode 100644 index 00000000000..36bca3e9619 --- /dev/null +++ b/tests/cases/conformance/es6/modules/importEmptyFromModuleNotExisted.ts @@ -0,0 +1 @@ +import {} from 'module-not-existed' diff --git a/tests/cases/fourslash/convertFunctionToEs6Class_commentOnVariableDeclaration.ts b/tests/cases/fourslash/convertFunctionToEs6Class_commentOnVariableDeclaration.ts new file mode 100644 index 00000000000..417bf0bc905 --- /dev/null +++ b/tests/cases/fourslash/convertFunctionToEs6Class_commentOnVariableDeclaration.ts @@ -0,0 +1,16 @@ +/// + +// @allowJs: true +// @Filename: /a.js +/////** Doc */ +////const C = function() { this.x = 0; } + +verify.codeFix({ + description: "Convert function to an ES2015 class", + newFileContent: +`/** Doc */ +class C { + constructor() { this.x = 0; } +} +`, +}); diff --git a/tests/cases/fourslash/documentHighlights_windowsPath.ts b/tests/cases/fourslash/documentHighlights_windowsPath.ts new file mode 100644 index 00000000000..594f175745b --- /dev/null +++ b/tests/cases/fourslash/documentHighlights_windowsPath.ts @@ -0,0 +1,7 @@ +/// + +//@Filename: C:\a\b\c.ts +////var /*1*/[|x|] = 1; + +const range = test.ranges()[0]; +verify.documentHighlightsOf(range, [range], { filesToSearch: [range.fileName] }); \ No newline at end of file diff --git a/tests/cases/fourslash/findAllReferencesDynamicImport3.ts b/tests/cases/fourslash/findAllReferencesDynamicImport3.ts index 21d2e1097db..636e640ceb3 100644 --- a/tests/cases/fourslash/findAllReferencesDynamicImport3.ts +++ b/tests/cases/fourslash/findAllReferencesDynamicImport3.ts @@ -1,13 +1,13 @@ /// // @Filename: foo.ts -//// export function [|bar|]() { return "bar"; } - -//// import('./foo').then(({ [|bar|] }) => undefined); +////export function [|{| "isWriteAccess": true, "isDefinition": true |}bar|]() { return "bar"; } +////import('./foo').then(({ [|{| "isWriteAccess": true, "isDefinition": true |}bar|] }) => undefined); const [r0, r1] = test.ranges(); -// This is because bindingElement at r1 are both name and value -verify.referencesOf(r0, [r1, r0, r1, r0]); -verify.referencesOf(r1, [r0, r1, r1, r0]); -verify.renameLocations(r0, [r0, r1]); -verify.renameLocations(r1, [r1, r0, r0, r1]); \ No newline at end of file +verify.referenceGroups(r0, [{ definition: "function bar(): string", ranges: [r0, r1] }]); +verify.referenceGroups(r1, [ + { definition: "function bar(): string", ranges: [r0] }, + { definition: "var bar: () => string", ranges: [r1] }, +]); +verify.rangesAreRenameLocations(); diff --git a/tests/cases/fourslash/findAllRefsForObjectSpread.ts b/tests/cases/fourslash/findAllRefsForObjectSpread.ts index 970806922ed..c6f111672c8 100644 --- a/tests/cases/fourslash/findAllRefsForObjectSpread.ts +++ b/tests/cases/fourslash/findAllRefsForObjectSpread.ts @@ -12,12 +12,12 @@ const [r0, r1, r2, r3] = ranges; // members of spread types only refer to themselves and the resulting property verify.referenceGroups(r0, [{ definition: "(property) A1.a: string", ranges: [r0, r2, r3] }]); -verify.referenceGroups(r1, [{ definition: "(property) A2.a: number", ranges: [r1, r2] }]); +verify.referenceGroups(r1, [{ definition: "(property) A2.a?: number", ranges: [r1, r2] }]); // but the resulting property refers to everything verify.referenceGroups(r2, [ { definition: "(property) A1.a: string", ranges: [r0, r2, r3] }, - { definition: "(property) A2.a: number", ranges: [r1] }, + { definition: "(property) A2.a?: number", ranges: [r1] }, ]); verify.referenceGroups(r3, [{ definition: "(property) A1.a: string", ranges: [r0, r2, r3] }]); diff --git a/tests/cases/fourslash/findAllRefsObjectBindingElementPropertyName10.ts b/tests/cases/fourslash/findAllRefsObjectBindingElementPropertyName10.ts index 1c79d326dbc..500ca7fe3cf 100644 --- a/tests/cases/fourslash/findAllRefsObjectBindingElementPropertyName10.ts +++ b/tests/cases/fourslash/findAllRefsObjectBindingElementPropertyName10.ts @@ -8,4 +8,4 @@ ////function f ({ [|next|]: { [|next|]: x} }: Recursive) { ////} -verify.singleReferenceGroup("(property) Recursive.next: Recursive"); +verify.singleReferenceGroup("(property) Recursive.next?: Recursive"); diff --git a/tests/cases/fourslash/findAllRefsTypeofImport.ts b/tests/cases/fourslash/findAllRefsTypeofImport.ts new file mode 100644 index 00000000000..77bd2d51a8c --- /dev/null +++ b/tests/cases/fourslash/findAllRefsTypeofImport.ts @@ -0,0 +1,8 @@ +/// + +// @Filename: /a.ts +////export const [|{| "isWriteAccess": true, "isDefinition": true |}x|] = 0; +////declare const a: typeof import("./a"); +////a.[|x|]; + +verify.singleReferenceGroup("const x: 0"); diff --git a/tests/cases/fourslash/getOutliningSpansDepthElseIf.ts b/tests/cases/fourslash/getOutliningSpansDepthElseIf.ts new file mode 100644 index 00000000000..1e349e5b190 --- /dev/null +++ b/tests/cases/fourslash/getOutliningSpansDepthElseIf.ts @@ -0,0 +1,89 @@ +/// + +// Tests that each 'else if' does not count towards a higher nesting depth. + +////if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else if (1)[| { +//// 1; +////}|] else[| { +//// 1; +////}|] + +verify.outliningSpansInCurrentFile(test.ranges()); diff --git a/tests/cases/fourslash/quickInfoForObjectBindingElementPropertyName03.ts b/tests/cases/fourslash/quickInfoForObjectBindingElementPropertyName03.ts index c29a7265eab..9378c99126c 100644 --- a/tests/cases/fourslash/quickInfoForObjectBindingElementPropertyName03.ts +++ b/tests/cases/fourslash/quickInfoForObjectBindingElementPropertyName03.ts @@ -9,5 +9,5 @@ ////} for (const marker of test.markerNames()) { - verify.quickInfoAt(marker, "(property) Recursive.next: Recursive"); + verify.quickInfoAt(marker, "(property) Recursive.next?: Recursive"); } \ No newline at end of file diff --git a/tests/cases/fourslash/server/quickInfoMappedSpreadTypes.ts b/tests/cases/fourslash/quickInfoMappedSpreadTypes.ts similarity index 89% rename from tests/cases/fourslash/server/quickInfoMappedSpreadTypes.ts rename to tests/cases/fourslash/quickInfoMappedSpreadTypes.ts index 2a0c1668763..c1e34f49bfc 100644 --- a/tests/cases/fourslash/server/quickInfoMappedSpreadTypes.ts +++ b/tests/cases/fourslash/quickInfoMappedSpreadTypes.ts @@ -1,4 +1,4 @@ -/// +/// ////interface Foo { //// /** Doc */ diff --git a/tests/cases/fourslash/quickInfoMappedType.ts b/tests/cases/fourslash/quickInfoMappedType.ts new file mode 100644 index 00000000000..c4afb444155 --- /dev/null +++ b/tests/cases/fourslash/quickInfoMappedType.ts @@ -0,0 +1,11 @@ +/// + +////interface I { m(): void; } +////declare const o: { [K in keyof I]: number }; +////o.m/*0*/; +//// +////declare const p: { [K in keyof I]: I[K] }; +////p.m/*1*/; + +verify.quickInfoAt("0", "(property) m: number"); +verify.quickInfoAt("1", "(method) m(): void"); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_export_named.ts b/tests/cases/fourslash/refactorConvertToEs6Module_export_named.ts index 60d2436ddb0..a748b9844a6 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_export_named.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_export_named.ts @@ -3,7 +3,7 @@ // @allowJs: true // @Filename: /a.js -////[|exports.f = function() {}|]; +////[|exports.f|] = function() {}; ////exports.C = class {}; ////exports.x = 0; ////exports.a1 = () => {}; diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_missingInitializer.ts b/tests/cases/fourslash/refactorConvertToEs6Module_missingInitializer.ts new file mode 100644 index 00000000000..77c4ce0fc43 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToEs6Module_missingInitializer.ts @@ -0,0 +1,14 @@ +/// + +// @allowJs: true + +// @Filename: /a.js +////require("m"); +////let x; x; + +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: +`import "m"; +let x; x;` +}); diff --git a/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter b/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter index 6b9706810b5..40bdb4eadab 160000 --- a/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter +++ b/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter @@ -1 +1 @@ -Subproject commit 6b9706810b55af326a93b9aa59cb17815a30bb32 +Subproject commit 40bdb4eadabc9fbed7d83e3f26817a931c0763b6 diff --git a/tests/cases/user/axios-src/axios-src b/tests/cases/user/axios-src/axios-src new file mode 160000 index 00000000000..0b3db5d87a6 --- /dev/null +++ b/tests/cases/user/axios-src/axios-src @@ -0,0 +1 @@ +Subproject commit 0b3db5d87a60a1ad8b0dce9669dbc10483ec33da diff --git a/tests/cases/user/axios-src/test.json b/tests/cases/user/axios-src/test.json new file mode 100644 index 00000000000..b6495a1b80b --- /dev/null +++ b/tests/cases/user/axios-src/test.json @@ -0,0 +1,3 @@ +{ + "types": ["node"] +} diff --git a/tests/cases/user/axios-src/tsconfig.json b/tests/cases/user/axios-src/tsconfig.json new file mode 100644 index 00000000000..ef3f63dc126 --- /dev/null +++ b/tests/cases/user/axios-src/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "noImplicitAny": false, + "noImplicitThis": false, + "maxNodeModuleJsDepth": 0, + "strict": true, + "noEmit": true, + "allowJs": true, + "checkJs": true, + "types": ["node"], + "lib": ["esnext", "dom"], + }, + "include": ["axios-src/lib"] +} diff --git a/tests/cases/user/create-react-app/chalk-override.d.ts b/tests/cases/user/create-react-app/chalk-override.d.ts new file mode 100644 index 00000000000..5adfd6d3cfb --- /dev/null +++ b/tests/cases/user/create-react-app/chalk-override.d.ts @@ -0,0 +1 @@ +declare module 'chalk'; diff --git a/tests/cases/user/create-react-app/create-react-app b/tests/cases/user/create-react-app/create-react-app new file mode 160000 index 00000000000..1d4fdc2dd49 --- /dev/null +++ b/tests/cases/user/create-react-app/create-react-app @@ -0,0 +1 @@ +Subproject commit 1d4fdc2dd4950011beacf1883900bf5d8da7079e diff --git a/tests/cases/user/create-react-app/test.json b/tests/cases/user/create-react-app/test.json new file mode 100644 index 00000000000..e0d4d26bdca --- /dev/null +++ b/tests/cases/user/create-react-app/test.json @@ -0,0 +1,3 @@ +{ + "types": [] +} diff --git a/tests/cases/user/create-react-app/tsconfig.json b/tests/cases/user/create-react-app/tsconfig.json new file mode 100644 index 00000000000..0bb5948b878 --- /dev/null +++ b/tests/cases/user/create-react-app/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "noImplicitAny": false, + "noImplicitThis": false, + "maxNodeModuleJsDepth": 0, + "strict": true, + "noEmit": true, + "allowJs": true, + "checkJs": true, + "types": ["node"], + "lib": ["esnext", "dom"], + "baseUrl": "./", + "paths": { + "chalk": ["chalk-override"] + } + }, + "include": ["create-react-app"], + "exclude": ["create-react-app/packages/react-error-overlay", + "create-react-app/packages/react-scripts"] +} diff --git a/tests/cases/user/puppeteer/puppeteer b/tests/cases/user/puppeteer/puppeteer new file mode 160000 index 00000000000..98bb2615adb --- /dev/null +++ b/tests/cases/user/puppeteer/puppeteer @@ -0,0 +1 @@ +Subproject commit 98bb2615adb6815c91efcc59593b49e2ec8c3935 diff --git a/tests/cases/user/puppeteer/test.json b/tests/cases/user/puppeteer/test.json new file mode 100644 index 00000000000..e0d4d26bdca --- /dev/null +++ b/tests/cases/user/puppeteer/test.json @@ -0,0 +1,3 @@ +{ + "types": [] +}