diff --git a/.travis.yml b/.travis.yml index b35dabcbb5f..2124f3ada33 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,6 @@ node_js: - '10' - '8' -sudo: false - env: - workerCount=3 timeout=600000 diff --git a/Gulpfile.js b/Gulpfile.js index c4dd5d737e5..6e379ff41d2 100644 --- a/Gulpfile.js +++ b/Gulpfile.js @@ -12,10 +12,9 @@ const merge2 = require("merge2"); const mkdirp = require("mkdirp"); const { src, dest, task, parallel, series, watch } = require("gulp"); const { append, transform } = require("gulp-insert"); -const { browserify } = require("./scripts/build/browserify"); const { prependFile } = require("./scripts/build/prepend"); const { exec, readJson, needsUpdate, getDiffTool, getDirSize, rm } = require("./scripts/build/utils"); -const { runConsoleTests, cleanTestDirs, writeTestConfigFile, refBaseline, localBaseline, refRwcBaseline, localRwcBaseline } = require("./scripts/build/tests"); +const { runConsoleTests, refBaseline, localBaseline, refRwcBaseline, localRwcBaseline } = require("./scripts/build/tests"); const { buildProject, cleanProject, watchProject } = require("./scripts/build/projects"); const cmdLineOptions = require("./scripts/build/options"); @@ -432,44 +431,6 @@ task("runtests-parallel").flags = { " --built": "Compile using the built version of the compiler.", }; -const buildWebTestServer = () => buildProject("tests/webTestServer.tsconfig.json"); -const cleanWebTestServer = () => cleanProject("tests/webTestServer.tsconfig.json"); -cleanTasks.push(cleanWebTestServer); - -const browserifyTests = () => src(["built/local/run.js"], { base: "built/local" }) - .pipe(newer("built/local/bundle.js")) - .pipe(sourcemaps.init({ loadMaps: true })) - .pipe(browserify()) - .pipe(rename("bundle.js")) - .pipe(sourcemaps.write(".", /**@type {*}*/({ includeContent: false, destPath: "built/local" }))) - .pipe(dest("built/local")); - -const runtestsBrowser = async () => { - await cleanTestDirs(); - const { tests, runners, light } = cmdLineOptions; - const testConfigFile = "test.config"; - await del([testConfigFile]); - if (tests || runners || light) { - writeTestConfigFile(tests, runners, light); - } - const args = ["tests/webTestServer.js"]; - if (cmdLineOptions.browser) { - args.push(cmdLineOptions.browser); - } - if (tests) { - args.push(JSON.stringify(tests)); - } - await exec(process.execPath, args); -}; - -task("runtests-browser", series(preBuild, parallel(buildTests, buildServices, buildLssl, buildWebTestServer), browserifyTests, runtestsBrowser)); -task("runtests-browser").description = "Runs the tests using the built run.js file like 'gulp runtests'."; -task("runtests-browser").flags = { - "-t --tests=": "pattern for tests to run", - "-b --browser=": "Either 'IE' or 'chrome'", - " --built": "Compile using the built version of the compiler.", -}; - task("diff", () => exec(getDiffTool(), [refBaseline, localBaseline], { ignoreExitCode: true })); task("diff").description = "Diffs the compiler baselines using the diff tool specified by the 'DIFF' environment variable"; @@ -503,16 +464,6 @@ cleanTasks.push(cleanWebHost); task("clean-webhost", cleanWebHost); task("clean-webhost").description = "Cleans the outputs of the tsc web host"; -// TODO(rbuckton): Determine if 'perftsc' is still in use. -const buildPerfTsc = () => buildProject("tests/perftsc.tsconfig.json"); -task("perftsc", series(lkgPreBuild, buildPerfTsc)); -task("perftsc").description = "Builds augmented version of the compiler for perf tests"; - -const cleanPerfTsc = () => cleanProject("tests/perftsc.tsconfig.json"); -cleanTasks.push(cleanPerfTsc); -task("clean-perftsc", cleanPerfTsc); -task("clean-perftsc").description = "Cleans the outputs of the perftsc project"; - const buildLoggedIO = async () => { mkdirp.sync("built/local/temp"); await exec(process.execPath, ["lib/tsc", "--types", "--target", "es5", "--lib", "es5", "--outdir", "built/local/temp", "src/harness/loggedIO.ts"]); diff --git a/scripts/browserify-optional.js b/scripts/browserify-optional.js deleted file mode 100644 index 43997c7803c..00000000000 --- a/scripts/browserify-optional.js +++ /dev/null @@ -1,24 +0,0 @@ -// simple script to optionally elide source-map-support (or other optional modules) when running browserify. - -var stream = require("stream"), - Transform = stream.Transform, - resolve = require("browser-resolve"); - -var requirePattern = /require\s*\(\s*['"](source-map-support)['"]\s*\)/; -module.exports = function (file) { - return new Transform({ - transform: function (data, encoding, cb) { - var text = encoding === "buffer" ? data.toString("utf8") : data; - this.push(new Buffer(text.replace(requirePattern, function (originalText, moduleName) { - try { - resolve.sync(moduleName, { filename: file }); - return originalText; - } - catch (e) { - return "(function () { throw new Error(\"module '" + moduleName + "' not found.\"); })()"; - } - }), "utf8")); - cb(); - } - }); -}; \ No newline at end of file diff --git a/scripts/build/browserify.js b/scripts/build/browserify.js deleted file mode 100644 index ba8ccd15824..00000000000 --- a/scripts/build/browserify.js +++ /dev/null @@ -1,33 +0,0 @@ -// @ts-check -const browserify = require("browserify"); -const Vinyl = require("vinyl"); -const { Transform } = require("stream"); -const { streamFromFile } = require("./utils"); -const { replaceContents } = require("./sourcemaps"); - -/** - * @param {import("browserify").Options} [opts] - */ -function browserifyFile(opts) { - return new Transform({ - objectMode: true, - /** - * @param {string | Buffer | Vinyl} input - */ - transform(input, _, cb) { - if (typeof input === "string" || Buffer.isBuffer(input)) return cb(new Error("Only Vinyl files are supported.")); - try { - browserify(Object.assign({}, opts, { debug: !!input.sourceMap, basedir: input.base })) - .add(streamFromFile(input), { file: input.path, basedir: input.base }) - .bundle((err, contents) => { - if (err) return cb(err); - cb(null, replaceContents(input, contents)); - }); - } - catch (e) { - cb(e); - } - } - }); -} -exports.browserify = browserifyFile; \ No newline at end of file diff --git a/scripts/build/sourcemaps.js b/scripts/build/sourcemaps.js index 2c85b897b09..24c13b941c9 100644 --- a/scripts/build/sourcemaps.js +++ b/scripts/build/sourcemaps.js @@ -1,102 +1,4 @@ // @ts-check -/// - -const path = require("path"); -const convertMap = require("convert-source-map"); -const applySourceMap = require("vinyl-sourcemaps-apply"); -const through2 = require("through2"); - -/** - * @param {import("vinyl")} input - * @param {string | Buffer} contents - * @param {string | RawSourceMap} [sourceMap] - */ -function replaceContents(input, contents, sourceMap) { - const output = input.clone(); - output.contents = typeof contents === "string" ? Buffer.from(contents, "utf8") : contents; - if (input.sourceMap) { - output.sourceMap = typeof input.sourceMap === "string" ? /**@type {RawSourceMap}*/(JSON.parse(input.sourceMap)) : input.sourceMap; - if (typeof sourceMap === "string") { - sourceMap = /** @type {RawSourceMap} */(JSON.parse(sourceMap)); - } - else if (sourceMap === undefined) { - const stringContents = typeof contents === "string" ? contents : contents.toString("utf8"); - const newSourceMapConverter = convertMap.fromSource(stringContents); - if (newSourceMapConverter) { - sourceMap = /** @type {RawSourceMap} */(newSourceMapConverter.toObject()); - output.contents = new Buffer(convertMap.removeMapFileComments(stringContents), "utf8"); - } - } - if (sourceMap) { - const cwd = input.cwd || process.cwd(); - const base = input.base || cwd; - const sourceRoot = output.sourceMap.sourceRoot; - makeAbsoluteSourceMap(cwd, base, output.sourceMap); - makeAbsoluteSourceMap(cwd, base, /** @type {RawSourceMap} */(sourceMap)); - applySourceMap(output, sourceMap); - makeRelativeSourceMap(cwd, base, sourceRoot, output.sourceMap); - } - else { - output.sourceMap = undefined; - } - } - return output; -} -exports.replaceContents = replaceContents; - -function removeSourceMaps() { - return through2.obj((/**@type {import("vinyl")}*/file, _, cb) => { - if (file.isBuffer()) { - file.contents = Buffer.from(convertMap.removeMapFileComments(file.contents.toString("utf8")), "utf8"); - if (file.sourceMap) { - file.sourceMap = undefined; - } - } - cb(null, file); - }); -} -exports.removeSourceMaps = removeSourceMaps; - -/** - * @param {string | undefined} cwd - * @param {string | undefined} base - * @param {RawSourceMap} sourceMap - * - * @typedef {object} RawSourceMap - * @property {string} version - * @property {string} file - * @property {string} [sourceRoot] - * @property {string[]} sources - * @property {string[]} [sourcesContent] - * @property {string} mappings - * @property {string[]} [names] - */ -function makeAbsoluteSourceMap(cwd = process.cwd(), base = "", sourceMap) { - const sourceRoot = sourceMap.sourceRoot || ""; - const resolvedBase = path.resolve(cwd, base); - const resolvedSourceRoot = path.resolve(resolvedBase, sourceRoot); - sourceMap.file = path.resolve(resolvedBase, sourceMap.file).replace(/\\/g, "/"); - sourceMap.sources = sourceMap.sources.map(source => path.resolve(resolvedSourceRoot, source).replace(/\\/g, "/")); - sourceMap.sourceRoot = ""; -} -exports.makeAbsoluteSourceMap = makeAbsoluteSourceMap; - -/** - * @param {string | undefined} cwd - * @param {string | undefined} base - * @param {string} sourceRoot - * @param {RawSourceMap} sourceMap - */ -function makeRelativeSourceMap(cwd = process.cwd(), base = "", sourceRoot, sourceMap) { - makeAbsoluteSourceMap(cwd, base, sourceMap); - const resolvedBase = path.resolve(cwd, base); - const resolvedSourceRoot = path.resolve(resolvedBase, sourceRoot); - sourceMap.file = path.relative(resolvedBase, sourceMap.file).replace(/\\/g, "/"); - sourceMap.sources = sourceMap.sources.map(source => path.relative(resolvedSourceRoot, source).replace(/\\/g, "/")); - sourceMap.sourceRoot = sourceRoot; -} -exports.makeRelativeSourceMap = makeRelativeSourceMap; - /** * @param {string} message * @returns {never} diff --git a/scripts/createBenchmark.ts b/scripts/createBenchmark.ts deleted file mode 100644 index 254c0d99af0..00000000000 --- a/scripts/createBenchmark.ts +++ /dev/null @@ -1,124 +0,0 @@ -/// -/// - -import * as fs from "fs"; -import * as path from "path"; -import * as typescript from "typescript"; -declare var ts: typeof typescript; - -var tsSourceDir = "../src"; -var tsBuildDir = "../built/local"; -var testOutputDir = "../built/benchmark"; -var sourceFiles = [ - "compiler/types.ts", - "compiler/core.ts", - "compiler/sys.ts", - "compiler/diagnosticInformationMap.generated.ts", - "compiler/scanner.ts", - "compiler/binder.ts", - "compiler/utilities.ts", - "compiler/parser.ts", - "compiler/checker.ts", - "compiler/declarationEmitter.ts", - "compiler/emitter.ts", - "compiler/program.ts", - "compiler/commandLineParser.ts", - "compiler/tsc.ts"]; - -// .ts sources for the compiler, used as a test input -var rawCompilerSources = ""; -sourceFiles.forEach(f=> { - rawCompilerSources += "\r\n" + fs.readFileSync(path.join(tsSourceDir, f)).toString(); -}); -var compilerSources = `var compilerSources = ${JSON.stringify(rawCompilerSources) };`; - -// .js code for the compiler, what we are actually testing -var rawCompilerJavaScript = fs.readFileSync(path.join(tsBuildDir, "tsc.js")).toString(); -rawCompilerJavaScript = rawCompilerJavaScript.replace("ts.executeCommandLine(ts.sys.args);", ""); - -// lib.d.ts sources -var rawLibSources = fs.readFileSync(path.join(tsBuildDir, "lib.d.ts")).toString(); -var libSources = `var libSources = ${JSON.stringify(rawLibSources) };`; - -// write test output -if (!fs.existsSync(testOutputDir)) { - fs.mkdirSync(testOutputDir); -} - -// 1. compiler ts sources, used to test -fs.writeFileSync( - path.join(testOutputDir, "compilerSources.js"), - `${ compilerSources } \r\n ${ libSources }`); - -// 2. the compiler js sources + a call the compiler -fs.writeFileSync( - path.join(testOutputDir, "benchmarktsc.js"), - `${ rawCompilerJavaScript }\r\n${ compile.toString() }\r\ncompile(compilerSources, libSources);`); - -// 3. test html file to drive the test -fs.writeFileSync( - path.join(testOutputDir, "benchmarktsc.html"), - ` - - - - Typescript 1.1 Compiler - - - -
Status: Running
-
End-to-End Time: N/A
- - - - - -`); - -function compile(compilerSources, librarySources) { - var program = ts.createProgram( - ["lib.d.ts", "compiler.ts"], - { - noResolve: true, - out: "compiler.js", - removeComments: true, - target: ts.ScriptTarget.ES3 - }, { - getDefaultLibFileName: () => "lib.d.ts", - getSourceFile: (filename, languageVersion) => { - var source: string; - if (filename === "lib.d.ts") source = librarySources; - else if (filename === "compiler.ts") source = compilerSources; - else console.error("Unexpected read file request: " + filename); - - return ts.createSourceFile(filename, source, languageVersion); - }, - writeFile: (filename, data, writeByteOrderMark) => { - if (filename !== "compiler.js") - console.error("Unexpected write file request: " + filename); - // console.log(data); - }, - getCurrentDirectory: () => "", - getCanonicalFileName: (filename) => filename, - useCaseSensitiveFileNames: () => false, - getNewLine: () => "\r\n" - }); - - var emitOutput = program.emit(); - - var errors = program.getSyntacticDiagnostics() - .concat(program.getSemanticDiagnostics()) - .concat(program.getGlobalDiagnostics()) - .concat(emitOutput.diagnostics); - - if (errors.length) { - console.error("Unexpected errors."); - errors.forEach(e=> console.log(`${e.code}: ${e.messageText}`)) - } -} diff --git a/scripts/ior.ts b/scripts/ior.ts deleted file mode 100644 index 374747d8439..00000000000 --- a/scripts/ior.ts +++ /dev/null @@ -1,125 +0,0 @@ -/// - -import fs = require('fs'); -import path = require('path'); - -interface IOLog { - filesRead: { - path: string; - result: { contents: string; }; - }[]; - arguments: string[]; -} - -module Commands { - export function dir(obj: IOLog) { - obj.filesRead.filter(f => f.result !== undefined).forEach(f => { - console.log(f.path); - }); - } - dir['description'] = ': displays a list of files'; - - export function find(obj: IOLog, str: string) { - obj.filesRead.filter(f => f.result !== undefined).forEach(f => { - var lines = f.result.contents.split('\n'); - var printedHeader = false; - lines.forEach(line => { - if (line.indexOf(str) >= 0) { - if (!printedHeader) { - console.log(' === ' + f.path + ' ==='); - printedHeader = true; - } - console.log(line); - } - }); - }); - } - find['description'] = ' string: finds text in files'; - - export function grab(obj: IOLog, filename: string) { - obj.filesRead.filter(f => f.result !== undefined).forEach(f => { - if (path.basename(f.path) === filename) { - fs.writeFile(filename, f.result.contents); - } - }); - } - grab['description'] = ' filename.ts: writes out the specified file to disk'; - - export function extract(obj: IOLog, outputFolder: string) { - var directorySeparator = "/"; - function directoryExists(path: string): boolean { - return fs.existsSync(path) && fs.statSync(path).isDirectory(); - } - function getDirectoryPath(path: string) { - return path.substr(0, Math.max(getRootLength(path), path.lastIndexOf(directorySeparator))); - } - function getRootLength(path: string): number { - if (path.charAt(0) === directorySeparator) { - if (path.charAt(1) !== directorySeparator) return 1; - var p1 = path.indexOf(directorySeparator, 2); - if (p1 < 0) return 2; - var p2 = path.indexOf(directorySeparator, p1 + 1); - if (p2 < 0) return p1 + 1; - return p2 + 1; - } - if (path.charAt(1) === ":") { - if (path.charAt(2) === directorySeparator) return 3; - } - return 0; - } - function ensureDirectoriesExist(directoryPath: string) { - if (directoryPath.length > getRootLength(directoryPath) && !directoryExists(directoryPath)) { - var parentDirectory = getDirectoryPath(directoryPath); - ensureDirectoriesExist(parentDirectory); - console.log("creating directory: " + directoryPath); - fs.mkdirSync(directoryPath); - } - } - function normalizeSlashes(path: string): string { - return path.replace(/\\/g, "/"); - } - function transalatePath(outputFolder:string, path: string): string { - return normalizeSlashes(outputFolder + directorySeparator + path.replace(":", "")); - } - function fileExists(path: string): boolean { - return fs.existsSync(path); - } - obj.filesRead.forEach(f => { - var filename = transalatePath(outputFolder, f.path); - ensureDirectoriesExist(getDirectoryPath(filename)); - console.log("writing filename: " + filename); - fs.writeFileSync(filename, f.result.contents); - }); - - console.log("Command: tsc "); - obj.arguments.forEach(a => { - if (getRootLength(a) > 0) { - console.log(transalatePath(outputFolder, a)); - } - else { - console.log(a); - } - console.log(" "); - }); - } - extract['description'] = ' outputFolder: extract all input files to '; -} - -var args = process.argv.slice(2); -if (args.length < 2) { - console.log('Usage: node ior.js path_to_file.json [command]'); - console.log('List of commands: '); - Object.keys(Commands).forEach(k => console.log(' ' + k + Commands[k]['description'])); -} else { - var cmd: Function = Commands[args[1]]; - if (cmd === undefined) { - console.log('Unknown command ' + args[1]); - } else { - fs.readFile(args[0], 'utf-8', (err, data) => { - if (err) throw err; - var json = JSON.parse(data); - cmd.apply(undefined, [json].concat(args.slice(2))); - }); - } -} - diff --git a/scripts/parallel-lint.js b/scripts/parallel-lint.js deleted file mode 100644 index 2ac84667d6f..00000000000 --- a/scripts/parallel-lint.js +++ /dev/null @@ -1,50 +0,0 @@ -var tslint = require("tslint"); -var fs = require("fs"); -var path = require("path"); - -function getLinterOptions() { - return { - formatter: "prose", - formattersDirectory: undefined, - rulesDirectory: "built/local/tslint" - }; -} -function getLinterConfiguration() { - return tslint.Configuration.loadConfigurationFromPath(path.join(__dirname, "../tslint.json")); -} - -function lintFileContents(options, configuration, path, contents) { - var ll = new tslint.Linter(options); - ll.lint(path, contents, configuration); - return ll.getResult(); -} - -function lintFileAsync(options, configuration, path, cb) { - fs.readFile(path, "utf8", function (err, contents) { - if (err) { - return cb(err); - } - var result = lintFileContents(options, configuration, path, contents); - cb(undefined, result); - }); -} - -process.on("message", function (data) { - switch (data.kind) { - case "file": - var target = data.name; - var lintOptions = getLinterOptions(); - var lintConfiguration = getLinterConfiguration(); - lintFileAsync(lintOptions, lintConfiguration, target, function (err, result) { - if (err) { - process.send({ kind: "error", error: err.toString() }); - return; - } - process.send({ kind: "result", failures: result.failureCount, output: result.output }); - }); - break; - case "close": - process.exit(0); - break; - } -}); \ No newline at end of file diff --git a/scripts/types/ambient.d.ts b/scripts/types/ambient.d.ts index 52ddca6d7c1..ecfe29f9db6 100644 --- a/scripts/types/ambient.d.ts +++ b/scripts/types/ambient.d.ts @@ -1,13 +1,5 @@ import { TaskFunction } from "gulp"; -declare module "gulp-clone" { - function Clone(): NodeJS.ReadWriteStream; - namespace Clone { - export function sink() : NodeJS.ReadWriteStream & {tap: () => NodeJS.ReadWriteStream}; - } - export = Clone; -} - declare module "gulp-insert" { export function append(text: string | Buffer): NodeJS.ReadWriteStream; export function prepend(text: string | Buffer): NodeJS.ReadWriteStream; diff --git a/scripts/types/mocha/LICENSE b/scripts/types/mocha/LICENSE deleted file mode 100644 index 21071075c24..00000000000 --- a/scripts/types/mocha/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ - MIT License - - Copyright (c) Microsoft Corporation. All rights reserved. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE diff --git a/scripts/types/mocha/index.d.ts b/scripts/types/mocha/index.d.ts deleted file mode 100644 index 1ada77c0a49..00000000000 --- a/scripts/types/mocha/index.d.ts +++ /dev/null @@ -1,2856 +0,0 @@ -// Type definitions for mocha 5.2 -// Project: http://mochajs.org/ -// Definitions by: Kazi Manzur Rashid -// otiai10 -// jt000 -// Vadim Macagon -// Andrew Bradley -// Dmitrii Sorin -// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.1 - -export = Mocha; -export as namespace Mocha; - -/** - * Mocha API - * - * @see https://mochajs.org/api/mocha - */ -declare class Mocha { - private _growl; - private _reporter; - private _ui; - - constructor(options?: Mocha.MochaOptions); - - suite: Mocha.Suite; - files: string[]; - options: Mocha.MochaInstanceOptions; - - /** - * Enable or disable bailing on the first failure. - * - * @see https://mochajs.org/api/mocha#bail - */ - bail(bail?: boolean): this; - - /** - * Add test `file`. - * - * @see https://mochajs.org/api/mocha#addFile - */ - addFile(file: string): this; - - /** - * Set reporter to one of the built-in reporters. - * - * @see https://mochajs.org/api/mocha#reporter - */ - reporter(reporter: Mocha.Reporter, reporterOptions?: any): this; - - /** - * Set reporter to the provided constructor, one of the built-in reporters, or loads a reporter - * from a module path. Defaults to `"spec"`. - * - * @see https://mochajs.org/api/mocha#reporter - */ - reporter(reporter?: string | Mocha.ReporterConstructor, reporterOptions?: any): this; - - /** - * Set test UI to one of the built-in test interfaces. - * - * @see https://mochajs.org/api/mocha#ui - */ - ui(name: Mocha.Interface): this; - - /** - * Set test UI to one of the built-in test interfaces or loads a test interface from a module - * path. Defaults to `"bdd"`. - * - * @see https://mochajs.org/api/mocha#ui - */ - ui(name?: string): this; - - /** - * Escape string and add it to grep as a RegExp. - * - * @see https://mochajs.org/api/mocha#fgrep - */ - fgrep(str: string): this; - - /** - * Add regexp to grep, if `re` is a string it is escaped. - * - * @see https://mochajs.org/api/mocha#grep - */ - grep(re: string | RegExp): this; - - /** - * Invert `.grep()` matches. - * - * @see https://mochajs.org/api/mocha#invert - */ - invert(): this; - - /** - * Ignore global leaks. - * - * @see https://mochajs.org/api/mocha#ignoreLeaks - */ - ignoreLeaks(ignore: boolean): this; - - /** - * Enable global leak checking. - * - * @see https://mochajs.org/api/mocha#checkLeaks - */ - checkLeaks(): this; - - /** - * Display long stack-trace on failing - * - * @see https://mochajs.org/api/mocha#fullTrace - */ - fullTrace(): this; - - /** - * Enable growl support. - * - * @see https://mochajs.org/api/mocha#growl - */ - growl(): this; - - /** - * Ignore `globals` array or string. - * - * @see https://mochajs.org/api/mocha#globals - */ - globals(globals: string | ReadonlyArray): this; - - /** - * Emit color output. - * - * @see https://mochajs.org/api/mocha#useColors - */ - useColors(colors: boolean): this; - - /** - * Use inline diffs rather than +/-. - * - * @see https://mochajs.org/api/mocha#useInlineDiffs - */ - useInlineDiffs(inlineDiffs: boolean): this; - - /** - * Do not show diffs at all. - * - * @see https://mochajs.org/api/mocha#hideDiff - */ - hideDiff(hideDiff: boolean): this; - - /** - * Set the timeout in milliseconds. - * - * @see https://mochajs.org/api/mocha#timeout - */ - timeout(timeout: string | number): this; - - /** - * Set the number of times to retry failed tests. - * - * @see https://mochajs.org/api/mocha#retries - */ - retries(n: number): this; - - /** - * Set slowness threshold in milliseconds. - * - * @see https://mochajs.org/api/mocha#slow - */ - slow(slow: string | number): this; - - /** - * Enable timeouts. - * - * @see https://mochajs.org/api/mocha#enableTimeouts - */ - enableTimeouts(enabled?: boolean): this; - - /** - * Makes all tests async (accepting a callback) - * - * @see https://mochajs.org/api/mocha#asyncOnly. - */ - asyncOnly(): this; - - /** - * Disable syntax highlighting (in browser). - * - * @see https://mochajs.org/api/mocha#noHighlighting - */ - noHighlighting(): this; - - /** - * Enable uncaught errors to propagate (in browser). - * - * @see https://mochajs.org/api/mocha#allowUncaught - */ - allowUncaught(): boolean; - - /** - * Delay root suite execution. - * - * @see https://mochajs.org/api/mocha#delay - */ - delay(): boolean; - - /** - * Tests marked only fail the suite - * - * @see https://mochajs.org/api/mocha#forbidOnly - */ - forbidOnly(): boolean; - - /** - * Pending tests and tests marked skip fail the suite - * - * @see https://mochajs.org/api/mocha#forbidPending - */ - forbidPending(): boolean; - - /** - * Run tests and invoke `fn()` when complete. - * - * Note that `run` relies on Node's `require` to execute - * the test interface functions and will be subject to the - * cache - if the files are already in the `require` cache, - * they will effectively be skipped. Therefore, to run tests - * multiple times or to run tests in files that are already - * in the `require` cache, make sure to clear them from the - * cache first in whichever manner best suits your needs. - * - * @see https://mochajs.org/api/mocha#run - */ - run(fn?: (failures: number) => void): Mocha.Runner; - - /** - * Load registered files. - * - * @see https://mochajs.org/api/mocha#loadFiles - */ - protected loadFiles(fn?: () => void): void; -} - -declare namespace Mocha { - namespace utils { - /** - * Compute a slug from the given `str`. - * - * @see https://mochajs.org/api/module-utils.html#.slug - */ - function slug(str: string): string; - - /** - * Strip the function definition from `str`, and re-indent for pre whitespace. - * - * @see https://mochajs.org/api/module-utils.html#.clean - */ - function clean(str: string): string; - - /** - * Highlight the given string of `js`. - */ - function highlight(js: string): string; - - /** - * Takes some variable and asks `Object.prototype.toString()` what it thinks it is. - */ - function type(value: any): string; - - /** - * Stringify `value`. Different behavior depending on type of value: - * - * - If `value` is undefined or null, return `'[undefined]'` or `'[null]'`, respectively. - * - If `value` is not an object, function or array, return result of `value.toString()` wrapped in double-quotes. - * - If `value` is an *empty* object, function, or array, returns `'{}'`, `'[Function]'`, or `'[]'` respectively. - * - If `value` has properties, call canonicalize} on it, then return result of `JSON.stringify()` - * - * @see https://mochajs.org/api/module-utils.html#.stringify - */ - function stringify(value: any): string; - - /** - * Return a new Thing that has the keys in sorted order. Recursive. - * - * If the Thing... - * - has already been seen, return string `'[Circular]'` - * - is `undefined`, return string `'[undefined]'` - * - is `null`, return value `null` - * - is some other primitive, return the value - * - is not a primitive or an `Array`, `Object`, or `Function`, return the value of the Thing's `toString()` method - * - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again. - * - is an empty `Array`, `Object`, or `Function`, returns `'[]'`, `'{}'`, or `'[Function]'` respectively. - * - * @see https://mochajs.org/api/module-utils.html#.canonicalize - */ - function canonicalize(value: any, stack: any[], typeHint: string): any; - - /** - * Lookup file names at the given `path`. - * - * @see https://mochajs.org/api/Mocha.utils.html#.exports.lookupFiles - */ - function lookupFiles(filepath: string, extensions?: string[], recursive?: boolean): string[]; - - /** - * Generate an undefined error with a message warning the user. - * - * @see https://mochajs.org/api/module-utils.html#.undefinedError - */ - function undefinedError(): Error; - - /** - * Generate an undefined error if `err` is not defined. - * - * @see https://mochajs.org/api/module-utils.html#.getError - */ - function getError(err: Error | undefined): Error; - - /** - * When invoking this function you get a filter function that get the Error.stack as an - * input, and return a prettify output. (i.e: strip Mocha and internal node functions from - * stack trace). - * - * @see https://mochajs.org/api/module-utils.html#.stackTraceFilter - */ - function stackTraceFilter(): (stack: string) => string; - } - - namespace interfaces { - function bdd(suite: Suite): void; - function tdd(suite: Suite): void; - function qunit(suite: Suite): void; - function exports(suite: Suite): void; - } - - // #region Test interface augmentations - - interface HookFunction { - /** - * [bdd, qunit, tdd] Describe a "hook" to execute the given callback `fn`. The name of the - * function is used as the name of the hook. - * - * - _Only available when invoked via the mocha CLI._ - */ - (fn: Func): void; - - /** - * [bdd, qunit, tdd] Describe a "hook" to execute the given callback `fn`. The name of the - * function is used as the name of the hook. - * - * - _Only available when invoked via the mocha CLI._ - */ - (fn: AsyncFunc): void; - - /** - * [bdd, qunit, tdd] Describe a "hook" to execute the given `title` and callback `fn`. - * - * - _Only available when invoked via the mocha CLI._ - */ - (name: string, fn?: Func): void; - - /** - * [bdd, qunit, tdd] Describe a "hook" to execute the given `title` and callback `fn`. - * - * - _Only available when invoked via the mocha CLI._ - */ - (name: string, fn?: AsyncFunc): void; - } - - interface SuiteFunction { - /** - * [bdd, tdd] Describe a "suite" with the given `title` and callback `fn` containing - * nested suites. - * - * - _Only available when invoked via the mocha CLI._ - */ - (title: string, fn: (this: Suite) => void): Suite; - - /** - * [qunit] Describe a "suite" with the given `title`. - * - * - _Only available when invoked via the mocha CLI._ - */ - (title: string): Suite; - - /** - * [bdd, tdd, qunit] Indicates this suite should be executed exclusively. - * - * - _Only available when invoked via the mocha CLI._ - */ - only: ExclusiveSuiteFunction; - - /** - * [bdd, tdd] Indicates this suite should not be executed. - * - * - _Only available when invoked via the mocha CLI._ - */ - skip: PendingSuiteFunction; - } - - interface ExclusiveSuiteFunction { - /** - * [bdd, tdd] Describe a "suite" with the given `title` and callback `fn` containing - * nested suites. Indicates this suite should be executed exclusively. - * - * - _Only available when invoked via the mocha CLI._ - */ - (title: string, fn: (this: Suite) => void): Suite; - - /** - * [qunit] Describe a "suite" with the given `title`. Indicates this suite should be executed - * exclusively. - * - * - _Only available when invoked via the mocha CLI._ - */ - (title: string): Suite; - } - - /** - * [bdd, tdd] Describe a "suite" with the given `title` and callback `fn` containing - * nested suites. Indicates this suite should not be executed. - * - * - _Only available when invoked via the mocha CLI._ - * - * @returns [bdd] `Suite` - * @returns [tdd] `void` - */ - type PendingSuiteFunction = (title: string, fn: (this: Suite) => void) => Suite | void; - - interface TestFunction { - /** - * Describe a specification or test-case with the given callback `fn` acting as a thunk. - * The name of the function is used as the name of the test. - * - * - _Only available when invoked via the mocha CLI._ - */ - (fn: Func): Test; - - /** - * Describe a specification or test-case with the given callback `fn` acting as a thunk. - * The name of the function is used as the name of the test. - * - * - _Only available when invoked via the mocha CLI._ - */ - (fn: AsyncFunc): Test; - - /** - * Describe a specification or test-case with the given `title` and callback `fn` acting - * as a thunk. - * - * - _Only available when invoked via the mocha CLI._ - */ - (title: string, fn?: Func): Test; - - /** - * Describe a specification or test-case with the given `title` and callback `fn` acting - * as a thunk. - * - * - _Only available when invoked via the mocha CLI._ - */ - (title: string, fn?: AsyncFunc): Test; - - /** - * Indicates this test should be executed exclusively. - * - * - _Only available when invoked via the mocha CLI._ - */ - only: ExclusiveTestFunction; - - /** - * Indicates this test should not be executed. - * - * - _Only available when invoked via the mocha CLI._ - */ - skip: PendingTestFunction; - - /** - * Number of attempts to retry. - * - * - _Only available when invoked via the mocha CLI._ - */ - retries(n: number): void; - } - - interface ExclusiveTestFunction { - /** - * [bdd, tdd, qunit] Describe a specification or test-case with the given callback `fn` - * acting as a thunk. The name of the function is used as the name of the test. Indicates - * this test should be executed exclusively. - * - * - _Only available when invoked via the mocha CLI._ - */ - (fn: Func): Test; - - /** - * [bdd, tdd, qunit] Describe a specification or test-case with the given callback `fn` - * acting as a thunk. The name of the function is used as the name of the test. Indicates - * this test should be executed exclusively. - * - * - _Only available when invoked via the mocha CLI._ - */ - (fn: AsyncFunc): Test; - - /** - * [bdd, tdd, qunit] Describe a specification or test-case with the given `title` and - * callback `fn` acting as a thunk. Indicates this test should be executed exclusively. - * - * - _Only available when invoked via the mocha CLI._ - */ - (title: string, fn?: Func): Test; - - /** - * [bdd, tdd, qunit] Describe a specification or test-case with the given `title` and - * callback `fn` acting as a thunk. Indicates this test should be executed exclusively. - * - * - _Only available when invoked via the mocha CLI._ - */ - (title: string, fn?: AsyncFunc): Test; - } - - interface PendingTestFunction { - /** - * [bdd, tdd, qunit] Describe a specification or test-case with the given callback `fn` - * acting as a thunk. The name of the function is used as the name of the test. Indicates - * this test should not be executed. - * - * - _Only available when invoked via the mocha CLI._ - */ - (fn: Func): Test; - - /** - * [bdd, tdd, qunit] Describe a specification or test-case with the given callback `fn` - * acting as a thunk. The name of the function is used as the name of the test. Indicates - * this test should not be executed. - * - * - _Only available when invoked via the mocha CLI._ - */ - (fn: AsyncFunc): Test; - - /** - * [bdd, tdd, qunit] Describe a specification or test-case with the given `title` and - * callback `fn` acting as a thunk. Indicates this test should not be executed. - * - * - _Only available when invoked via the mocha CLI._ - */ - (title: string, fn?: Func): Test; - - /** - * [bdd, tdd, qunit] Describe a specification or test-case with the given `title` and - * callback `fn` acting as a thunk. Indicates this test should not be executed. - * - * - _Only available when invoked via the mocha CLI._ - */ - (title: string, fn?: AsyncFunc): Test; - } - - /** - * Execute after each test case. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#afterEach - */ - let afterEach: HookFunction; - - /** - * Execute after running tests. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#after - */ - let after: HookFunction; - - /** - * Execute before each test case. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#beforeEach - */ - let beforeEach: HookFunction; - - /** - * Execute before running tests. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#before - */ - let before: HookFunction; - - /** - * Describe a "suite" containing nested suites and tests. - * - * - _Only available when invoked via the mocha CLI._ - */ - let describe: SuiteFunction; - - /** - * Describes a test case. - * - * - _Only available when invoked via the mocha CLI._ - */ - let it: TestFunction; - - /** - * Describes a pending test case. - * - * - _Only available when invoked via the mocha CLI._ - */ - let xit: PendingTestFunction; - - /** - * Execute before each test case. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#beforeEach - */ - let setup: HookFunction; - - /** - * Execute before running tests. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#before - */ - let suiteSetup: HookFunction; - - /** - * Execute after running tests. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#after - */ - let suiteTeardown: HookFunction; - - /** - * Describe a "suite" containing nested suites and tests. - * - * - _Only available when invoked via the mocha CLI._ - */ - let suite: SuiteFunction; - - /** - * Execute after each test case. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#afterEach - */ - let teardown: HookFunction; - - /** - * Describes a test case. - * - * - _Only available when invoked via the mocha CLI._ - */ - let test: TestFunction; - - /** - * Triggers root suite execution. - * - * - _Only available if flag --delay is passed into Mocha._ - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#runWithSuite - */ - function run(): void; - - // #endregion Test interface augmentations - - namespace reporters { - /** - * Initialize a new `Base` reporter. - * - * All other reporters generally inherit from this reporter, providing stats such as test duration, - * number of tests passed / failed, etc. - * - * @see https://mochajs.org/api/Mocha.reporters.Base.html - */ - class Base { - constructor(runner: Runner, options?: MochaOptions); - /** @deprecated Use the overload that accepts `Mocha.Runner` instead. */ - constructor(runner: IRunner, options?: MochaOptions); - - /** - * Test run statistics - */ - stats: Stats; - - /** - * Test failures - */ - failures: Test[]; - - /** - * The configured runner - */ - runner: Runner; - - /** - * Output common epilogue used by many of the bundled reporters. - * - * @see https://mochajs.org/api/Mocha.reporters.Base.html#.Base#epilogue - */ - epilogue(): void; - - done?(failures: number, fn?: (failures: number) => void): void; - } - - namespace Base { - /** - * Enables coloring by default - * - * @see https://mochajs.org/api/module-base#.useColors - */ - let useColors: boolean; - - /** - * Inline diffs instead of +/- - * - * @see https://mochajs.org/api/module-base#.inlineDiffs - */ - let inlineDiffs: boolean; - - /** - * Default color map - * - * @see https://mochajs.org/api/module-base#.colors - */ - const colors: ColorMap; - - /** - * Default color map - * - * @see https://mochajs.org/api/module-base#.colors - */ - interface ColorMap { - // added by Base - pass: number; - fail: number; - "bright pass": number; - "bright fail": number; - "bright yellow": number; - pending: number; - suite: number; - "error title": number; - "error message": number; - "error stack": number; - checkmark: number; - fast: number; - medium: number; - slow: number; - green: number; - light: number; - "diff gutter": number; - "diff added": number; - "diff removed": number; - - // added by Progress - progress: number; - - // added by Landing - plane: number; - "plane crash": number; - runway: number; - - [key: string]: number; - } - - /** - * Default symbol map - * - * @see https://mochajs.org/api/module-base#.symbols - */ - const symbols: SymbolMap; - - /** - * Default symbol map - * - * @see https://mochajs.org/api/module-base#.symbols - */ - interface SymbolMap { - ok: string; - err: string; - dot: string; - comma: string; - bang: string; - [key: string]: string; - } - - /** - * Color `str` with the given `type` (from `colors`) - * - * @see https://mochajs.org/api/module-base#.color - */ - function color(type: string, str: string): string; - - /** - * Expose terminal window size - * - * @see https://mochajs.org/api/module-base#.window - */ - const window: { - width: number; - }; - - /** - * ANSI TTY control sequences common among reporters. - * - * @see https://mochajs.org/api/module-base#.cursor - */ - namespace cursor { - /** - * Hides the cursor - */ - function hide(): void; - - /** - * Shows the cursor - */ - function show(): void; - - /** - * Deletes the current line - */ - function deleteLine(): void; - - /** - * Moves to the beginning of the line - */ - function beginningOfLine(): void; - - /** - * Clears the line and moves to the beginning of the line. - */ - function CR(): void; - } - - /** - * Returns a diff between two strings with colored ANSI output. - * - * @see https://mochajs.org/api/module-base#.generateDiff - */ - function generateDiff(actual: string, expected: string): string; - - /** - * Output the given `failures` as a list. - * - * @see https://mochajs.org/api/Mocha.reporters.Base.html#.exports.list1 - */ - function list(failures: Test[]): void; - } - - /** - * Initialize a new `Dot` matrix test reporter. - * - * @see https://mochajs.org/api/Mocha.reporters.Dot.html - */ - class Dot extends Base { - } - - /** - * Initialize a new `Doc` reporter. - * - * @see https://mochajs.org/api/Mocha.reporters.Doc.html - */ - class Doc extends Base { - } - - /** - * Initialize a new `TAP` test reporter. - * - * @see https://mochajs.org/api/Mocha.reporters.TAP.html - */ - class TAP extends Base { - } - - /** - * Initialize a new `JSON` reporter - * - * @see https://mochajs.org/api/Mocha.reporters.JSON.html - */ - class JSON extends Base { - } - - /** - * Initialize a new `HTML` reporter. - * - * - _This reporter cannot be used on the console._ - * - * @see https://mochajs.org/api/Mocha.reporters.HTML.html - */ - class HTML extends Base { - /** - * Provide suite URL. - * - * @see https://mochajs.org/api/Mocha.reporters.HTML.html#suiteURL - */ - suiteURL(suite: Suite): string; - - /** - * Provide test URL. - * - * @see https://mochajs.org/api/Mocha.reporters.HTML.html#testURL - */ - testURL(test: Test): string; - - /** - * Adds code toggle functionality for the provided test's list element. - * - * @see https://mochajs.org/api/Mocha.reporters.HTML.html#addCodeToggle - */ - addCodeToggle(el: HTMLLIElement, contents: string): void; - } - - /** - * Initialize a new `List` test reporter. - * - * @see https://mochajs.org/api/Mocha.reporters.List.html - */ - class List extends Base { - } - - /** - * Initialize a new `Min` minimal test reporter (best used with --watch). - * - * @see https://mochajs.org/api/Mocha.reporters.Min.html - */ - class Min extends Base { - } - - /** - * Initialize a new `Spec` test reporter. - * - * @see https://mochajs.org/api/Mocha.reporters.Spec.html - */ - class Spec extends Base { - } - - /** - * Initialize a new `NyanCat` test reporter. - * - * @see https://mochajs.org/api/Mocha.reporters.Nyan.html - */ - class Nyan extends Base { - private colorIndex; - private numberOfLines; - private rainbowColors; - private scoreboardWidth; - private tick; - private trajectories; - private trajectoryWidthMax; - private draw; - private drawScoreboard; - private appendRainbow; - private drawRainbow; - private drawNyanCat; - private face; - private cursorUp; - private cursorDown; - private generateColors; - private rainbowify; - } - - /** - * Initialize a new `XUnit` test reporter. - * - * @see https://mochajs.org/api/Mocha.reporters.XUnit.html - */ - class XUnit extends Base { - constructor(runner: Runner, options?: XUnit.MochaOptions); - /** @deprecated Use the overload that accepts `Mocha.Runner` instead. */ - constructor(runner: IRunner, options?: XUnit.MochaOptions); - - /** - * Override done to close the stream (if it's a file). - * - * @see https://mochajs.org/api/Mocha.reporters.XUnit.html#done - */ - done(failures: number, fn: (failures: number) => void): void; - - /** - * Write out the given line. - * - * @see https://mochajs.org/api/Mocha.reporters.XUnit.html#write - */ - write(line: string): void; - - /** - * Output tag for the given `test.` - * - * @see https://mochajs.org/api/Mocha.reporters.XUnit.html#test - */ - test(test: Test): void; - } - - namespace XUnit { - interface MochaOptions extends Mocha.MochaOptions { - reporterOptions?: ReporterOptions; - } - - interface ReporterOptions { - output?: string; - suiteName?: string; - } - } - - /** - * Initialize a new `Markdown` test reporter. - * - * @see https://mochajs.org/api/Mocha.reporters.Markdown.html - */ - class Markdown extends Base { - } - - /** - * Initialize a new `Progress` bar test reporter. - * - * @see https://mochajs.org/api/Mocha.reporters.Progress.html - */ - class Progress extends Base { - constructor(runner: Runner, options?: Progress.MochaOptions); - /** @deprecated Use the overload that accepts `Mocha.Runner` instead. */ - constructor(runner: IRunner, options?: Progress.MochaOptions); - } - - namespace Progress { - interface MochaOptions extends Mocha.MochaOptions { - reporterOptions?: ReporterOptions; - } - - interface ReporterOptions { - open?: string; - complete?: string; - incomplete?: string; - close?: string; - verbose?: boolean; - } - } - - /** - * Initialize a new `Landing` reporter. - * - * @see https://mochajs.org/api/Mocha.reporters.Landing.html - */ - class Landing extends Base { - } - - /** - * Initialize a new `JSONStream` test reporter. - * - * @see https://mochajs.org/api/Mocha.reporters.JSONStream.html - */ - class JSONStream extends Base { - } - - // value-only aliases - const base: typeof Base; - const dot: typeof Dot; - const doc: typeof Doc; - const tap: typeof TAP; - const json: typeof JSON; - const html: typeof HTML; - const list: typeof List; - const spec: typeof Spec; - const nyan: typeof Nyan; - const xunit: typeof XUnit; - const markdown: typeof Markdown; - const progress: typeof Progress; - const landing: typeof Landing; - // NOTE: not possible to type this correctly: - // const "json-stream": typeof JSONStream; - } - - /** - * Initialize a new `Runnable` with the given `title` and callback `fn`. - * - * @see https://mochajs.org/api/Runnable.html - */ - class Runnable { - private _slow; - private _enableTimeouts; - private _retries; - private _currentRetry; - private _timeout; - private _timeoutError; - - constructor(title: string, fn?: Func | AsyncFunc); - - title: string; - fn: Func | AsyncFunc | undefined; - body: string; - async: boolean; - sync: boolean; - timedOut: boolean; - pending: boolean; - duration?: number; - parent?: Suite; - state?: "failed" | "passed"; - timer?: any; - ctx?: Context; - callback?: Done; - allowUncaught?: boolean; - file?: string; - - /** - * Get test timeout. - * - * @see https://mochajs.org/api/Runnable.html#timeout - */ - timeout(): number; - - /** - * Set test timeout. - * - * @see https://mochajs.org/api/Runnable.html#timeout - */ - timeout(ms: string | number): this; - - /** - * Get test slowness threshold. - * - * @see https://mochajs.org/api/Runnable.html#slow - */ - slow(): number; - - /** - * Set test slowness threshold. - * - * @see https://mochajs.org/api/Runnable.html#slow - */ - slow(ms: string | number): this; - - /** - * Get whether timeouts are enabled. - * - * @see https://mochajs.org/api/Runnable.html#enableTimeouts - */ - enableTimeouts(): boolean; - - /** - * Set whether timeouts are enabled. - * - * @see https://mochajs.org/api/Runnable.html#enableTimeouts - */ - enableTimeouts(enabled: boolean): this; - - /** - * Halt and mark as pending. - */ - skip(): never; - - /** - * Check if this runnable or its parent suite is marked as pending. - * - * @see https://mochajs.org/api/Runnable.html#isPending - */ - isPending(): boolean; - - /** - * Return `true` if this Runnable has failed. - */ - isFailed(): boolean; - - /** - * Return `true` if this Runnable has passed. - */ - isPassed(): boolean; - - /** - * Set or get number of retries. - * - * @see https://mochajs.org/api/Runnable.html#retries - */ - retries(): number; - - /** - * Set or get number of retries. - * - * @see https://mochajs.org/api/Runnable.html#retries - */ - retries(n: number): void; - - /** - * Set or get current retry - * - * @see https://mochajs.org/api/Runnable.html#currentRetry - */ - protected currentRetry(): number; - - /** - * Set or get current retry - * - * @see https://mochajs.org/api/Runnable.html#currentRetry - */ - protected currentRetry(n: number): void; - - /** - * Return the full title generated by recursively concatenating the parent's full title. - */ - fullTitle(): string; - - /** - * Return the title path generated by concatenating the parent's title path with the title. - */ - titlePath(): string[]; - - /** - * Clear the timeout. - * - * @see https://mochajs.org/api/Runnable.html#clearTimeout - */ - clearTimeout(): void; - - /** - * Inspect the runnable void of private properties. - * - * @see https://mochajs.org/api/Runnable.html#inspect - */ - inspect(): string; - - /** - * Reset the timeout. - * - * @see https://mochajs.org/api/Runnable.html#resetTimeout - */ - resetTimeout(): void; - - /** - * Get a list of whitelisted globals for this test run. - * - * @see https://mochajs.org/api/Runnable.html#globals - */ - globals(): string[]; - - /** - * Set a list of whitelisted globals for this test run. - * - * @see https://mochajs.org/api/Runnable.html#globals - */ - globals(globals: ReadonlyArray): void; - - /** - * Run the test and invoke `fn(err)`. - * - * @see https://mochajs.org/api/Runnable.html#run - */ - run(fn: Done): void; - } - - // #region Runnable "error" event - interface Runnable extends NodeJS.EventEmitter { - on(event: "error", listener: (error: any) => void): this; - once(event: "error", listener: (error: any) => void): this; - addListener(event: "error", listener: (error: any) => void): this; - removeListener(event: "error", listener: (error: any) => void): this; - prependListener(event: "error", listener: (error: any) => void): this; - prependOnceListener(event: "error", listener: (error: any) => void): this; - emit(name: "error", error: any): boolean; - } - // #endregion Runnable "error" event - // #region Runnable untyped events - interface Runnable extends NodeJS.EventEmitter { - on(event: string, listener: (...args: any[]) => void): this; - once(event: string, listener: (...args: any[]) => void): this; - addListener(event: string, listener: (...args: any[]) => void): this; - removeListener(event: string, listener: (...args: any[]) => void): this; - prependListener(event: string, listener: (...args: any[]) => void): this; - prependOnceListener(event: string, listener: (...args: any[]) => void): this; - emit(name: string, ...args: any[]): boolean; - } - // #endregion Runnable untyped events - - /** - * Test context - * - * @see https://mochajs.org/api/module-Context.html#~Context - */ - class Context { - private _runnable; - - test?: Runnable; - currentTest?: Test; - - /** - * Get the context `Runnable`. - */ - runnable(): Runnable; - - /** - * Set the context `Runnable`. - */ - runnable(runnable: Runnable): this; - /** @deprecated Use the overload that accepts `Mocha.Runnable` instead. */ - runnable(runnable: IRunnable): this; - - /** - * Get test timeout. - */ - timeout(): number; - - /** - * Set test timeout. - */ - timeout(ms: string | number): this; - - /** - * Get whether timeouts are enabled. - */ - enableTimeouts(): boolean; - - /** - * Set whether timeouts are enabled. - */ - enableTimeouts(enabled: boolean): this; - - /** - * Get test slowness threshold. - */ - slow(): number; - - /** - * Set test slowness threshold. - */ - slow(ms: string | number): this; - - /** - * Mark a test as skipped. - */ - skip(): never; - - /** - * Get the number of allowed retries on failed tests. - */ - retries(): number; - - /** - * Set the number of allowed retries on failed tests. - */ - retries(n: number): this; - - [key: string]: any; - } - - /** - * Initialize a `Runner` for the given `suite`. - * - * @see https://mochajs.org/api/Mocha.Runner.html - */ - class Runner { - private _globals; - private _abort; - private _delay; - private _defaultGrep; - private next; - private hookErr; - private prevGlobalsLength; - private nextSuite; - - constructor(suite: Suite, delay: boolean); - - /** @deprecated Use the overload that accepts `Mocha.Suite` instead. */ - constructor(suite: ISuite, delay: boolean); - - suite: Suite; - started: boolean; - total: number; - failures: number; - asyncOnly?: boolean; - allowUncaught?: boolean; - fullStackTrace?: boolean; - forbidOnly?: boolean; - forbidPending?: boolean; - ignoreLeaks?: boolean; - test?: Test; - currentRunnable?: Runnable; - stats?: Stats; // added by reporters - - /** - * Run tests with full titles matching `re`. Updates runner.total - * with number of tests matched. - * - * @see https://mochajs.org/api/Mocha.Runner.html#.Runner#grep - */ - grep(re: RegExp, invert: boolean): this; - - /** - * Returns the number of tests matching the grep search for the - * given suite. - * - * @see https://mochajs.org/api/Mocha.Runner.html#.Runner#grepTotal - */ - grepTotal(suite: Suite): number; - - /** @deprecated Use the overload that accepts `Mocha.Suite` instead. */ - grepTotal(suite: ISuite): number; - - /** - * Gets the allowed globals. - * - * @see https://mochajs.org/api/Mocha.Runner.html#.Runner#globals - */ - globals(): string[]; - - /** - * Allow the given `arr` of globals. - * - * @see https://mochajs.org/api/Mocha.Runner.html#.Runner#globals - */ - globals(arr: ReadonlyArray): this; - - /** - * Run the root suite and invoke `fn(failures)` on completion. - * - * @see https://mochajs.org/api/Mocha.Runner.html#.Runner#run - */ - run(fn?: (failures: number) => void): this; - - /** - * Cleanly abort execution. - * - * @see https://mochajs.org/api/Mocha.Runner.html#.Runner#abort - */ - abort(): this; - - /** - * Handle uncaught exceptions. - * - * @see https://mochajs.org/api/Mocha.Runner.html#uncaught - */ - uncaught(err: any): void; - - /** - * Wrapper for setImmediate, process.nextTick, or browser polyfill. - */ - protected static immediately(callback: Function): void; - - /** - * Return a list of global properties. - * - * @see https://mochajs.org/api/Mocha.Runner.html#globalProps - */ - protected globalProps(): string[]; - - /** - * Check for global variable leaks. - * - * @see https://mochajs.org/api/Mocha.Runner.html#checkGlobals - */ - protected checkGlobals(test: Test): void; - - /** - * Fail the given `test`. - * - * @see https://mochajs.org/api/Mocha.Runner.html#fail - */ - protected fail(test: Test, err: any): void; - - /** - * Fail the given `hook` with `err`. - * - * Hook failures work in the following pattern: - * - If bail, then exit - * - Failed `before` hook skips all tests in a suite and subsuites, - * but jumps to corresponding `after` hook - * - Failed `before each` hook skips remaining tests in a - * suite and jumps to corresponding `after each` hook, - * which is run only once - * - Failed `after` hook does not alter - * execution order - * - Failed `after each` hook skips remaining tests in a - * suite and subsuites, but executes other `after each` - * hooks - * - * @see https://mochajs.org/api/Mocha.Runner.html#failHook - */ - protected failHook(hook: Hook, err: any): void; - - /** - * Run hook `name` callbacks and then invoke `fn()`. - * - * @see https://mochajs.org/api/Mocha.Runner.html#hook - */ - protected hook(name: string, fn: () => void): void; - - /** - * Run hook `name` for the given array of `suites` - * in order, and callback `fn(err, errSuite)`. - * - * @see https://mochajs.org/api/Mocha.Runner.html#hooks - */ - protected hooks(name: string, suites: Suite[], fn: (err?: any, errSuite?: Suite) => void): void; - - /** - * Run hooks from the top level down. - * - * @see https://mochajs.org/api/Mocha.Runner.html#hookUp - */ - protected hookUp(name: string, fn: (err?: any, errSuite?: Suite) => void): void; - - /** - * Run hooks from the bottom up. - * - * @see https://mochajs.org/api/Mocha.Runner.html#hookDown - */ - protected hookDown(name: string, fn: (err?: any, errSuite?: Suite) => void): void; - - /** - * Return an array of parent Suites from closest to furthest. - * - * @see https://mochajs.org/api/Mocha.Runner.html#parents - */ - protected parents(): Suite[]; - - /** - * Run the current test and callback `fn(err)`. - * - * @see https://mochajs.org/api/Mocha.Runner.html#runTest - */ - protected runTest(fn: Done): any; - - /** - * Run tests in the given `suite` and invoke the callback `fn()` when complete. - * - * @see https://mochajs.org/api/Mocha.Runner.html#runTests - */ - protected runTests(suite: Suite, fn: (errSuite?: Suite) => void): void; - - /** - * Run the given `suite` and invoke the callback `fn()` when complete. - * - * @see https://mochajs.org/api/Mocha.Runner.html#runSuite - */ - protected runSuite(suite: Suite, fn: (errSuite?: Suite) => void): void; - } - - // #region Runner "waiting" event - interface Runner { - on(event: "waiting", listener: (rootSuite: Suite) => void): this; - once(event: "waiting", listener: (rootSuite: Suite) => void): this; - addListener(event: "waiting", listener: (rootSuite: Suite) => void): this; - removeListener(event: "waiting", listener: (rootSuite: Suite) => void): this; - prependListener(event: "waiting", listener: (rootSuite: Suite) => void): this; - prependOnceListener(event: "waiting", listener: (rootSuite: Suite) => void): this; - emit(name: "waiting", rootSuite: Suite): boolean; - } - // #endregion Runner "waiting" event - // #region Runner "start" event - interface Runner extends NodeJS.EventEmitter { - on(event: "start", listener: () => void): this; - once(event: "start", listener: () => void): this; - addListener(event: "start", listener: () => void): this; - removeListener(event: "start", listener: () => void): this; - prependListener(event: "start", listener: () => void): this; - prependOnceListener(event: "start", listener: () => void): this; - emit(name: "start"): boolean; - } - // #endregion Runner "start" event - // #region Runner "end" event - interface Runner extends NodeJS.EventEmitter { - on(event: "end", listener: () => void): this; - once(event: "end", listener: () => void): this; - addListener(event: "end", listener: () => void): this; - removeListener(event: "end", listener: () => void): this; - prependListener(event: "end", listener: () => void): this; - prependOnceListener(event: "end", listener: () => void): this; - emit(name: "end"): boolean; - } - // #endregion Runner "end" event - // #region Runner "suite" event - interface Runner extends NodeJS.EventEmitter { - on(event: "suite", listener: (suite: Suite) => void): this; - once(event: "suite", listener: (suite: Suite) => void): this; - addListener(event: "suite", listener: (suite: Suite) => void): this; - removeListener(event: "suite", listener: (suite: Suite) => void): this; - prependListener(event: "suite", listener: (suite: Suite) => void): this; - prependOnceListener(event: "suite", listener: (suite: Suite) => void): this; - emit(name: "suite", suite: Suite): boolean; - } - // #endregion Runner "suite" event - // #region Runner "suite end" event - interface Runner extends NodeJS.EventEmitter { - on(event: "suite end", listener: (suite: Suite) => void): this; - once(event: "suite end", listener: (suite: Suite) => void): this; - addListener(event: "suite end", listener: (suite: Suite) => void): this; - removeListener(event: "suite end", listener: (suite: Suite) => void): this; - prependListener(event: "suite end", listener: (suite: Suite) => void): this; - prependOnceListener(event: "suite end", listener: (suite: Suite) => void): this; - emit(name: "suite end", suite: Suite): boolean; - } - // #endregion Runner "suite end" event - // #region Runner "test" event - interface Runner extends NodeJS.EventEmitter { - on(event: "test", listener: (test: Test) => void): this; - once(event: "test", listener: (test: Test) => void): this; - addListener(event: "test", listener: (test: Test) => void): this; - removeListener(event: "test", listener: (test: Test) => void): this; - prependListener(event: "test", listener: (test: Test) => void): this; - prependOnceListener(event: "test", listener: (test: Test) => void): this; - emit(name: "test", test: Test): boolean; - } - // #endregion Runner "test" event - // #region Runner "test end" event - interface Runner extends NodeJS.EventEmitter { - on(event: "test end", listener: (test: Test) => void): this; - once(event: "test end", listener: (test: Test) => void): this; - addListener(event: "test end", listener: (test: Test) => void): this; - removeListener(event: "test end", listener: (test: Test) => void): this; - prependListener(event: "test end", listener: (test: Test) => void): this; - prependOnceListener(event: "test end", listener: (test: Test) => void): this; - emit(name: "test end", test: Test): boolean; - } - // #endregion Runner "test end" event - // #region Runner "hook" event - interface Runner extends NodeJS.EventEmitter { - on(event: "hook", listener: (hook: Hook) => void): this; - once(event: "hook", listener: (hook: Hook) => void): this; - addListener(event: "hook", listener: (hook: Hook) => void): this; - removeListener(event: "hook", listener: (hook: Hook) => void): this; - prependListener(event: "hook", listener: (hook: Hook) => void): this; - prependOnceListener(event: "hook", listener: (hook: Hook) => void): this; - emit(name: "hook", hook: Hook): boolean; - } - // #endregion Runner "hook" event - // #region Runner "hook end" event - interface Runner extends NodeJS.EventEmitter { - on(event: "hook end", listener: (hook: Hook) => void): this; - once(event: "hook end", listener: (hook: Hook) => void): this; - addListener(event: "hook end", listener: (hook: Hook) => void): this; - removeListener(event: "hook end", listener: (hook: Hook) => void): this; - prependListener(event: "hook end", listener: (hook: Hook) => void): this; - prependOnceListener(event: "hook end", listener: (hook: Hook) => void): this; - emit(name: "hook end", hook: Hook): boolean; - } - // #endregion Runner "hook end" event - // #region Runner "pass" event - interface Runner extends NodeJS.EventEmitter { - on(event: "pass", listener: (test: Test) => void): this; - once(event: "pass", listener: (test: Test) => void): this; - addListener(event: "pass", listener: (test: Test) => void): this; - removeListener(event: "pass", listener: (test: Test) => void): this; - prependListener(event: "pass", listener: (test: Test) => void): this; - prependOnceListener(event: "pass", listener: (test: Test) => void): this; - emit(name: "pass", test: Test): boolean; - } - // #endregion Runner "pass" event - // #region Runner "fail" event - interface Runner extends NodeJS.EventEmitter { - on(event: "fail", listener: (test: Test, err: any) => void): this; - once(event: "fail", listener: (test: Test, err: any) => void): this; - addListener(event: "fail", listener: (test: Test, err: any) => void): this; - removeListener(event: "fail", listener: (test: Test, err: any) => void): this; - prependListener(event: "fail", listener: (test: Test, err: any) => void): this; - prependOnceListener(event: "fail", listener: (test: Test, err: any) => void): this; - emit(name: "fail", test: Test, err: any): boolean; - } - // #endregion Runner "fail" event - // #region Runner "pending" event - interface Runner extends NodeJS.EventEmitter { - on(event: "pending", listener: (test: Test) => void): this; - once(event: "pending", listener: (test: Test) => void): this; - addListener(event: "pending", listener: (test: Test) => void): this; - removeListener(event: "pending", listener: (test: Test) => void): this; - prependListener(event: "pending", listener: (test: Test) => void): this; - prependOnceListener(event: "pending", listener: (test: Test) => void): this; - emit(name: "pending", test: Test): boolean; - } - // #endregion Runner "pending" event - // #region Runner untyped events - interface Runner extends NodeJS.EventEmitter { - on(event: string, listener: (...args: any[]) => void): this; - once(event: string, listener: (...args: any[]) => void): this; - addListener(event: string, listener: (...args: any[]) => void): this; - removeListener(event: string, listener: (...args: any[]) => void): this; - prependListener(event: string, listener: (...args: any[]) => void): this; - prependOnceListener(event: string, listener: (...args: any[]) => void): this; - emit(name: string, ...args: any[]): boolean; - } - // #endregion Runner untyped events - - /** - * Initialize a new `Suite` with the given `title` and `ctx`. - * - * @see https://mochajs.org/api/Mocha.Suite.html - */ - class Suite { - private _beforeEach; - private _beforeAll; - private _afterEach; - private _afterAll; - private _timeout; - private _enableTimeouts; - private _slow; - private _bail; - private _retries; - private _onlyTests; - private _onlySuites; - - constructor(title: string, parentContext?: Context); - /** @deprecated Use the overload that accepts `Mocha.Context` instead. */ - constructor(title: string, parentContext?: IContext); - - ctx: Context; - suites: Suite[]; - tests: Test[]; - pending: boolean; - file?: string; - root: boolean; - delayed: boolean; - parent: Suite | undefined; - title: string; - - /** - * Create a new `Suite` with the given `title` and parent `Suite`. When a suite - * with the same title is already present, that suite is returned to provide - * nicer reporter and more flexible meta-testing. - * - * @see https://mochajs.org/api/mocha#.exports.create - */ - static create(parent: Suite, title: string): Suite; - /** @deprecated Use the overload that accepts `Mocha.Suite` instead. */ - static create(parent: ISuite, title: string): Suite; - - /** - * Return a clone of this `Suite`. - * - * @see https://mochajs.org/api/Mocha.Suite.html#clone - */ - clone(): Suite; - - /** - * Get timeout `ms`. - * - * @see https://mochajs.org/api/Mocha.Suite.html#timeout - */ - timeout(): number; - - /** - * Set timeout `ms` or short-hand such as "2s". - * - * @see https://mochajs.org/api/Mocha.Suite.html#timeout - */ - timeout(ms: string | number): this; - - /** - * Get number of times to retry a failed test. - * - * @see https://mochajs.org/api/Mocha.Suite.html#retries - */ - retries(): number; - - /** - * Set number of times to retry a failed test. - * - * @see https://mochajs.org/api/Mocha.Suite.html#retries - */ - retries(n: string | number): this; - - /** - * Get whether timeouts are enabled. - * - * @see https://mochajs.org/api/Mocha.Suite.html#enableTimeouts - */ - enableTimeouts(): boolean; - - /** - * Set whether timeouts are `enabled`. - * - * @see https://mochajs.org/api/Mocha.Suite.html#enableTimeouts - */ - enableTimeouts(enabled: boolean): this; - - /** - * Get slow `ms`. - * - * @see https://mochajs.org/api/Mocha.Suite.html#slow - */ - slow(): number; - - /** - * Set slow `ms` or short-hand such as "2s". - * - * @see https://mochajs.org/api/Mocha.Suite.html#slow - */ - slow(ms: string | number): this; - - /** - * Get whether to bail after first error. - * - * @see https://mochajs.org/api/Mocha.Suite.html#bail - */ - bail(): boolean; - - /** - * Set whether to bail after first error. - * - * @see https://mochajs.org/api/Mocha.Suite.html#bail - */ - bail(bail: boolean): this; - - /** - * Check if this suite or its parent suite is marked as pending. - * - * @see https://mochajs.org/api/Mocha.Suite.html#isPending - */ - isPending(): boolean; - - /** - * Run `fn(test[, done])` before running tests. - * - * @see https://mochajs.org/api/Mocha.Suite.html#beforeAll - */ - beforeAll(fn?: Func): this; - - /** - * Run `fn(test[, done])` before running tests. - * - * @see https://mochajs.org/api/Mocha.Suite.html#beforeAll - */ - beforeAll(fn?: AsyncFunc): this; - - /** - * Run `fn(test[, done])` before running tests. - * - * @see https://mochajs.org/api/Mocha.Suite.html#beforeAll - */ - beforeAll(title: string, fn?: Func): this; - - /** - * Run `fn(test[, done])` before running tests. - * - * @see https://mochajs.org/api/Mocha.Suite.html#beforeAll - */ - beforeAll(title: string, fn?: AsyncFunc): this; - - /** - * Run `fn(test[, done])` after running tests. - * - * @see https://mochajs.org/api/Mocha.Suite.html#afterAll - */ - afterAll(fn?: Func): this; - - /** - * Run `fn(test[, done])` after running tests. - * - * @see https://mochajs.org/api/Mocha.Suite.html#afterAll - */ - afterAll(fn?: AsyncFunc): this; - - /** - * Run `fn(test[, done])` after running tests. - * - * @see https://mochajs.org/api/Mocha.Suite.html#afterAll - */ - afterAll(title: string, fn?: Func): this; - - /** - * Run `fn(test[, done])` after running tests. - * - * @see https://mochajs.org/api/Mocha.Suite.html#afterAll - */ - afterAll(title: string, fn?: AsyncFunc): this; - - /** - * Run `fn(test[, done])` before each test case. - * - * @see https://mochajs.org/api/Mocha.Suite.html#beforeEach - */ - beforeEach(fn?: Func): this; - - /** - * Run `fn(test[, done])` before each test case. - * - * @see https://mochajs.org/api/Mocha.Suite.html#beforeEach - */ - beforeEach(fn?: AsyncFunc): this; - - /** - * Run `fn(test[, done])` before each test case. - * - * @see https://mochajs.org/api/Mocha.Suite.html#beforeEach - */ - beforeEach(title: string, fn?: Func): this; - - /** - * Run `fn(test[, done])` before each test case. - * - * @see https://mochajs.org/api/Mocha.Suite.html#beforeEach - */ - beforeEach(title: string, fn?: AsyncFunc): this; - - /** - * Run `fn(test[, done])` after each test case. - * - * @see https://mochajs.org/api/Mocha.Suite.html#afterEach - */ - afterEach(fn?: Func): this; - - /** - * Run `fn(test[, done])` after each test case. - * - * @see https://mochajs.org/api/Mocha.Suite.html#afterEach - */ - afterEach(fn?: AsyncFunc): this; - - /** - * Run `fn(test[, done])` after each test case. - * - * @see https://mochajs.org/api/Mocha.Suite.html#afterEach - */ - afterEach(title: string, fn?: Func): this; - - /** - * Run `fn(test[, done])` after each test case. - * - * @see https://mochajs.org/api/Mocha.Suite.html#afterEach - */ - afterEach(title: string, fn?: AsyncFunc): this; - - /** - * Add a test `suite`. - * - * @see https://mochajs.org/api/Mocha.Suite.html#addSuite - */ - addSuite(suite: Suite): this; - /** @deprecated Use the overload that accepts `Mocha.ISuite` instead. */ - addSuite(suite: ISuite): this; - - /** - * Add a `test` to this suite. - * - * @see https://mochajs.org/api/Mocha.Suite.html#addTest - */ - addTest(test: Test): this; - /** @deprecated Use the overload that accepts `Mocha.ITest` instead. */ - addTest(test: ITest): this; - - /** - * Return the full title generated by recursively concatenating the parent's - * full title. - * - * @see https://mochajs.org/api/Mocha.Suite.html#.Suite#fullTitle - */ - fullTitle(): string; - - /** - * Return the title path generated by recursively concatenating the parent's - * title path. - * - * @see https://mochajs.org/api/Mocha.Suite.html#.Suite#titlePath - */ - titlePath(): string[]; - - /** - * Return the total number of tests. - * - * @see https://mochajs.org/api/Mocha.Suite.html#.Suite#total - */ - total(): number; - - /** - * Iterates through each suite recursively to find all tests. Applies a - * function in the format `fn(test)`. - * - * @see https://mochajs.org/api/Mocha.Suite.html#eachTest - */ - eachTest(fn: (test: Test) => void): this; - - /** - * This will run the root suite if we happen to be running in delayed mode. - * - * @see https://mochajs.org/api/Mocha.Suite.html#run - */ - run(): void; - - /** - * Generic hook-creator. - */ - protected _createHook(title: string, fn?: Func | AsyncFunc): Hook; - } - - // #region Suite "beforeAll" event - interface Suite extends NodeJS.EventEmitter { - on(event: "beforeAll", listener: (hook: Hook) => void): this; - once(event: "beforeAll", listener: (hook: Hook) => void): this; - addListener(event: "beforeAll", listener: (hook: Hook) => void): this; - removeListener(event: "beforeAll", listener: (hook: Hook) => void): this; - prependListener(event: "beforeAll", listener: (hook: Hook) => void): this; - prependOnceListener(event: "beforeAll", listener: (hook: Hook) => void): this; - emit(name: "beforeAll", hook: Hook): boolean; - } - // #endregion Suite "beforeAll" event - // #region Suite "afterAll" event - interface Suite extends NodeJS.EventEmitter { - on(event: "afterAll", listener: (hook: Hook) => void): this; - once(event: "afterAll", listener: (hook: Hook) => void): this; - addListener(event: "afterAll", listener: (hook: Hook) => void): this; - removeListener(event: "afterAll", listener: (hook: Hook) => void): this; - prependListener(event: "afterAll", listener: (hook: Hook) => void): this; - prependOnceListener(event: "afterAll", listener: (hook: Hook) => void): this; - emit(name: "afterAll", hook: Hook): boolean; - } - // #endregion Suite "afterAll" event - // #region Suite "beforeEach" event - interface Suite extends NodeJS.EventEmitter { - on(event: "beforeEach", listener: (hook: Hook) => void): this; - once(event: "beforeEach", listener: (hook: Hook) => void): this; - addListener(event: "beforeEach", listener: (hook: Hook) => void): this; - removeListener(event: "beforeEach", listener: (hook: Hook) => void): this; - prependListener(event: "beforeEach", listener: (hook: Hook) => void): this; - prependOnceListener(event: "beforeEach", listener: (hook: Hook) => void): this; - emit(name: "beforeEach", hook: Hook): boolean; - } - // #endregion Suite "beforeEach" event - // #region Suite "afterEach" event - interface Suite extends NodeJS.EventEmitter { - on(event: "afterEach", listener: (hook: Hook) => void): this; - once(event: "afterEach", listener: (hook: Hook) => void): this; - addListener(event: "afterEach", listener: (hook: Hook) => void): this; - removeListener(event: "afterEach", listener: (hook: Hook) => void): this; - prependListener(event: "afterEach", listener: (hook: Hook) => void): this; - prependOnceListener(event: "afterEach", listener: (hook: Hook) => void): this; - emit(name: "afterEach", hook: Hook): boolean; - } - // #endregion Suite "afterEach" event - // #region Suite "suite" event - interface Suite extends NodeJS.EventEmitter { - on(event: "suite", listener: (suite: Suite) => void): this; - once(event: "suite", listener: (suite: Suite) => void): this; - addListener(event: "suite", listener: (suite: Suite) => void): this; - removeListener(event: "suite", listener: (suite: Suite) => void): this; - prependListener(event: "suite", listener: (suite: Suite) => void): this; - prependOnceListener(event: "suite", listener: (suite: Suite) => void): this; - emit(name: "suite", suite: Suite): boolean; - } - // #endregion Suite "suite" event - // #region Suite "test" event - interface Suite { - on(event: "test", listener: (test: Test) => void): this; - once(event: "test", listener: (test: Test) => void): this; - addListener(event: "test", listener: (test: Test) => void): this; - removeListener(event: "test", listener: (test: Test) => void): this; - prependListener(event: "test", listener: (test: Test) => void): this; - prependOnceListener(event: "test", listener: (test: Test) => void): this; - emit(name: "test", test: Test): boolean; - } - // #endregion Suite "test" event - // #region Suite "run" event - interface Suite extends NodeJS.EventEmitter { - on(event: "run", listener: () => void): this; - once(event: "run", listener: () => void): this; - addListener(event: "run", listener: () => void): this; - removeListener(event: "run", listener: () => void): this; - prependListener(event: "run", listener: () => void): this; - prependOnceListener(event: "run", listener: () => void): this; - emit(name: "run"): boolean; - } - // #endregion Suite "run" event - // #region Suite "pre-require" event - interface Suite extends NodeJS.EventEmitter { - on(event: "pre-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this; - once(event: "pre-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this; - addListener(event: "pre-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this; - removeListener(event: "pre-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this; - prependListener(event: "pre-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this; - prependOnceListener(event: "pre-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this; - emit(name: "pre-require", context: MochaGlobals, file: string, mocha: Mocha): boolean; - } - // #endregion Suite "pre-require" event - // #region Suite "require" event - interface Suite extends NodeJS.EventEmitter { - on(event: "require", listener: (module: any, file: string, mocha: Mocha) => void): this; - once(event: "require", listener: (module: any, file: string, mocha: Mocha) => void): this; - addListener(event: "require", listener: (module: any, file: string, mocha: Mocha) => void): this; - removeListener(event: "require", listener: (module: any, file: string, mocha: Mocha) => void): this; - prependListener(event: "require", listener: (module: any, file: string, mocha: Mocha) => void): this; - prependOnceListener(event: "require", listener: (module: any, file: string, mocha: Mocha) => void): this; - emit(name: "require", module: any, file: string, mocha: Mocha): boolean; - } - // #endregion Suite "require" event - // #region Suite "post-require" event - interface Suite extends NodeJS.EventEmitter { - on(event: "post-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this; - once(event: "post-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this; - addListener(event: "post-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this; - removeListener(event: "post-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this; - prependListener(event: "post-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this; - prependOnceListener(event: "post-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this; - emit(name: "post-require", context: MochaGlobals, file: string, mocha: Mocha): boolean; - } - // #endregion Suite "post-require" event - // #region Suite untyped events - interface Suite extends NodeJS.EventEmitter { - on(event: string, listener: (...args: any[]) => void): this; - once(event: string, listener: (...args: any[]) => void): this; - addListener(event: string, listener: (...args: any[]) => void): this; - removeListener(event: string, listener: (...args: any[]) => void): this; - prependListener(event: string, listener: (...args: any[]) => void): this; - prependOnceListener(event: string, listener: (...args: any[]) => void): this; - emit(name: string, ...args: any[]): boolean; - } - // #endregion Runner untyped events - - /** - * Initialize a new `Hook` with the given `title` and callback `fn` - * - * @see https://mochajs.org/api/Hook.html - */ - class Hook extends Runnable { - private _error; - - type: "hook"; - originalTitle?: string; // added by Runner - - /** - * Get the test `err`. - * - * @see https://mochajs.org/api/Hook.html#error - */ - error(): any; - - /** - * Set the test `err`. - * - * @see https://mochajs.org/api/Hook.html#error - */ - error(err: any): void; - } - - /** - * Initialize a new `Test` with the given `title` and callback `fn`. - * - * @see https://mochajs.org/api/Test.html - */ - class Test extends Runnable { - type: "test"; - speed?: "slow" | "medium" | "fast"; // added by reporters - err?: Error; // added by reporters - clone(): Test; - } - - /** - * Test statistics - */ - interface Stats { - suites: number; - tests: number; - passes: number; - pending: number; - failures: number; - start?: Date; - end?: Date; - duration?: number; - } - - type TestInterface = (suite: Suite) => void; - - interface ReporterConstructor { - new (runner: Runner, options: { reporterOptions?: any; }): reporters.Base; - } - - type Done = (err?: any) => void; - - /** - * Callback function used for tests and hooks. - */ - type Func = (this: Context, done: Done) => void; - - /** - * Async callback function used for tests and hooks. - */ - type AsyncFunc = (this: Context) => PromiseLike; - - /** - * Options to pass to Mocha. - */ - interface MochaOptions { - /** Test interfaces ("bdd", "tdd", "exports", etc.). */ - ui?: Interface; - - /** - * Reporter constructor, built-in reporter name, or reporter module path. Defaults to - * `"spec"`. - */ - reporter?: string | ReporterConstructor; - - /** Options to pass to the reporter. */ - reporterOptions?: any; - - /** Array of accepted globals. */ - globals?: string[]; - - /** timeout in milliseconds. */ - timeout?: number; - - enableTimeouts?: boolean; - - /** number of times to retry failed tests. */ - retries?: number; - - /** bail on the first test failure. */ - bail?: boolean; - - /** milliseconds to wait before considering a test slow. */ - slow?: number; - - /** ignore global leaks. */ - ignoreLeaks?: boolean; - - /** display the full stack trace on failure. */ - fullStackTrace?: boolean; - - /** string or regexp to filter tests with. */ - grep?: string | RegExp; - - /** Enable growl support. */ - growl?: boolean; - - /** Emit color output. */ - useColors?: boolean; - - /** Use inline diffs rather than +/-. */ - inlineDiffs?: boolean; - - /** Do not show diffs at all. */ - hideDiff?: boolean; - - asyncOnly?: boolean; - delay?: boolean; - forbidOnly?: boolean; - forbidPending?: boolean; - noHighlighting?: boolean; - allowUncaught?: boolean; - } - - interface MochaInstanceOptions extends MochaOptions { - files?: string[]; - } - - /** - * Variables added to the global scope by Mocha when run in the CLI. - */ - interface MochaGlobals { - /** - * Execute before running tests. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#before - */ - before: HookFunction; - - /** - * Execute after running tests. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#after - */ - after: HookFunction; - - /** - * Execute before each test case. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#beforeEach - */ - beforeEach: HookFunction; - - /** - * Execute after each test case. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#afterEach - */ - afterEach: HookFunction; - - /** - * Describe a "suite" containing nested suites and tests. - * - * - _Only available when invoked via the mocha CLI._ - */ - describe: SuiteFunction; - - /** - * Describe a "suite" containing nested suites and tests. - * - * - _Only available when invoked via the mocha CLI._ - */ - context: SuiteFunction; - - /** - * Pending suite. - * - * - _Only available when invoked via the mocha CLI._ - */ - xdescribe: PendingSuiteFunction; - - /** - * Pending suite. - * - * - _Only available when invoked via the mocha CLI._ - */ - xcontext: PendingSuiteFunction; - - /** - * Describes a test case. - * - * - _Only available when invoked via the mocha CLI._ - */ - it: TestFunction; - - /** - * Describes a test case. - * - * - _Only available when invoked via the mocha CLI._ - */ - specify: TestFunction; - - /** - * Describes a pending test case. - * - * - _Only available when invoked via the mocha CLI._ - */ - xit: PendingTestFunction; - - /** - * Describes a pending test case. - * - * - _Only available when invoked via the mocha CLI._ - */ - xspecify: PendingTestFunction; - - /** - * Execute before running tests. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#before - */ - suiteSetup: HookFunction; - - /** - * Execute after running tests. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#after - */ - suiteTeardown: HookFunction; - - /** - * Execute before each test case. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#beforeEach - */ - setup: HookFunction; - - /** - * Execute after each test case. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#afterEach - */ - teardown: HookFunction; - - /** - * Describe a "suite" containing nested suites and tests. - * - * - _Only available when invoked via the mocha CLI._ - */ - suite: SuiteFunction; - - /** - * Describes a test case. - * - * - _Only available when invoked via the mocha CLI._ - */ - test: TestFunction; - - run: typeof run; - } - - /** - * Third-party declarations that want to add new entries to the `Reporter` union can - * contribute names here. - */ - interface ReporterContributions { - Base: never; - base: never; - Dot: never; - dot: never; - TAP: never; - tap: never; - JSON: never; - json: never; - HTML: never; - html: never; - List: never; - list: never; - Min: never; - min: never; - Spec: never; - spec: never; - Nyan: never; - nyan: never; - XUnit: never; - xunit: never; - Markdown: never; - markdown: never; - Progress: never; - progress: never; - Landing: never; - landing: never; - JSONStream: never; - "json-stream": never; - } - - type Reporter = keyof ReporterContributions; - - /** - * Third-party declarations that want to add new entries to the `Interface` union can - * contribute names here. - */ - interface InterfaceContributions { - bdd: never; - tdd: never; - qunit: never; - exports: never; - } - - type Interface = keyof InterfaceContributions; - - // #region Deprecations - - /** @deprecated use `Mocha.Context` instead. */ - interface IContext { - test?: IRunnable; - runnable(): IRunnable | undefined; - /** @deprecated `.runnable()` returns `this` in `Mocha.Context`. */ - runnable(runnable: IRunnable): IContext; - timeout(): number; - /** @deprecated `.timeout()` returns `this` in `Mocha.Context`. */ - timeout(timeout: number): IContext; - /** @deprecated `.enableTimeouts()` has additional overloads in `Mocha.Context`. */ - /** @deprecated `.enableTimeouts()` returns `this` in `Mocha.Context`. */ - enableTimeouts(enableTimeouts: boolean): IContext; - /** @deprecated `.slow()` has additional overloads in `Mocha.Context`. */ - /** @deprecated `.slow()` returns `this` in `Mocha.Context`. */ - slow(slow: number): IContext; - /** @deprecated `.skip()` returns `never` in `Mocha.Context`. */ - skip(): IContext; - retries(): number; - /** @deprecated `.retries()` returns `this` in `Mocha.Context`. */ - retries(retries: number): IContext; - } - - /** @deprecated use `Mocha.Suite` instead. */ - interface ISuiteCallbackContext { - /** @deprecated `.timeout()` has additional overloads in `Mocha.Suite`. */ - timeout(ms: number | string): this; - /** @deprecated `.retries()` has additional overloads in `Mocha.Suite`. */ - retries(n: number): this; - /** @deprecated `.slow()` has additional overloads in `Mocha.Suite`. */ - slow(ms: number): this; - } - - /** @deprecated use `Mocha.Context` instead. */ - interface IHookCallbackContext { - /** @deprecated `.skip()` returns `never` in `Mocha.Context`. */ - skip(): this; - /** @deprecated `.timeout()` has additional overloads in `Mocha.Context`. */ - timeout(ms: number | string): this; - [index: string]: any; - } - - /** @deprecated use `Mocha.Context` instead. */ - interface ITestCallbackContext { - /** @deprecated `.skip()` returns `never` in `Mocha.Context`. */ - skip(): this; - /** @deprecated `.timeout()` has additional overloads in `Mocha.Context`. */ - timeout(ms: number | string): this; - /** @deprecated `.retries()` has additional overloads in `Mocha.Context`. */ - retries(n: number): this; - /** @deprecated `.slow()` has additional overloads in `Mocha.Context`. */ - slow(ms: number): this; - [index: string]: any; - } - - /** Partial interface for Mocha's `Runnable` class. */ - /** @deprecated use `Mocha.Runnable` instead. */ - interface IRunnable extends NodeJS.EventEmitter { - title: string; - /** @deprecated `.fn` has type `Func | AsyncFunc` in `Mocha.Runnable`. */ - fn: Function | undefined; - async: boolean; - sync: boolean; - timedOut: boolean; - /** @deprecated `.timeout()` has additional overloads in `Mocha.Runnable`. */ - timeout(n: number | string): this; - duration?: number; - } - - /** Partial interface for Mocha's `Suite` class. */ - /** @deprecated use `Mocha.Suite` instead. */ - interface ISuite { - /** @deprecated `.ctx` has type `Mocha.Context` in `Mocha.Suite`. */ - ctx: IContext; - /** @deprecated `.parent` has type `Mocha.Suite | undefined` in `Mocha.Suite`. */ - parent: ISuite | undefined; - root: boolean; - title: string; - /** @deprecated `.suites` has type `Mocha.Suite[]` in `Mocha.Suite`. */ - suites: ISuite[]; - /** @deprecated `.tests` has type `Mocha.Test[]` in `Mocha.Suite`. */ - tests: ITest[]; - - bail(): boolean; - /** @deprecated `.bail()` returns `this` in `Mocha.Suite`. */ - bail(bail: boolean): ISuite; - fullTitle(): string; - retries(): number; - /** @deprecated `.retries()` returns `this` in `Mocha.Suite`. */ - retries(retries: number): ISuite; - slow(): number; - /** @deprecated `.slow()` returns `this` in `Mocha.Suite`. */ - slow(slow: number): ISuite; - timeout(): number; - /** @deprecated `.timeout()` returns `this` in `Mocha.Suite`. */ - timeout(timeout: number): ISuite; - } - - /** Partial interface for Mocha's `Test` class. */ - /** @deprecated use `Mocha.Test` instead. */ - interface ITest extends IRunnable { - body?: string; - file?: string; - /** @deprecated `.parent` has type `Mocha.Suite | undefined` in `Mocha.Test`. */ - parent?: ISuite; - pending: boolean; - state?: 'failed' | 'passed'; - type: 'test'; - fullTitle(): string; - } - - /** @deprecated use `Mocha.Hook` instead. */ - interface IHook extends IRunnable { - /** @deprecated `.ctx` has type `Mocha.Context` in `Mocha.Runnable`. */ - ctx?: IContext; - /** @deprecated `.parent` has type `Mocha.Suite` in `Mocha.Runnable`. */ - parent?: ISuite; - type: 'hook'; - /** @deprecated `.error()` has additional overloads in `Mocha.Hook`. */ - error(err: Error): void; - } - - /** @deprecated use `Mocha.Context` instead. */ - interface IBeforeAndAfterContext extends IHookCallbackContext { - /** @deprecated `.currentTest` has type `Mocha.Test` in `Mocha.Context`. */ - currentTest?: ITest; - } - - /** @deprecated use `Mocha.Stats` instead. */ - type IStats = Stats; - - /** Partial interface for Mocha's `Runner` class. */ - /** @deprecated use `Mocha.Runner` instead. */ - interface IRunner extends NodeJS.EventEmitter { - asyncOnly?: boolean; - stats?: IStats; - started: boolean; - /** @deprecated `.suite` has type `Mocha.Suite` in `Mocha.Runner`. */ - suite: ISuite; - total: number; - failures: number; - forbidOnly?: boolean; - forbidPending?: boolean; - fullStackTrace?: boolean; - ignoreLeaks?: boolean; - grep(re: RegExp, invert: boolean): this; - /** @deprecated Parameter `suite` has type `Mocha.Suite` in `Mocha.Runner`. */ - grepTotal(suite: ISuite): number; - /** @deprecated `.globals()` has different overloads in `Mocha.Runner`. */ - globals(arr: ReadonlyArray): this | string[]; - abort(): this; - run(fn?: (failures: number) => void): this; - } - - /** @deprecated use `Mocha.SuiteFunction` instead. */ - interface IContextDefinition { - /** @deprecated use `Mocha.SuiteFunction` instead. */ - (description: string, callback: (this: ISuiteCallbackContext) => void): ISuite; - /** @deprecated use `Mocha.SuiteFunction` instead. */ - only(description: string, callback: (this: ISuiteCallbackContext) => void): ISuite; - /** @deprecated use `Mocha.SuiteFunction` instead. */ - skip(description: string, callback: (this: ISuiteCallbackContext) => void): void; - } - - /** @deprecated use `Mocha.TestFunction` instead. */ - interface ITestDefinition { - /** @deprecated use `Mocha.TestFunction` instead. */ - /** @deprecated `Mocha.TestFunction` does not allow mixing `done` with a return type of `PromiseLike`. */ - (expectation: string, callback?: (this: ITestCallbackContext, done: MochaDone) => PromiseLike | void): ITest; - /** @deprecated use `Mocha.TestFunction` instead. */ - /** @deprecated `Mocha.TestFunction#only` does not allow mixing `done` with a return type of `PromiseLike`. */ - only(expectation: string, callback?: (this: ITestCallbackContext, done: MochaDone) => PromiseLike | void): ITest; - /** @deprecated use `Mocha.TestFunction` instead. */ - /** @deprecated `Mocha.TestFunction#skip` does not allow mixing `done` with a return type of `PromiseLike`. */ - skip(expectation: string, callback?: (this: ITestCallbackContext, done: MochaDone) => PromiseLike | void): void; - } - - // #endregion -} - -declare global { - // #region Test interface augmentations - - /** - * Triggers root suite execution. - * - * - _Only available if flag --delay is passed into Mocha._ - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#runWithSuite - */ - function run(): void; - - /** - * Execute before running tests. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#before - */ - var before: Mocha.HookFunction; - - /** - * Execute before running tests. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#before - */ - var suiteSetup: Mocha.HookFunction; - - /** - * Execute after running tests. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#after - */ - var after: Mocha.HookFunction; - - /** - * Execute after running tests. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#after - */ - var suiteTeardown: Mocha.HookFunction; - - /** - * Execute before each test case. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#beforeEach - */ - var beforeEach: Mocha.HookFunction; - - /** - * Execute before each test case. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#beforeEach - */ - var setup: Mocha.HookFunction; - - /** - * Execute after each test case. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#afterEach - */ - var afterEach: Mocha.HookFunction; - - /** - * Execute after each test case. - * - * - _Only available when invoked via the mocha CLI._ - * - * @see https://mochajs.org/api/global.html#afterEach - */ - var teardown: Mocha.HookFunction; - - /** - * Describe a "suite" containing nested suites and tests. - * - * - _Only available when invoked via the mocha CLI._ - */ - var describe: Mocha.SuiteFunction; - - /** - * Describe a "suite" containing nested suites and tests. - * - * - _Only available when invoked via the mocha CLI._ - */ - var context: Mocha.SuiteFunction; - - /** - * Describe a "suite" containing nested suites and tests. - * - * - _Only available when invoked via the mocha CLI._ - */ - var suite: Mocha.SuiteFunction; - - /** - * Pending suite. - * - * - _Only available when invoked via the mocha CLI._ - */ - var xdescribe: Mocha.PendingSuiteFunction; - - /** - * Pending suite. - * - * - _Only available when invoked via the mocha CLI._ - */ - var xcontext: Mocha.PendingSuiteFunction; - - /** - * Describes a test case. - * - * - _Only available when invoked via the mocha CLI._ - */ - var it: Mocha.TestFunction; - - /** - * Describes a test case. - * - * - _Only available when invoked via the mocha CLI._ - */ - var specify: Mocha.TestFunction; - - /** - * Describes a test case. - * - * - _Only available when invoked via the mocha CLI._ - */ - var test: Mocha.TestFunction; - - /** - * Describes a pending test case. - * - * - _Only available when invoked via the mocha CLI._ - */ - var xit: Mocha.PendingTestFunction; - - /** - * Describes a pending test case. - * - * - _Only available when invoked via the mocha CLI._ - */ - var xspecify: Mocha.PendingTestFunction; - - // #endregion Test interface augmentations - - // #region Reporter augmentations - - // Forward declaration for `HTMLLIElement` from lib.dom.d.ts. - // Required by Mocha.reporters.HTML. - // NOTE: Mocha *must not* have a direct dependency on DOM types. - // tslint:disable-next-line no-empty-interface - interface HTMLLIElement { } - - // Augments the DOM `Window` object when lib.dom.d.ts is loaded. - // tslint:disable-next-line no-empty-interface - interface Window extends Mocha.MochaGlobals { } - - namespace NodeJS { - // Forward declaration for `NodeJS.EventEmitter` from node.d.ts. - // Required by Mocha.Runnable, Mocha.Runner, and Mocha.Suite. - // NOTE: Mocha *must not* have a direct dependency on @types/node. - // tslint:disable-next-line no-empty-interface - interface EventEmitter { } - - // Augments NodeJS's `global` object when node.d.ts is loaded - // tslint:disable-next-line no-empty-interface - interface Global extends Mocha.MochaGlobals { } - } - - // #endregion Reporter augmentations - - // #region Browser augmentations - - /** - * Mocha global. - * - * - _Only supported in the browser._ - */ - const mocha: BrowserMocha; - - interface BrowserMocha extends Mocha { - /** - * Function to allow assertion libraries to throw errors directly into mocha. - * This is useful when running tests in a browser because window.onerror will - * only receive the 'message' attribute of the Error. - * - * - _Only supported in the browser._ - */ - throwError(err: any): never; - - /** - * Setup mocha with the given settings options. - * - * - _Only supported in the browser._ - */ - setup(opts?: Mocha.Interface | MochaSetupOptions): this; - } - - /** - * Options to pass to `mocha.setup` in the browser. - */ - interface MochaSetupOptions extends Mocha.MochaOptions { - // TODO: This does not seem to be supported according to the source. Should it be removed? - require?: string[]; - fullTrace?: boolean; - } - - // #endregion Browser augmentations - - // #region Deprecations - - /** @deprecated use `Mocha.DoneCallback` instead. */ - type MochaDone = Mocha.Done; - - /** @deprecated use `Mocha.ReporterConstructor` instead. */ - type ReporterConstructor = Mocha.ReporterConstructor; - - // #endregion Deprecations -} diff --git a/scripts/types/mocha/lib/interfaces/common.d.ts b/scripts/types/mocha/lib/interfaces/common.d.ts deleted file mode 100644 index 1deb9712e6b..00000000000 --- a/scripts/types/mocha/lib/interfaces/common.d.ts +++ /dev/null @@ -1,109 +0,0 @@ -import Mocha = require("../../"); - -export = common; - -declare function common(suites: Mocha.Suite[], context: Mocha.MochaGlobals, mocha: Mocha): common.CommonFunctions; - -declare namespace common { - export interface CommonFunctions { - /** - * This is only present if flag --delay is passed into Mocha. It triggers - * root suite execution. - */ - runWithSuite(suite: Mocha.Suite): () => void; - - /** - * Execute before running tests. - */ - before(fn?: Mocha.Func | Mocha.AsyncFunc): void; - - /** - * Execute before running tests. - */ - before(name: string, fn?: Mocha.Func | Mocha.AsyncFunc): void; - - /** - * Execute after running tests. - */ - after(fn?: Mocha.Func | Mocha.AsyncFunc): void; - - /** - * Execute after running tests. - */ - after(name: string, fn?: Mocha.Func | Mocha.AsyncFunc): void; - - /** - * Execute before each test case. - */ - beforeEach(fn?: Mocha.Func | Mocha.AsyncFunc): void; - - /** - * Execute before each test case. - */ - beforeEach(name: string, fn?: Mocha.Func | Mocha.AsyncFunc): void; - - /** - * Execute after each test case. - */ - afterEach(fn?: Mocha.Func | Mocha.AsyncFunc): void; - - /** - * Execute after each test case. - */ - afterEach(name: string, fn?: Mocha.Func | Mocha.AsyncFunc): void; - - suite: SuiteFunctions; - test: TestFunctions; - } - - export interface CreateOptions { - /** Title of suite */ - title: string; - - /** Suite function */ - fn?: (this: Mocha.Suite) => void; - - /** Is suite pending? */ - pending?: boolean; - - /** Filepath where this Suite resides */ - file?: string; - - /** Is suite exclusive? */ - isOnly?: boolean; - } - - export interface SuiteFunctions { - /** - * Create an exclusive Suite; convenience function - */ - only(opts: CreateOptions): Mocha.Suite; - - /** - * Create a Suite, but skip it; convenience function - */ - skip(opts: CreateOptions): Mocha.Suite; - - /** - * Creates a suite. - */ - create(opts: CreateOptions): Mocha.Suite; - } - - export interface TestFunctions { - /** - * Exclusive test-case. - */ - only(mocha: Mocha, test: Mocha.Test): Mocha.Test; - - /** - * Pending test case. - */ - skip(title: string): void; - - /** - * Number of retry attempts - */ - retries(n: number): void; - } -} diff --git a/scripts/types/mocha/lib/ms.d.ts b/scripts/types/mocha/lib/ms.d.ts deleted file mode 100644 index 890da5b8c5a..00000000000 --- a/scripts/types/mocha/lib/ms.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -export = milliseconds; - -/** - * Parse the given `str` and return milliseconds. - * - * @see {@link https://mochajs.org/api/module-milliseconds.html} - * @see {@link https://mochajs.org/api/module-milliseconds.html#~parse} - */ -declare function milliseconds(val: string): number; - -/** - * Format for `ms`. - * - * @see {@link https://mochajs.org/api/module-milliseconds.html} - * @see {@link https://mochajs.org/api/module-milliseconds.html#~format} - */ -declare function milliseconds(val: number): string; diff --git a/scripts/types/mocha/package.json b/scripts/types/mocha/package.json deleted file mode 100644 index e45485e803b..00000000000 --- a/scripts/types/mocha/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "@types/mocha", - "private": true, - "version": "5.2.1" -} diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 179e5fb04d0..510f03ec41b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -228,9 +228,9 @@ namespace ts { isContextSensitive, getFullyQualifiedName, getResolvedSignature: (node, candidatesOutArray, agumentCount) => - getResolvedSignatureWorker(node, candidatesOutArray, agumentCount, /*isForSignatureHelp*/ false), + getResolvedSignatureWorker(node, candidatesOutArray, agumentCount, CheckMode.Normal), getResolvedSignatureForSignatureHelp: (node, candidatesOutArray, agumentCount) => - getResolvedSignatureWorker(node, candidatesOutArray, agumentCount, /*isForSignatureHelp*/ true), + getResolvedSignatureWorker(node, candidatesOutArray, agumentCount, CheckMode.IsForSignatureHelp), getConstantValue: nodeIn => { const node = getParseTreeNode(nodeIn, canHaveConstantValue); return node ? getConstantValue(node) : undefined; @@ -374,10 +374,10 @@ namespace ts { getLocalTypeParametersOfClassOrInterfaceOrTypeAlias, }; - function getResolvedSignatureWorker(nodeIn: CallLikeExpression, candidatesOutArray: Signature[] | undefined, argumentCount: number | undefined, isForSignatureHelp: boolean): Signature | undefined { + function getResolvedSignatureWorker(nodeIn: CallLikeExpression, candidatesOutArray: Signature[] | undefined, argumentCount: number | undefined, checkMode: CheckMode): Signature | undefined { const node = getParseTreeNode(nodeIn, isCallLikeExpression); apparentArgumentCount = argumentCount; - const res = node ? getResolvedSignature(node, candidatesOutArray, isForSignatureHelp) : undefined; + const res = node ? getResolvedSignature(node, candidatesOutArray, checkMode) : undefined; apparentArgumentCount = undefined; return res; } @@ -688,10 +688,12 @@ namespace ts { } const enum CheckMode { - Normal = 0, // Normal type checking - SkipContextSensitive = 1, // Skip context sensitive function expressions - Inferential = 2, // Inferential typing - Contextual = 3, // Normal type checking informed by a contextual type, therefore not cacheable + Normal = 0, // Normal type checking + Contextual = 1 << 0, // Explicitly assigned contextual type, therefore not cacheable + Inferential = 1 << 1, // Inferential typing + SkipContextSensitive = 1 << 2, // Skip context sensitive function expressions + SkipGenericFunctions = 1 << 3, // Skip single signature generic functions + IsForSignatureHelp = 1 << 4, // Call resolution for purposes of signature help } const enum CallbackCheck { @@ -3981,7 +3983,7 @@ namespace ts { context.flags &= ~NodeBuilderFlags.WriteTypeParametersInQualifiedName; // Avoids potential infinite loop when building for a claimspace with a generic const shouldUseGeneratedName = context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams && - type.symbol.declarations[0] && + type.symbol.declarations && type.symbol.declarations[0] && isTypeParameterDeclaration(type.symbol.declarations[0]) && typeParameterShadowsNameInScope(type, context); const name = shouldUseGeneratedName @@ -8373,9 +8375,23 @@ namespace ts { return undefined; } - function getSignatureInstantiation(signature: Signature, typeArguments: Type[] | undefined, isJavascript: boolean): Signature { - return getSignatureInstantiationWithoutFillingInTypeArguments(signature, fillMissingTypeArguments(typeArguments, signature.typeParameters, getMinTypeArgumentCount(signature.typeParameters), isJavascript)); + function getSignatureInstantiation(signature: Signature, typeArguments: Type[] | undefined, isJavascript: boolean, inferredTypeParameters?: ReadonlyArray): Signature { + const instantiatedSignature = getSignatureInstantiationWithoutFillingInTypeArguments(signature, fillMissingTypeArguments(typeArguments, signature.typeParameters, getMinTypeArgumentCount(signature.typeParameters), isJavascript)); + if (inferredTypeParameters) { + const returnSignature = getSingleCallSignature(getReturnTypeOfSignature(instantiatedSignature)); + if (returnSignature) { + const newReturnSignature = cloneSignature(returnSignature); + newReturnSignature.typeParameters = inferredTypeParameters; + newReturnSignature.target = returnSignature.target; + newReturnSignature.mapper = returnSignature.mapper; + const newInstantiatedSignature = cloneSignature(instantiatedSignature); + newInstantiatedSignature.resolvedReturnType = getOrCreateTypeFromSignature(newReturnSignature); + return newInstantiatedSignature; + } + } + return instantiatedSignature; } + function getSignatureInstantiationWithoutFillingInTypeArguments(signature: Signature, typeArguments: ReadonlyArray | undefined): Signature { const instantiations = signature.instantiations || (signature.instantiations = createMap()); const id = getTypeListId(typeArguments); @@ -8389,6 +8405,7 @@ namespace ts { function createSignatureInstantiation(signature: Signature, typeArguments: ReadonlyArray | undefined): Signature { return instantiateSignature(signature, createSignatureTypeMapper(signature, typeArguments), /*eraseTypeParameters*/ true); } + function createSignatureTypeMapper(signature: Signature, typeArguments: ReadonlyArray | undefined): TypeMapper { return createTypeMapper(signature.typeParameters!, typeArguments); } @@ -8790,7 +8807,7 @@ namespace ts { function getTypeReferenceTypeWorker(node: NodeWithTypeArguments, symbol: Symbol, typeArguments: Type[] | undefined): Type | undefined { if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { - if (symbol.valueDeclaration && isBinaryExpression(symbol.valueDeclaration.parent)) { + if (symbol.valueDeclaration && symbol.valueDeclaration.parent && isBinaryExpression(symbol.valueDeclaration.parent)) { const jsdocType = getJSDocTypeReference(node, symbol, typeArguments); if (jsdocType) { return jsdocType; @@ -20035,27 +20052,36 @@ namespace ts { // Instantiate a generic signature in the context of a non-generic signature (section 3.8.5 in TypeScript spec) function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, contextualMapper?: TypeMapper, compareTypes?: TypeComparer): Signature { const context = createInferenceContext(signature.typeParameters!, signature, InferenceFlags.None, compareTypes); - const sourceSignature = contextualMapper ? instantiateSignature(contextualSignature, contextualMapper) : contextualSignature; + // We clone the contextualMapper to avoid fixing. For example, when the source signature is (x: T) => T[] and + // the contextual signature is (...args: A) => B, we want to infer the element type of A's constraint (say 'any') + // for T but leave it possible to later infer '[any]' back to A. + const restType = getEffectiveRestType(contextualSignature); + const mapper = contextualMapper && restType && restType.flags & TypeFlags.TypeParameter ? cloneTypeMapper(contextualMapper) : contextualMapper; + const sourceSignature = mapper ? instantiateSignature(contextualSignature, mapper) : contextualSignature; forEachMatchingParameterType(sourceSignature, signature, (source, target) => { // Type parameters from outer context referenced by source type are fixed by instantiation of the source type inferTypes(context.inferences, source, target); }); if (!contextualMapper) { inferTypes(context.inferences, getReturnTypeOfSignature(contextualSignature), getReturnTypeOfSignature(signature), InferencePriority.ReturnType); + const signaturePredicate = getTypePredicateOfSignature(signature); + const contextualPredicate = getTypePredicateOfSignature(sourceSignature); + if (signaturePredicate && contextualPredicate && signaturePredicate.kind === contextualPredicate.kind && + (signaturePredicate.kind === TypePredicateKind.This || signaturePredicate.parameterIndex === (contextualPredicate as IdentifierTypePredicate).parameterIndex)) { + inferTypes(context.inferences, contextualPredicate.type, signaturePredicate.type, InferencePriority.ReturnType); + } } return getSignatureInstantiation(signature, getInferredTypes(context), isInJSFile(contextualSignature.declaration)); } - function inferJsxTypeArguments(node: JsxOpeningLikeElement, signature: Signature, excludeArgument: ReadonlyArray | undefined, context: InferenceContext): Type[] { + function inferJsxTypeArguments(node: JsxOpeningLikeElement, signature: Signature, checkMode: CheckMode, context: InferenceContext): Type[] { const paramType = getEffectiveFirstArgumentForJsxSignature(signature, node); - - const checkAttrType = checkExpressionWithContextualType(node.attributes, paramType, excludeArgument && excludeArgument[0] !== undefined ? identityMapper : context); + const checkAttrType = checkExpressionWithContextualType(node.attributes, paramType, context, checkMode); inferTypes(context.inferences, checkAttrType, paramType); - return getInferredTypes(context); } - function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: ReadonlyArray, excludeArgument: ReadonlyArray | undefined, context: InferenceContext): Type[] { + function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: ReadonlyArray, checkMode: CheckMode, context: InferenceContext): Type[] { // Clear out all the inference results from the last time inferTypeArguments was called on this context for (const inference of context.inferences) { // As an optimization, we don't have to clear (and later recompute) inferred types @@ -20068,7 +20094,7 @@ namespace ts { } if (isJsxOpeningLikeElement(node)) { - return inferJsxTypeArguments(node, signature, excludeArgument, context); + return inferJsxTypeArguments(node, signature, checkMode, context); } // If a contextual type is available, infer from that type to the return type of the call expression. For @@ -20115,10 +20141,7 @@ namespace ts { const arg = args[i]; if (arg.kind !== SyntaxKind.OmittedExpression) { const paramType = getTypeAtPosition(signature, i); - // For context sensitive arguments we pass the identityMapper, which is a signal to treat all - // context sensitive function expressions as wildcards - const mapper = excludeArgument && excludeArgument[i] !== undefined ? identityMapper : context; - const argType = checkExpressionWithContextualType(arg, paramType, mapper); + const argType = checkExpressionWithContextualType(arg, paramType, context, checkMode); inferTypes(context.inferences, argType, paramType); } } @@ -20146,7 +20169,7 @@ namespace ts { // and the argument are ...x forms. return arg.kind === SyntaxKind.SyntheticExpression ? createArrayType((arg).type) : - getArrayifiedType(checkExpressionWithContextualType((arg).expression, restType, context)); + getArrayifiedType(checkExpressionWithContextualType((arg).expression, restType, context, CheckMode.Normal)); } } const contextualType = getIndexTypeOfType(restType, IndexKind.Number) || anyType; @@ -20154,7 +20177,7 @@ namespace ts { const types = []; let spreadIndex = -1; for (let i = index; i < argCount; i++) { - const argType = checkExpressionWithContextualType(args[i], contextualType, context); + const argType = checkExpressionWithContextualType(args[i], contextualType, context, CheckMode.Normal); if (spreadIndex < 0 && isSpreadArgument(args[i])) { spreadIndex = i - index; } @@ -20212,14 +20235,13 @@ namespace ts { * @param node a JSX opening-like element we are trying to figure its call signature * @param signature a candidate signature we are trying whether it is a call signature * @param relation a relationship to check parameter and argument type - * @param excludeArgument */ - function checkApplicableSignatureForJsxOpeningLikeElement(node: JsxOpeningLikeElement, signature: Signature, relation: Map, excludeArgument: boolean[] | undefined, reportErrors: boolean) { + function checkApplicableSignatureForJsxOpeningLikeElement(node: JsxOpeningLikeElement, signature: Signature, relation: Map, checkMode: CheckMode, reportErrors: boolean) { // Stateless function components can have maximum of three arguments: "props", "context", and "updater". // However "context" and "updater" are implicit and can't be specify by users. Only the first parameter, props, // can be specified by users through attributes property. const paramType = getEffectiveFirstArgumentForJsxSignature(signature, node); - const attributesType = checkExpressionWithContextualType(node.attributes, paramType, excludeArgument && excludeArgument[0] ? identityMapper : undefined); + const attributesType = checkExpressionWithContextualType(node.attributes, paramType, /*contextualMapper*/ undefined, checkMode); return checkTypeRelatedToAndOptionallyElaborate(attributesType, paramType, relation, reportErrors ? node.tagName : undefined, node.attributes); } @@ -20228,10 +20250,10 @@ namespace ts { args: ReadonlyArray, signature: Signature, relation: Map, - excludeArgument: boolean[] | undefined, + checkMode: CheckMode, reportErrors: boolean) { if (isJsxOpeningLikeElement(node)) { - return checkApplicableSignatureForJsxOpeningLikeElement(node, signature, relation, excludeArgument, reportErrors); + return checkApplicableSignatureForJsxOpeningLikeElement(node, signature, relation, checkMode, reportErrors); } const thisType = getThisTypeOfSignature(signature); if (thisType && thisType !== voidType && node.kind !== SyntaxKind.NewExpression) { @@ -20253,11 +20275,11 @@ namespace ts { const arg = args[i]; if (arg.kind !== SyntaxKind.OmittedExpression) { const paramType = getTypeAtPosition(signature, i); - const argType = checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined); - // If one or more arguments are still excluded (as indicated by a non-null excludeArgument parameter), + const argType = checkExpressionWithContextualType(arg, paramType, /*contextualMapper*/ undefined, checkMode); + // If one or more arguments are still excluded (as indicated by CheckMode.SkipContextSensitive), // we obtain the regular type of any object literal arguments because we may not have inferred complete // parameter types yet and therefore excess property checks may yield false positives (see #17041). - const checkArgType = excludeArgument ? getRegularTypeOfObjectLiteral(argType) : argType; + const checkArgType = checkMode & CheckMode.SkipContextSensitive ? getRegularTypeOfObjectLiteral(argType) : argType; if (!checkTypeRelatedToAndOptionallyElaborate(checkArgType, paramType, relation, reportErrors ? arg : undefined, arg, headMessage)) { return false; } @@ -20473,7 +20495,7 @@ namespace ts { return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount); } - function resolveCall(node: CallLikeExpression, signatures: ReadonlyArray, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean, fallbackError?: DiagnosticMessage): Signature { + function resolveCall(node: CallLikeExpression, signatures: ReadonlyArray, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, fallbackError?: DiagnosticMessage): Signature { const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression; const isDecorator = node.kind === SyntaxKind.Decorator; const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node); @@ -20515,7 +20537,7 @@ namespace ts { // For a decorator, no arguments are susceptible to contextual typing due to the fact // decorators are applied to a declaration by the emitter, and not to an expression. const isSingleNonGenericCandidate = candidates.length === 1 && !candidates[0].typeParameters; - let excludeArgument = !isDecorator && !isSingleNonGenericCandidate ? getExcludeArgument(args) : undefined; + let argCheckMode = !isDecorator && !isSingleNonGenericCandidate && some(args, isContextSensitive) ? CheckMode.SkipContextSensitive : CheckMode.Normal; // The following variables are captured and modified by calls to chooseOverload. // If overload resolution or type argument inference fails, we want to report the @@ -20546,7 +20568,7 @@ namespace ts { // If we are in signature help, a trailing comma indicates that we intend to provide another argument, // so we will only accept overloads with arity at least 1 higher than the current number of provided arguments. const signatureHelpTrailingComma = - isForSignatureHelp && node.kind === SyntaxKind.CallExpression && node.arguments.hasTrailingComma; + !!(checkMode & CheckMode.IsForSignatureHelp) && node.kind === SyntaxKind.CallExpression && node.arguments.hasTrailingComma; // Section 4.12.1: // if the candidate list contains one or more signatures for which the type of each argument @@ -20574,12 +20596,7 @@ namespace ts { // skip the checkApplicableSignature check. if (reportErrors) { if (candidateForArgumentError) { - // excludeArgument is undefined, in this case also equivalent to [undefined, undefined, ...] - // The importance of excludeArgument is to prevent us from typing function expression parameters - // in arguments too early. If possible, we'd like to only type them once we know the correct - // overload. However, this matters for the case where the call is correct. When the call is - // an error, we don't need to exclude any arguments, although it would cause no harm to do so. - checkApplicableSignature(node, args, candidateForArgumentError, assignableRelation, /*excludeArgument*/ undefined, /*reportErrors*/ true); + checkApplicableSignature(node, args, candidateForArgumentError, assignableRelation, CheckMode.Normal, /*reportErrors*/ true); } else if (candidateForArgumentArityError) { diagnostics.add(getArgumentArityError(node, [candidateForArgumentArityError], args)); @@ -20613,7 +20630,7 @@ namespace ts { if (typeArguments || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) { return undefined; } - if (!checkApplicableSignature(node, args, candidate, relation, excludeArgument, /*reportErrors*/ false)) { + if (!checkApplicableSignature(node, args, candidate, relation, CheckMode.Normal, /*reportErrors*/ false)) { candidateForArgumentError = candidate; return undefined; } @@ -20640,9 +20657,10 @@ namespace ts { } else { inferenceContext = createInferenceContext(candidate.typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None); - typeArgumentTypes = inferTypeArguments(node, candidate, args, excludeArgument, inferenceContext); + typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode | CheckMode.SkipGenericFunctions, inferenceContext); + argCheckMode |= inferenceContext.flags & InferenceFlags.SkippedGenericFunction ? CheckMode.SkipGenericFunctions : CheckMode.Normal; } - checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration)); + checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext && inferenceContext.inferredTypeParameters); // If the original signature has a generic rest type, instantiation may produce a // signature with different arity and we need to perform another arity check. if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) { @@ -20653,21 +20671,21 @@ namespace ts { else { checkCandidate = candidate; } - if (!checkApplicableSignature(node, args, checkCandidate, relation, excludeArgument, /*reportErrors*/ false)) { + if (!checkApplicableSignature(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false)) { // Give preference to error candidates that have no rest parameters (as they are more specific) if (!candidateForArgumentError || getEffectiveRestType(candidateForArgumentError) || !getEffectiveRestType(checkCandidate)) { candidateForArgumentError = checkCandidate; } continue; } - if (excludeArgument) { + if (argCheckMode) { // If one or more context sensitive arguments were excluded, we start including // them now (and keeping do so for any subsequent candidates) and perform a second // round of type inference and applicability checking for this particular candidate. - excludeArgument = undefined; + argCheckMode = CheckMode.Normal; if (inferenceContext) { - const typeArgumentTypes = inferTypeArguments(node, candidate, args, excludeArgument, inferenceContext); - checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration)); + const typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode, inferenceContext); + checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext && inferenceContext.inferredTypeParameters); // If the original signature has a generic rest type, instantiation may produce a // signature with different arity and we need to perform another arity check. if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) { @@ -20675,7 +20693,7 @@ namespace ts { continue; } } - if (!checkApplicableSignature(node, args, checkCandidate, relation, excludeArgument, /*reportErrors*/ false)) { + if (!checkApplicableSignature(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false)) { // Give preference to error candidates that have no rest parameters (as they are more specific) if (!candidateForArgumentError || getEffectiveRestType(candidateForArgumentError) || !getEffectiveRestType(checkCandidate)) { candidateForArgumentError = checkCandidate; @@ -20691,21 +20709,6 @@ namespace ts { } } - function getExcludeArgument(args: ReadonlyArray): boolean[] | undefined { - let excludeArgument: boolean[] | undefined; - // We do not need to call `getEffectiveArgumentCount` here as it only - // applies when calculating the number of arguments for a decorator. - for (let i = 0; i < args.length; i++) { - if (isContextSensitive(args[i])) { - if (!excludeArgument) { - excludeArgument = new Array(args.length); - } - excludeArgument[i] = true; - } - } - return excludeArgument; - } - // No signature was applicable. We have already reported the errors for the invalid signature. // If this is a type resolution session, e.g. Language Service, try to get better information than anySignature. function getCandidateForOverloadFailure( @@ -20805,7 +20808,7 @@ namespace ts { function inferSignatureInstantiationForOverloadFailure(node: CallLikeExpression, typeParameters: ReadonlyArray, candidate: Signature, args: ReadonlyArray): Signature { const inferenceContext = createInferenceContext(typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None); - const typeArgumentTypes = inferTypeArguments(node, candidate, args, getExcludeArgument(args), inferenceContext); + const typeArgumentTypes = inferTypeArguments(node, candidate, args, CheckMode.SkipContextSensitive | CheckMode.SkipGenericFunctions, inferenceContext); return createSignatureInstantiation(candidate, typeArgumentTypes); } @@ -20828,7 +20831,7 @@ namespace ts { return maxParamsIndex; } - function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean): Signature { + function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { if (node.expression.kind === SyntaxKind.SuperKeyword) { const superType = checkSuperExpression(node.expression); if (isTypeAny(superType)) { @@ -20843,7 +20846,7 @@ namespace ts { const baseTypeNode = getEffectiveBaseTypeNode(getContainingClass(node)!); if (baseTypeNode) { const baseConstructors = getInstantiatedConstructorsForTypeArguments(superType, baseTypeNode.typeArguments, baseTypeNode); - return resolveCall(node, baseConstructors, candidatesOutArray, isForSignatureHelp); + return resolveCall(node, baseConstructors, candidatesOutArray, checkMode); } } return resolveUntypedCall(node); @@ -20903,12 +20906,32 @@ namespace ts { } return resolveErrorCall(node); } + // When a call to a generic function is an argument to an outer call to a generic function for which + // inference is in process, we have a choice to make. If the inner call relies on inferences made from + // its contextual type to its return type, deferring the inner call processing allows the best possible + // contextual type to accumulate. But if the outer call relies on inferences made from the return type of + // the inner call, the inner call should be processed early. There's no sure way to know which choice is + // right (only a full unification algorithm can determine that), so we resort to the following heuristic: + // If no type arguments are specified in the inner call and at least one call signature is generic and + // returns a function type, we choose to defer processing. This narrowly permits function composition + // operators to flow inferences through return types, but otherwise processes calls right away. We + // use the resolvingSignature singleton to indicate that we deferred processing. This result will be + // propagated out and eventually turned into silentNeverType (a type that is assignable to anything and + // from which we never make inferences). + if (checkMode & CheckMode.SkipGenericFunctions && !node.typeArguments && callSignatures.some(isGenericFunctionReturningFunction)) { + skippedGenericFunction(node, checkMode); + return resolvingSignature; + } // If the function is explicitly marked with `@class`, then it must be constructed. if (callSignatures.some(sig => isInJSFile(sig.declaration) && !!getJSDocClassTag(sig.declaration!))) { error(node, Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(funcType)); return resolveErrorCall(node); } - return resolveCall(node, callSignatures, candidatesOutArray, isForSignatureHelp); + return resolveCall(node, callSignatures, candidatesOutArray, checkMode); + } + + function isGenericFunctionReturningFunction(signature: Signature) { + return !!(signature.typeParameters && isFunctionType(getReturnTypeOfSignature(signature))); } /** @@ -20922,7 +20945,7 @@ namespace ts { !numCallSignatures && !numConstructSignatures && !(apparentFuncType.flags & (TypeFlags.Union | TypeFlags.Never)) && isTypeAssignableTo(funcType, globalFunctionType); } - function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean): Signature { + function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { if (node.arguments && languageVersion < ScriptTarget.ES5) { const spreadIndex = getSpreadArgumentIndex(node.arguments); if (spreadIndex >= 0) { @@ -20975,7 +20998,7 @@ namespace ts { return resolveErrorCall(node); } - return resolveCall(node, constructSignatures, candidatesOutArray, isForSignatureHelp); + return resolveCall(node, constructSignatures, candidatesOutArray, checkMode); } // If expressionType's apparent type is an object type with no construct signatures but @@ -20984,7 +21007,7 @@ namespace ts { // operation is Any. It is an error to have a Void this type. const callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call); if (callSignatures.length) { - const signature = resolveCall(node, callSignatures, candidatesOutArray, isForSignatureHelp); + const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode); if (!noImplicitAny) { if (signature.declaration && !isJSConstructor(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) { error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword); @@ -21094,7 +21117,7 @@ namespace ts { } } - function resolveTaggedTemplateExpression(node: TaggedTemplateExpression, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean): Signature { + function resolveTaggedTemplateExpression(node: TaggedTemplateExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { const tagType = checkExpression(node.tag); const apparentType = getApparentType(tagType); @@ -21115,7 +21138,7 @@ namespace ts { return resolveErrorCall(node); } - return resolveCall(node, callSignatures, candidatesOutArray, isForSignatureHelp); + return resolveCall(node, callSignatures, candidatesOutArray, checkMode); } /** @@ -21146,7 +21169,7 @@ namespace ts { /** * Resolves a decorator as if it were a call expression. */ - function resolveDecorator(node: Decorator, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean): Signature { + function resolveDecorator(node: Decorator, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { const funcType = checkExpression(node.expression); const apparentType = getApparentType(funcType); if (apparentType === errorType) { @@ -21175,7 +21198,7 @@ namespace ts { return resolveErrorCall(node); } - return resolveCall(node, callSignatures, candidatesOutArray, isForSignatureHelp, headMessage); + return resolveCall(node, callSignatures, candidatesOutArray, checkMode, headMessage); } function createSignatureForJSXIntrinsic(node: JsxOpeningLikeElement, result: Type): Signature { @@ -21204,11 +21227,11 @@ namespace ts { ); } - function resolveJsxOpeningLikeElement(node: JsxOpeningLikeElement, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean): Signature { + function resolveJsxOpeningLikeElement(node: JsxOpeningLikeElement, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { if (isJsxIntrinsicIdentifier(node.tagName)) { const result = getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node); const fakeSignature = createSignatureForJSXIntrinsic(node, result); - checkTypeAssignableToAndOptionallyElaborate(checkExpressionWithContextualType(node.attributes, getEffectiveFirstArgumentForJsxSignature(fakeSignature, node), /*mapper*/ undefined), result, node.tagName, node.attributes); + checkTypeAssignableToAndOptionallyElaborate(checkExpressionWithContextualType(node.attributes, getEffectiveFirstArgumentForJsxSignature(fakeSignature, node), /*mapper*/ undefined, CheckMode.Normal), result, node.tagName, node.attributes); return fakeSignature; } const exprTypes = checkExpression(node.tagName); @@ -21228,7 +21251,7 @@ namespace ts { return resolveErrorCall(node); } - return resolveCall(node, signatures, candidatesOutArray, isForSignatureHelp); + return resolveCall(node, signatures, candidatesOutArray, checkMode); } /** @@ -21243,19 +21266,19 @@ namespace ts { signature.parameters.length < getDecoratorArgumentCount(decorator, signature)); } - function resolveSignature(node: CallLikeExpression, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean): Signature { + function resolveSignature(node: CallLikeExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { switch (node.kind) { case SyntaxKind.CallExpression: - return resolveCallExpression(node, candidatesOutArray, isForSignatureHelp); + return resolveCallExpression(node, candidatesOutArray, checkMode); case SyntaxKind.NewExpression: - return resolveNewExpression(node, candidatesOutArray, isForSignatureHelp); + return resolveNewExpression(node, candidatesOutArray, checkMode); case SyntaxKind.TaggedTemplateExpression: - return resolveTaggedTemplateExpression(node, candidatesOutArray, isForSignatureHelp); + return resolveTaggedTemplateExpression(node, candidatesOutArray, checkMode); case SyntaxKind.Decorator: - return resolveDecorator(node, candidatesOutArray, isForSignatureHelp); + return resolveDecorator(node, candidatesOutArray, checkMode); case SyntaxKind.JsxOpeningElement: case SyntaxKind.JsxSelfClosingElement: - return resolveJsxOpeningLikeElement(node, candidatesOutArray, isForSignatureHelp); + return resolveJsxOpeningLikeElement(node, candidatesOutArray, checkMode); } throw Debug.assertNever(node, "Branch in 'resolveSignature' should be unreachable."); } @@ -21267,7 +21290,7 @@ namespace ts { * the function will fill it up with appropriate candidate signatures * @return a signature of the call-like expression or undefined if one can't be found */ - function getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[] | undefined, isForSignatureHelp = false): Signature { + function getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[] | undefined, checkMode?: CheckMode): Signature { const links = getNodeLinks(node); // If getResolvedSignature has already been called, we will have cached the resolvedSignature. // However, it is possible that either candidatesOutArray was not passed in the first time, @@ -21278,11 +21301,15 @@ namespace ts { return cached; } links.resolvedSignature = resolvingSignature; - const result = resolveSignature(node, candidatesOutArray, isForSignatureHelp); - // If signature resolution originated in control flow type analysis (for example to compute the - // assigned type in a flow assignment) we don't cache the result as it may be based on temporary - // types from the control flow analysis. - links.resolvedSignature = flowLoopStart === flowLoopCount ? result : cached; + const result = resolveSignature(node, candidatesOutArray, checkMode || CheckMode.Normal); + // When CheckMode.SkipGenericFunctions is set we use resolvingSignature to indicate that call + // resolution should be deferred. + if (result !== resolvingSignature) { + // If signature resolution originated in control flow type analysis (for example to compute the + // assigned type in a flow assignment) we don't cache the result as it may be based on temporary + // types from the control flow analysis. + links.resolvedSignature = flowLoopStart === flowLoopCount ? result : cached; + } return result; } @@ -21366,10 +21393,15 @@ namespace ts { * @param node The call/new expression to be checked. * @returns On success, the expression's signature's return type. On failure, anyType. */ - function checkCallExpression(node: CallExpression | NewExpression): Type { + function checkCallExpression(node: CallExpression | NewExpression, checkMode?: CheckMode): Type { if (!checkGrammarTypeArguments(node, node.typeArguments)) checkGrammarArguments(node.arguments); - const signature = getResolvedSignature(node); + const signature = getResolvedSignature(node, /*candidatesOutArray*/ undefined, checkMode); + if (signature === resolvingSignature) { + // CheckMode.SkipGenericFunctions is enabled and this is a call to a generic function that + // returns a function type. We defer checking and return anyFunctionType. + return silentNeverType; + } if (node.expression.kind === SyntaxKind.SuperKeyword) { return voidType; @@ -21870,7 +21902,7 @@ namespace ts { const functionFlags = getFunctionFlags(func); let type: Type; if (func.body.kind !== SyntaxKind.Block) { - type = checkExpressionCached(func.body, checkMode); + type = checkExpressionCached(func.body, checkMode && checkMode & ~CheckMode.SkipGenericFunctions); if (functionFlags & FunctionFlags.Async) { // From within an async function you can return either a non-promise value or a promise. Any // Promise/A+ compatible implementation will always assimilate any foreign promise, so the @@ -22060,7 +22092,7 @@ namespace ts { forEachReturnStatement(func.body, returnStatement => { const expr = returnStatement.expression; if (expr) { - let type = checkExpressionCached(expr, checkMode); + let type = checkExpressionCached(expr, checkMode && checkMode & ~CheckMode.SkipGenericFunctions); if (functionFlags & FunctionFlags.Async) { // From within an async function you can return either a non-promise value or a promise. Any // Promise/A+ compatible implementation will always assimilate any foreign promise, so the @@ -22160,7 +22192,7 @@ namespace ts { checkNodeDeferred(node); // The identityMapper object is used to indicate that function expressions are wildcards - if (checkMode === CheckMode.SkipContextSensitive && isContextSensitive(node)) { + if (checkMode && checkMode & CheckMode.SkipContextSensitive && isContextSensitive(node)) { // Skip parameters, return signature with return type that retains noncontextual parts so inferences can still be drawn in an early stage if (!getEffectiveReturnTypeNode(node) && hasContextSensitiveReturnExpression(node)) { const links = getNodeLinks(node); @@ -22200,7 +22232,7 @@ namespace ts { const signature = getSignaturesOfType(type, SignatureKind.Call)[0]; if (isContextSensitive(node)) { const contextualMapper = getContextualMapper(node); - if (checkMode === CheckMode.Inferential) { + if (checkMode && checkMode & CheckMode.Inferential) { inferFromAnnotatedParameters(signature, contextualSignature, contextualMapper); } const instantiatedContextualSignature = contextualMapper === identityMapper ? @@ -23211,15 +23243,13 @@ namespace ts { return node; } - function checkExpressionWithContextualType(node: Expression, contextualType: Type, contextualMapper: TypeMapper | undefined): Type { + function checkExpressionWithContextualType(node: Expression, contextualType: Type, contextualMapper: TypeMapper | undefined, checkMode: CheckMode): Type { const context = getContextNode(node); const saveContextualType = context.contextualType; const saveContextualMapper = context.contextualMapper; context.contextualType = contextualType; context.contextualMapper = contextualMapper; - const checkMode = contextualMapper === identityMapper ? CheckMode.SkipContextSensitive : - contextualMapper ? CheckMode.Inferential : CheckMode.Contextual; - const type = checkExpression(node, checkMode); + const type = checkExpression(node, checkMode | CheckMode.Contextual | (contextualMapper ? CheckMode.Inferential : 0)); // We strip literal freshness when an appropriate contextual type is present such that contextually typed // literals always preserve their literal types (otherwise they might widen during type inference). An alternative // here would be to not mark contextually typed literals as fresh in the first place. @@ -23233,7 +23263,7 @@ namespace ts { function checkExpressionCached(node: Expression, checkMode?: CheckMode): Type { const links = getNodeLinks(node); if (!links.resolvedType) { - if (checkMode) { + if (checkMode && checkMode !== CheckMode.Normal) { return checkExpression(node, checkMode); } // When computing a type that we're going to cache, we need to ignore any ongoing control flow @@ -23341,22 +23371,127 @@ namespace ts { } function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration | QualifiedName, type: Type, checkMode?: CheckMode) { - if (checkMode === CheckMode.Inferential) { + if (checkMode && checkMode & (CheckMode.Inferential | CheckMode.SkipGenericFunctions)) { const signature = getSingleCallSignature(type); if (signature && signature.typeParameters) { + if (checkMode & CheckMode.SkipGenericFunctions) { + skippedGenericFunction(node, checkMode); + return anyFunctionType; + } const contextualType = getApparentTypeOfContextualType(node); if (contextualType) { const contextualSignature = getSingleCallSignature(getNonNullableType(contextualType)); if (contextualSignature && !contextualSignature.typeParameters) { - return getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, getContextualMapper(node))); + const context = getContextualMapper(node); + // We have an expression that is an argument of a generic function for which we are performing + // type argument inference. The expression is of a function type with a single generic call + // signature and a contextual function type with a single non-generic call signature. Now check + // if the outer function returns a function type with a single non-generic call signature and + // if some of the outer function type parameters have no inferences so far. If so, we can + // potentially add inferred type parameters to the outer function return type. + const returnSignature = context.signature && getSingleCallSignature(getReturnTypeOfSignature(context.signature)); + if (returnSignature && !returnSignature.typeParameters && !every(context.inferences, hasInferenceCandidates)) { + // Instantiate the expression type with its own type parameters as type arguments. This + // ensures that the type parameters are not erased to type any during type inference such + // that they can be inferred as actual types. + const uniqueTypeParameters = getUniqueTypeParameters(context, signature.typeParameters); + const strippedType = getOrCreateTypeFromSignature(getSignatureInstantiationWithoutFillingInTypeArguments(signature, uniqueTypeParameters)); + // Infer from the stripped expression type to the contextual type starting with an empty + // set of inference candidates. + const inferences = map(context.typeParameters, createInferenceInfo); + inferTypes(inferences, strippedType, contextualType); + // If we produced some inference candidates and if the type parameters for which we produced + // candidates do not already have existing inferences, we adopt the new inference candidates and + // add the type parameters of the expression type to the set of inferred type parameters for + // the outer function return type. + if (some(inferences, hasInferenceCandidates) && !hasOverlappingInferences(context.inferences, inferences)) { + mergeInferences(context.inferences, inferences); + context.inferredTypeParameters = concatenate(context.inferredTypeParameters, uniqueTypeParameters); + return strippedType; + } + } + return getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, context)); } } } } - return type; } + function skippedGenericFunction(node: Node, checkMode: CheckMode) { + if (checkMode & CheckMode.Inferential) { + // We have skipped a generic function during inferential typing. Obtain the inference context and + // indicate this has occurred such that we know a second pass of inference is be needed. + const context = getContextualMapper(node); + context.flags |= InferenceFlags.SkippedGenericFunction; + } + } + + function hasInferenceCandidates(info: InferenceInfo) { + return !!(info.candidates || info.contraCandidates); + } + + function hasOverlappingInferences(a: InferenceInfo[], b: InferenceInfo[]) { + for (let i = 0; i < a.length; i++) { + if (hasInferenceCandidates(a[i]) && hasInferenceCandidates(b[i])) { + return true; + } + } + return false; + } + + function mergeInferences(target: InferenceInfo[], source: InferenceInfo[]) { + for (let i = 0; i < target.length; i++) { + if (!hasInferenceCandidates(target[i]) && hasInferenceCandidates(source[i])) { + target[i] = source[i]; + } + } + } + + function getUniqueTypeParameters(context: InferenceContext, typeParameters: ReadonlyArray): ReadonlyArray { + const result: TypeParameter[] = []; + let oldTypeParameters: TypeParameter[] | undefined; + let newTypeParameters: TypeParameter[] | undefined; + for (const tp of typeParameters) { + const name = tp.symbol.escapedName; + if (hasTypeParameterByName(context.inferredTypeParameters, name) || hasTypeParameterByName(result, name)) { + const newName = getUniqueTypeParameterName(concatenate(context.inferredTypeParameters, result), name); + const symbol = createSymbol(SymbolFlags.TypeParameter, newName); + const newTypeParameter = createTypeParameter(symbol); + newTypeParameter.target = tp; + oldTypeParameters = append(oldTypeParameters, tp); + newTypeParameters = append(newTypeParameters, newTypeParameter); + result.push(newTypeParameter); + } + else { + result.push(tp); + } + } + if (newTypeParameters) { + const mapper = createTypeMapper(oldTypeParameters!, newTypeParameters); + for (const tp of newTypeParameters) { + tp.mapper = mapper; + } + } + return result; + } + + function hasTypeParameterByName(typeParameters: ReadonlyArray | undefined, name: __String) { + return some(typeParameters, tp => tp.symbol.escapedName === name); + } + + function getUniqueTypeParameterName(typeParameters: ReadonlyArray, baseName: __String) { + let len = (baseName).length; + while (len > 1 && (baseName).charCodeAt(len - 1) >= CharacterCodes._0 && (baseName).charCodeAt(len - 1) <= CharacterCodes._9) len--; + const s = (baseName).slice(0, len); + for (let index = 1; true; index++) { + const augmentedName = <__String>(s + index); + if (!hasTypeParameterByName(typeParameters, augmentedName)) { + return augmentedName; + } + } + } + /** * Returns the type of an expression. Unlike checkExpression, this function is simply concerned * with computing the type and may not fully check all contained sub-expressions for errors. @@ -23496,7 +23631,7 @@ namespace ts { } /* falls through */ case SyntaxKind.NewExpression: - return checkCallExpression(node); + return checkCallExpression(node, checkMode); case SyntaxKind.TaggedTemplateExpression: return checkTaggedTemplateExpression(node); case SyntaxKind.ParenthesizedExpression: diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 4bd4801ce8f..0bf648ffb11 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -917,7 +917,7 @@ namespace ts { /** * Deduplicates an unsorted array. - * @param equalityComparer An optional `EqualityComparer` used to determine if two values are duplicates. + * @param equalityComparer An `EqualityComparer` used to determine if two values are duplicates. * @param comparer An optional `Comparer` used to sort entries before comparison, though the * result will remain in the original order in `array`. */ @@ -1173,6 +1173,21 @@ namespace ts { }}; } + export function arrayReverseIterator(array: ReadonlyArray): Iterator { + let i = array.length; + return { + next: () => { + if (i === 0) { + return { value: undefined as never, done: true }; + } + else { + i--; + return { value: array[i], done: false }; + } + } + }; + } + /** * Stable sort of an array. Elements equal to each other maintain their relative position in the array. */ diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 66aba1befad..71dcc43482d 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2927,6 +2927,10 @@ "category": "Error", "code": 4102 }, + "Type parameter '{0}' of exported mapped object type is using private name '{1}'.": { + "category": "Error", + "code": 4103 + }, "The current host does not support the '{0}' option.": { "category": "Error", @@ -4910,5 +4914,9 @@ "Enable the 'experimentalDecorators' option in your configuration file": { "category": "Message", "code": 95074 + }, + "Convert to named parameters": { + "category": "Message", + "code": 95075 } } diff --git a/src/compiler/resolutionCache.ts b/src/compiler/resolutionCache.ts index 237c1637d31..b82a5a78d71 100644 --- a/src/compiler/resolutionCache.ts +++ b/src/compiler/resolutionCache.ts @@ -71,8 +71,8 @@ namespace ts { nonRecursive?: boolean; } - export function isPathInNodeModulesStartingWithDot(path: Path) { - return stringContains(path, "/node_modules/."); + export function isPathIgnored(path: Path) { + return some(ignoredPaths, searchPath => stringContains(path, searchPath)); } export const maxNumberOfFilesToIterateForInvalidation = 256; @@ -696,7 +696,7 @@ namespace ts { } else { // If something to do with folder/file starting with "." in node_modules folder, skip it - if (isPathInNodeModulesStartingWithDot(fileOrDirectoryPath)) return false; + if (isPathIgnored(fileOrDirectoryPath)) return false; // Some file or directory in the watching directory is created // Return early if it does not have any of the watching extension or not the custom failed lookup path diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 67556ca5fcc..f5ae4928de6 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -326,6 +326,9 @@ namespace ts { : FileWatcherEventKind.Changed; } + /*@internal*/ + export const ignoredPaths = ["/node_modules/.", "/.git"]; + /*@internal*/ export interface RecursiveDirectoryWatcherHost { watchDirectory: HostWatchDirectory; @@ -371,6 +374,8 @@ namespace ts { else { directoryWatcher = { watcher: host.watchDirectory(dirName, fileName => { + if (isIgnoredPath(fileName)) return; + // Call the actual callback callbackCache.forEach((callbacks, rootDirName) => { if (rootDirName === dirPath || (startsWith(dirPath, rootDirName) && dirPath[rootDirName.length] === directorySeparator)) { @@ -426,7 +431,7 @@ namespace ts { const childFullName = getNormalizedAbsolutePath(child, parentDir); // Filter our the symbolic link directories since those arent included in recursive watch // which is same behaviour when recursive: true is passed to fs.watch - return filePathComparer(childFullName, normalizePath(host.realpath(childFullName))) === Comparison.EqualTo ? childFullName : undefined; + return !isIgnoredPath(childFullName) && filePathComparer(childFullName, normalizePath(host.realpath(childFullName))) === Comparison.EqualTo ? childFullName : undefined; }) : emptyArray, existingChildWatches, (child, childWatcher) => filePathComparer(child, childWatcher.dirName), @@ -452,6 +457,16 @@ namespace ts { (newChildWatches || (newChildWatches = [])).push(childWatcher); } } + + function isIgnoredPath(path: string) { + return some(ignoredPaths, searchPath => isInPath(path, searchPath)); + } + + function isInPath(path: string, searchPath: string) { + if (stringContains(path, searchPath)) return true; + if (host.useCaseSensitiveFileNames) return false; + return stringContains(toCanonicalFilePath(path), searchPath); + } } /*@internal*/ diff --git a/src/compiler/transformers/declarations/diagnostics.ts b/src/compiler/transformers/declarations/diagnostics.ts index 9a9aed99e47..33465799c29 100644 --- a/src/compiler/transformers/declarations/diagnostics.ts +++ b/src/compiler/transformers/declarations/diagnostics.ts @@ -391,6 +391,10 @@ namespace ts { diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1; break; + case SyntaxKind.MappedType: + diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_mapped_object_type_is_using_private_name_1; + break; + case SyntaxKind.ConstructorType: case SyntaxKind.ConstructSignature: diagnosticMessage = Diagnostics.Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c6e866fccd4..ca014db5119 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4423,6 +4423,7 @@ namespace ts { NoDefault = 1 << 0, // Infer unknownType for no inferences (otherwise anyType or emptyObjectType) AnyDefault = 1 << 1, // Infer anyType for no inferences (otherwise emptyObjectType) NoFixing = 1 << 2, // Disable type parameter fixing + SkippedGenericFunction = 1 << 3, } /** @@ -4452,6 +4453,7 @@ namespace ts { flags: InferenceFlags; // Inference flags compareTypes: TypeComparer; // Type comparer function returnMapper?: TypeMapper; // Type mapper for inferences from return types (if any) + inferredTypeParameters?: ReadonlyArray; } /* @internal */ diff --git a/src/compiler/watch.ts b/src/compiler/watch.ts index 2551f164cec..41ef7876d76 100644 --- a/src/compiler/watch.ts +++ b/src/compiler/watch.ts @@ -987,7 +987,7 @@ namespace ts { } nextSourceFileVersion(fileOrDirectoryPath); - if (isPathInNodeModulesStartingWithDot(fileOrDirectoryPath)) return; + if (isPathIgnored(fileOrDirectoryPath)) return; // If the the added or created file or directory is not supported file name, ignore the file // But when watched directory is added/removed, we need to reload the file list diff --git a/src/harness/harness.ts b/src/harness/harness.ts index a78a04c3ecb..f03103d0239 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -47,23 +47,6 @@ interface XMLHttpRequest { /* tslint:enable:no-var-keyword prefer-const */ namespace Utils { - // Setup some globals based on the current environment - export const enum ExecutionEnvironment { - Node, - Browser, - } - - export function getExecutionEnvironment() { - if (typeof window !== "undefined") { - return ExecutionEnvironment.Browser; - } - else { - return ExecutionEnvironment.Node; - } - } - - export let currentExecutionEnvironment = getExecutionEnvironment(); - export function encodeString(s: string): string { return ts.sys.bufferFrom!(s).toString("utf8"); } @@ -74,23 +57,12 @@ namespace Utils { } export function evalFile(fileContents: string, fileName: string, nodeContext?: any) { - const environment = getExecutionEnvironment(); - switch (environment) { - case ExecutionEnvironment.Browser: - // tslint:disable-next-line:no-eval - eval(fileContents); - break; - case ExecutionEnvironment.Node: - const vm = require("vm"); - if (nodeContext) { - vm.runInNewContext(fileContents, nodeContext, fileName); - } - else { - vm.runInThisContext(fileContents, fileName); - } - break; - default: - throw new Error("Unknown context"); + const vm = require("vm"); + if (nodeContext) { + vm.runInNewContext(fileContents, nodeContext, fileName); + } + else { + vm.runInThisContext(fileContents, fileName); } } @@ -624,344 +596,11 @@ namespace Harness { }; } - interface URL { - hash: string; - host: string; - hostname: string; - href: string; - password: string; - pathname: string; - port: string; - protocol: string; - search: string; - username: string; - toString(): string; - } - - declare var URL: { - prototype: URL; - new(url: string, base?: string | URL): URL; - }; - - function createBrowserIO(): IO { - const serverRoot = new URL("http://localhost:8888/"); - - class HttpHeaders extends collections.SortedMap { - constructor(template?: Record) { - super(ts.compareStringsCaseInsensitive); - if (template) { - for (const key in template) { - if (ts.hasProperty(template, key)) { - this.set(key, template[key]); - } - } - } - } - - public static combine(left: HttpHeaders | undefined, right: HttpHeaders | undefined): HttpHeaders | undefined { - if (!left && !right) return undefined; - const headers = new HttpHeaders(); - if (left) left.forEach((value, key) => { headers.set(key, value); }); - if (right) right.forEach((value, key) => { headers.set(key, value); }); - return headers; - } - - public has(key: string) { - return super.has(key.toLowerCase()); - } - - public get(key: string) { - return super.get(key.toLowerCase()); - } - - public set(key: string, value: string | string[]) { - return super.set(key.toLowerCase(), value); - } - - public delete(key: string) { - return super.delete(key.toLowerCase()); - } - - public writeRequestHeaders(xhr: XMLHttpRequest) { - this.forEach((values, key) => { - if (key === "access-control-allow-origin" || key === "content-length") return; - const value = Array.isArray(values) ? values.join(",") : values; - if (key === "content-type") { - xhr.overrideMimeType(value); - return; - } - xhr.setRequestHeader(key, value); - }); - } - - public static readResponseHeaders(xhr: XMLHttpRequest): HttpHeaders { - const allHeaders = xhr.getAllResponseHeaders(); - const headers = new HttpHeaders(); - for (const header of allHeaders.split(/\r\n/g)) { - const colonIndex = header.indexOf(":"); - if (colonIndex >= 0) { - const key = header.slice(0, colonIndex).trim(); - const value = header.slice(colonIndex + 1).trim(); - const values = value.split(","); - headers.set(key, values.length > 1 ? values : value); - } - } - return headers; - } - } - - class HttpContent { - public headers: HttpHeaders; - public content: string; - - constructor(headers: HttpHeaders | Record, content: string) { - this.headers = headers instanceof HttpHeaders ? headers : new HttpHeaders(headers); - this.content = content; - } - - public static fromMediaType(mediaType: string, content: string) { - return new HttpContent({ "Content-Type": mediaType }, content); - } - - public static text(content: string) { - return HttpContent.fromMediaType("text/plain", content); - } - - public static json(content: object) { - return HttpContent.fromMediaType("application/json", JSON.stringify(content)); - } - - public static readResponseContent(xhr: XMLHttpRequest) { - if (typeof xhr.responseText === "string") { - return new HttpContent({ - "Content-Type": xhr.getResponseHeader("Content-Type") || undefined!, // TODO: GH#18217 - "Content-Length": xhr.getResponseHeader("Content-Length") || undefined!, // TODO: GH#18217 - }, xhr.responseText); - } - return undefined; - } - - public writeRequestHeaders(xhr: XMLHttpRequest) { - this.headers.writeRequestHeaders(xhr); - } - } - - class HttpRequestMessage { - public method: string; - public url: URL; - public headers: HttpHeaders; - public content?: HttpContent; - - constructor(method: string, url: string | URL, headers?: HttpHeaders | Record, content?: HttpContent) { - this.method = method; - this.url = typeof url === "string" ? new URL(url) : url; - this.headers = headers instanceof HttpHeaders ? headers : new HttpHeaders(headers); - this.content = content; - } - - public static options(url: string | URL) { - return new HttpRequestMessage("OPTIONS", url); - } - - public static head(url: string | URL) { - return new HttpRequestMessage("HEAD", url); - } - - public static get(url: string | URL) { - return new HttpRequestMessage("GET", url); - } - - public static delete(url: string | URL) { - return new HttpRequestMessage("DELETE", url); - } - - public static put(url: string | URL, content: HttpContent) { - return new HttpRequestMessage("PUT", url, /*headers*/ undefined, content); - } - - public static post(url: string | URL, content: HttpContent) { - return new HttpRequestMessage("POST", url, /*headers*/ undefined, content); - } - - public writeRequestHeaders(xhr: XMLHttpRequest) { - this.headers.writeRequestHeaders(xhr); - if (this.content) { - this.content.writeRequestHeaders(xhr); - } - } - } - - class HttpResponseMessage { - public statusCode: number; - public statusMessage: string; - public headers: HttpHeaders; - public content?: HttpContent; - - constructor(statusCode: number, statusMessage: string, headers?: HttpHeaders | Record, content?: HttpContent) { - this.statusCode = statusCode; - this.statusMessage = statusMessage; - this.headers = headers instanceof HttpHeaders ? headers : new HttpHeaders(headers); - this.content = content; - } - - public static notFound(): HttpResponseMessage { - return new HttpResponseMessage(404, "Not Found"); - } - - public static hasSuccessStatusCode(response: HttpResponseMessage) { - return response.statusCode === 304 || (response.statusCode >= 200 && response.statusCode < 300); - } - - public static readResponseMessage(xhr: XMLHttpRequest) { - return new HttpResponseMessage( - xhr.status, - xhr.statusText, - HttpHeaders.readResponseHeaders(xhr), - HttpContent.readResponseContent(xhr)); - } - } - - function send(request: HttpRequestMessage): HttpResponseMessage { - const xhr = new XMLHttpRequest(); - try { - xhr.open(request.method, request.url.toString(), /*async*/ false); - request.writeRequestHeaders(xhr); - xhr.setRequestHeader("Access-Control-Allow-Origin", "*"); - xhr.send(request.content && request.content.content); - while (xhr.readyState !== 4); // block until ready - return HttpResponseMessage.readResponseMessage(xhr); - } - catch (e) { - return HttpResponseMessage.notFound(); - } - } - - let caseSensitivity: "CI" | "CS" | undefined; - - function useCaseSensitiveFileNames() { - if (!caseSensitivity) { - const response = send(HttpRequestMessage.options(new URL("*", serverRoot))); - const xCaseSensitivity = response.headers.get("X-Case-Sensitivity"); - caseSensitivity = xCaseSensitivity === "CS" ? "CS" : "CI"; - } - return caseSensitivity === "CS"; - } - - function resolvePath(path: string) { - const response = send(HttpRequestMessage.post(new URL("/api/resolve", serverRoot), HttpContent.text(path))); - return HttpResponseMessage.hasSuccessStatusCode(response) && response.content ? response.content.content : undefined; - } - - function getFileSize(path: string): number { - const response = send(HttpRequestMessage.head(new URL(path, serverRoot))); - return HttpResponseMessage.hasSuccessStatusCode(response) ? +response.headers.get("Content-Length")!.toString() : 0; - } - - function readFile(path: string): string | undefined { - const response = send(HttpRequestMessage.get(new URL(path, serverRoot))); - return HttpResponseMessage.hasSuccessStatusCode(response) && response.content ? response.content.content : undefined; - } - - function writeFile(path: string, contents: string) { - send(HttpRequestMessage.put(new URL(path, serverRoot), HttpContent.text(contents))); - } - - function fileExists(path: string): boolean { - const response = send(HttpRequestMessage.head(new URL(path, serverRoot))); - return HttpResponseMessage.hasSuccessStatusCode(response); - } - - function directoryExists(path: string): boolean { - const response = send(HttpRequestMessage.post(new URL("/api/directoryExists", serverRoot), HttpContent.text(path))); - return hasJsonContent(response) && JSON.parse(response.content.content) as boolean; - } - - function deleteFile(path: string) { - send(HttpRequestMessage.delete(new URL(path, serverRoot))); - } - - function directoryName(path: string) { - const url = new URL(path, serverRoot); - return ts.getDirectoryPath(ts.normalizeSlashes(url.pathname || "/")); - } - - function enumerateTestFiles(runner: RunnerBase): (string | FileBasedTest)[] { - const response = send(HttpRequestMessage.post(new URL("/api/enumerateTestFiles", serverRoot), HttpContent.text(runner.kind()))); - return hasJsonContent(response) ? JSON.parse(response.content.content) : []; - } - - function listFiles(dirname: string, spec?: RegExp, options?: { recursive?: boolean }): string[] { - if (spec || (options && !options.recursive)) { - let results = IO.listFiles(dirname); - if (spec) { - results = results.filter(file => spec.test(file)); - } - if (options && !options.recursive) { - results = results.filter(file => ts.getDirectoryPath(ts.normalizeSlashes(file)) === dirname); - } - return results; - } - - const response = send(HttpRequestMessage.post(new URL("/api/listFiles", serverRoot), HttpContent.text(dirname))); - return hasJsonContent(response) ? JSON.parse(response.content.content) : []; - } - - function readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[], depth?: number) { - return ts.matchFiles(path, extension, exclude, include, useCaseSensitiveFileNames(), "", depth, getAccessibleFileSystemEntries); - } - - function getAccessibleFileSystemEntries(dirname: string): ts.FileSystemEntries { - const response = send(HttpRequestMessage.post(new URL("/api/getAccessibleFileSystemEntries", serverRoot), HttpContent.text(dirname))); - return hasJsonContent(response) ? JSON.parse(response.content.content) : { files: [], directories: [] }; - } - - function hasJsonContent(response: HttpResponseMessage): response is HttpResponseMessage & { content: HttpContent } { - return HttpResponseMessage.hasSuccessStatusCode(response) - && !!response.content - && /^application\/json(;.*)$/.test("" + response.content.headers.get("Content-Type")); - } - - return { - newLine: () => harnessNewLine, - getCurrentDirectory: () => "", - useCaseSensitiveFileNames, - resolvePath, - getFileSize, - readFile, - writeFile, - directoryName: Utils.memoize(directoryName, path => path), - getDirectories: () => [], - createDirectory: () => {}, // tslint:disable-line no-empty - fileExists, - directoryExists, - deleteFile, - listFiles: Utils.memoize(listFiles, (path, spec, options) => `${path}|${spec}|${options ? options.recursive === true : true}`), - enumerateTestFiles: Utils.memoize(enumerateTestFiles, runner => runner.kind()), - log: s => console.log(s), - args: () => [], - getExecutingFilePath: () => "", - exit: () => {}, // tslint:disable-line no-empty - readDirectory, - getAccessibleFileSystemEntries, - getWorkspaceRoot: () => "/" - }; - } - export function mockHash(s: string): string { return `hash-${s}`; } - const environment = Utils.getExecutionEnvironment(); - switch (environment) { - case Utils.ExecutionEnvironment.Node: - IO = createNodeIO(); - break; - case Utils.ExecutionEnvironment.Browser: - IO = createBrowserIO(); - break; - default: - throw new Error(`Unknown value '${environment}' for ExecutionEnvironment.`); - } + IO = createNodeIO(); } if (Harness.IO.tryEnableSourceMapsForHost && /^development$/i.test(Harness.IO.getEnvironmentVariable!("NODE_ENV"))) { @@ -970,10 +609,8 @@ if (Harness.IO.tryEnableSourceMapsForHost && /^development$/i.test(Harness.IO.ge namespace Harness { export const libFolder = "built/local/"; - const tcServicesFileName = ts.combinePaths(libFolder, Utils.getExecutionEnvironment() === Utils.ExecutionEnvironment.Browser ? "typescriptServicesInBrowserTest.js" : "typescriptServices.js"); - export const tcServicesFile = IO.readFile(tcServicesFileName) + (Utils.getExecutionEnvironment() !== Utils.ExecutionEnvironment.Browser - ? IO.newLine() + `//# sourceURL=${IO.resolvePath(tcServicesFileName)}` - : ""); + const tcServicesFileName = ts.combinePaths(libFolder, "typescriptServices.js"); + export const tcServicesFile = IO.readFile(tcServicesFileName) + IO.newLine() + `//# sourceURL=${IO.resolvePath(tcServicesFileName)}`; export type SourceMapEmitterCallback = ( emittedFile: string, diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 43814ebbe9d..6c1ad386a05 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -408,6 +408,21 @@ namespace ts.server { } } + /*@internal*/ + export interface OpenFileArguments { + fileName: string; + content?: string; + scriptKind?: protocol.ScriptKindName | ScriptKind; + hasMixedContent?: boolean; + projectRootPath?: string; + } + + /*@internal*/ + export interface ChangeFileArguments { + fileName: string; + changes: Iterator; + } + export class ProjectService { /*@internal*/ @@ -988,7 +1003,7 @@ namespace ts.server { fileOrDirectory => { const fileOrDirectoryPath = this.toPath(fileOrDirectory); project.getCachedDirectoryStructureHost().addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath); - if (isPathInNodeModulesStartingWithDot(fileOrDirectoryPath)) return; + if (isPathIgnored(fileOrDirectoryPath)) return; const configFilename = project.getConfigFilePath(); // If the the added or created file or directory is not supported file name, ignore the file @@ -1129,11 +1144,22 @@ namespace ts.server { return project; } + private assignOrphanScriptInfosToInferredProject() { + // collect orphaned files and assign them to inferred project just like we treat open of a file + this.openFiles.forEach((projectRootPath, path) => { + const info = this.getScriptInfoForPath(path as Path)!; + // collect all orphaned script infos from open files + if (info.isOrphan()) { + this.assignOrphanScriptInfoToInferredProject(info, projectRootPath); + } + }); + } + /** * Remove this file from the set of open, non-configured files. * @param info The file that has been closed or newly configured */ - private closeOpenFile(info: ScriptInfo): void { + private closeOpenFile(info: ScriptInfo, skipAssignOrphanScriptInfosToInferredProject?: true) { // Closing file should trigger re-reading the file content from disk. This is // because the user may chose to discard the buffer content before saving // to the disk, and the server's version of the file can be out of sync. @@ -1177,15 +1203,8 @@ namespace ts.server { this.openFiles.delete(info.path); - if (ensureProjectsForOpenFiles) { - // collect orphaned files and assign them to inferred project just like we treat open of a file - this.openFiles.forEach((projectRootPath, path) => { - const info = this.getScriptInfoForPath(path as Path)!; - // collect all orphaned script infos from open files - if (info.isOrphan()) { - this.assignOrphanScriptInfoToInferredProject(info, projectRootPath); - } - }); + if (!skipAssignOrphanScriptInfosToInferredProject && ensureProjectsForOpenFiles) { + this.assignOrphanScriptInfosToInferredProject(); } // Cleanup script infos that arent part of any project (eg. those could be closed script infos not referenced by any project) @@ -1200,6 +1219,8 @@ namespace ts.server { else { this.handleDeletedFile(info); } + + return ensureProjectsForOpenFiles; } private deleteScriptInfo(info: ScriptInfo) { @@ -2051,7 +2072,7 @@ namespace ts.server { watchDir, (fileOrDirectory) => { const fileOrDirectoryPath = this.toPath(fileOrDirectory); - if (isPathInNodeModulesStartingWithDot(fileOrDirectoryPath)) return; + if (isPathIgnored(fileOrDirectoryPath)) return; // Has extension Debug.assert(result.refCount > 0); @@ -2571,20 +2592,22 @@ namespace ts.server { }); } - openClientFileWithNormalizedPath(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, projectRootPath?: NormalizedPath): OpenConfiguredProjectResult { + private getOrCreateOpenScriptInfo(fileName: NormalizedPath, fileContent: string | undefined, scriptKind: ScriptKind | undefined, hasMixedContent: boolean | undefined, projectRootPath: NormalizedPath | undefined) { + const info = this.getOrCreateScriptInfoOpenedByClientForNormalizedPath(fileName, projectRootPath ? this.getNormalizedAbsolutePath(projectRootPath) : this.currentDirectory, fileContent, scriptKind, hasMixedContent)!; // TODO: GH#18217 + this.openFiles.set(info.path, projectRootPath); + return info; + } + + private assignProjectToOpenedScriptInfo(info: ScriptInfo): OpenConfiguredProjectResult { let configFileName: NormalizedPath | undefined; let configFileErrors: ReadonlyArray | undefined; - - const info = this.getOrCreateScriptInfoOpenedByClientForNormalizedPath(fileName, projectRootPath ? this.getNormalizedAbsolutePath(projectRootPath) : this.currentDirectory, fileContent, scriptKind, hasMixedContent)!; // TODO: GH#18217 - - this.openFiles.set(info.path, projectRootPath); let project: ConfiguredProject | ExternalProject | undefined = this.findExternalProjectContainingOpenScriptInfo(info); if (!project && !this.syntaxOnly) { // Checking syntaxOnly is an optimization configFileName = this.getConfigFileNameForFile(info); if (configFileName) { project = this.findConfiguredProjectByProjectName(configFileName); if (!project) { - project = this.createLoadAndUpdateConfiguredProject(configFileName, `Creating possible configured project for ${fileName} to open`); + project = this.createLoadAndUpdateConfiguredProject(configFileName, `Creating possible configured project for ${info.fileName} to open`); // Send the event only if the project got created as part of this open request and info is part of the project if (info.isOrphan()) { // Since the file isnt part of configured project, do not send config file info @@ -2592,7 +2615,7 @@ namespace ts.server { } else { configFileErrors = project.getAllProjectErrors(); - this.sendConfigFileDiagEvent(project, fileName); + this.sendConfigFileDiagEvent(project, info.fileName); } } else { @@ -2614,10 +2637,14 @@ namespace ts.server { // At this point if file is part of any any configured or external project, then it would be present in the containing projects // So if it still doesnt have any containing projects, it needs to be part of inferred project if (info.isOrphan()) { - this.assignOrphanScriptInfoToInferredProject(info, projectRootPath); + Debug.assert(this.openFiles.has(info.path)); + this.assignOrphanScriptInfoToInferredProject(info, this.openFiles.get(info.path)); } Debug.assert(!info.isOrphan()); + return { configFileName, configFileErrors }; + } + private cleanupAfterOpeningFile() { // This was postponed from closeOpenFile to after opening next file, // so that we can reuse the project if we need to right away this.removeOrphanConfiguredProjects(); @@ -2637,9 +2664,14 @@ namespace ts.server { this.removeOrphanScriptInfos(); this.printProjects(); + } + openClientFileWithNormalizedPath(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, projectRootPath?: NormalizedPath): OpenConfiguredProjectResult { + const info = this.getOrCreateOpenScriptInfo(fileName, fileContent, scriptKind, hasMixedContent, projectRootPath); + const result = this.assignProjectToOpenedScriptInfo(info); + this.cleanupAfterOpeningFile(); this.telemetryOnOpenFile(info); - return { configFileName, configFileErrors }; + return result; } private removeOrphanConfiguredProjects() { @@ -2746,12 +2778,16 @@ namespace ts.server { * Close file whose contents is managed by the client * @param filename is absolute pathname */ - closeClientFile(uncheckedFileName: string) { + closeClientFile(uncheckedFileName: string): void; + /*@internal*/ + closeClientFile(uncheckedFileName: string, skipAssignOrphanScriptInfosToInferredProject: true): boolean; + closeClientFile(uncheckedFileName: string, skipAssignOrphanScriptInfosToInferredProject?: true) { const info = this.getScriptInfoForNormalizedPath(toNormalizedPath(uncheckedFileName)); - if (info) { - this.closeOpenFile(info); + const result = info ? this.closeOpenFile(info, skipAssignOrphanScriptInfosToInferredProject) : false; + if (!skipAssignOrphanScriptInfosToInferredProject) { + this.printProjects(); } - this.printProjects(); + return result; } private collectChanges(lastKnownProjectVersions: protocol.ProjectVersionInfo[], currentProjects: Project[], result: ProjectFilesWithTSDiagnostics[]): void { @@ -2771,36 +2807,68 @@ namespace ts.server { } /* @internal */ - applyChangesInOpenFiles(openFiles: protocol.ExternalFile[] | undefined, changedFiles: protocol.ChangedOpenFile[] | undefined, closedFiles: string[] | undefined): void { + applyChangesInOpenFiles(openFiles: Iterator | undefined, changedFiles?: Iterator, closedFiles?: string[]): void { + let openScriptInfos: ScriptInfo[] | undefined; + let assignOrphanScriptInfosToInferredProject = false; if (openFiles) { - for (const file of openFiles) { + while (true) { + const { value: file, done } = openFiles.next(); + if (done) break; const scriptInfo = this.getScriptInfo(file.fileName); Debug.assert(!scriptInfo || !scriptInfo.isScriptOpen(), "Script should not exist and not be open already"); - const normalizedPath = scriptInfo ? scriptInfo.fileName : toNormalizedPath(file.fileName); - this.openClientFileWithNormalizedPath(normalizedPath, file.content, tryConvertScriptKindName(file.scriptKind!), file.hasMixedContent); // TODO: GH#18217 + // Create script infos so we have the new content for all the open files before we do any updates to projects + const info = this.getOrCreateOpenScriptInfo( + scriptInfo ? scriptInfo.fileName : toNormalizedPath(file.fileName), + file.content, + tryConvertScriptKindName(file.scriptKind!), + file.hasMixedContent, + file.projectRootPath ? toNormalizedPath(file.projectRootPath) : undefined + ); + (openScriptInfos || (openScriptInfos = [])).push(info); } } if (changedFiles) { - for (const file of changedFiles) { + while (true) { + const { value: file, done } = changedFiles.next(); + if (done) break; const scriptInfo = this.getScriptInfo(file.fileName)!; Debug.assert(!!scriptInfo); + // Make edits to script infos and marks containing project as dirty this.applyChangesToFile(scriptInfo, file.changes); } } if (closedFiles) { for (const file of closedFiles) { - this.closeClientFile(file); + // Close files, but dont assign projects to orphan open script infos, that part comes later + assignOrphanScriptInfosToInferredProject = this.closeClientFile(file, /*skipAssignOrphanScriptInfosToInferredProject*/ true) || assignOrphanScriptInfosToInferredProject; } } + + // All the script infos now exist, so ok to go update projects for open files + if (openScriptInfos) { + openScriptInfos.forEach(info => this.assignProjectToOpenedScriptInfo(info)); + } + + // While closing files there could be open files that needed assigning new inferred projects, do it now + if (assignOrphanScriptInfosToInferredProject) { + this.assignOrphanScriptInfosToInferredProject(); + } + + // Cleanup projects + this.cleanupAfterOpeningFile(); + + // Telemetry + forEach(openScriptInfos, info => this.telemetryOnOpenFile(info)); + this.printProjects(); } /* @internal */ - applyChangesToFile(scriptInfo: ScriptInfo, changes: TextChange[]) { - // apply changes in reverse order - for (let i = changes.length - 1; i >= 0; i--) { - const change = changes[i]; + applyChangesToFile(scriptInfo: ScriptInfo, changes: Iterator) { + while (true) { + const { value: change, done } = changes.next(); + if (done) break; scriptInfo.editContent(change.span.start, change.span.start + change.span.length, change.newText); } } diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 1fd8d98b570..3b7690e2c60 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -92,6 +92,7 @@ namespace ts.server.protocol { SynchronizeProjectList = "synchronizeProjectList", /* @internal */ ApplyChangedToOpenFiles = "applyChangedToOpenFiles", + UpdateOpen = "updateOpen", /* @internal */ EncodedSemanticClassificationsFull = "encodedSemanticClassifications-full", /* @internal */ @@ -1543,6 +1544,32 @@ namespace ts.server.protocol { closedFiles?: string[]; } + /** + * Request to synchronize list of open files with the client + */ + export interface UpdateOpenRequest extends Request { + command: CommandTypes.UpdateOpen; + arguments: UpdateOpenRequestArgs; + } + + /** + * Arguments to UpdateOpenRequest + */ + export interface UpdateOpenRequestArgs { + /** + * List of newly open files + */ + openFiles?: OpenRequestArgs[]; + /** + * List of open files files that were changes + */ + changedFiles?: FileCodeEdits[]; + /** + * List of files that were closed + */ + closedFiles?: string[]; + } + /** * Request to set compiler options for inferred projects. * External projects are opened / closed explicitly. diff --git a/src/server/session.ts b/src/server/session.ts index b47dfe6b716..7cc3f595f82 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -1654,10 +1654,10 @@ namespace ts.server { const end = scriptInfo.lineOffsetToPosition(args.endLine, args.endOffset); if (start >= 0) { this.changeSeq++; - this.projectService.applyChangesToFile(scriptInfo, [{ + this.projectService.applyChangesToFile(scriptInfo, singleIterator({ span: { start, length: end - start }, newText: args.insertString! // TODO: GH#18217 - }]); + })); } } @@ -2096,9 +2096,39 @@ namespace ts.server { }); return this.requiredResponse(converted); }, + [CommandNames.UpdateOpen]: (request: protocol.UpdateOpenRequest) => { + this.changeSeq++; + this.projectService.applyChangesInOpenFiles( + request.arguments.openFiles && mapIterator(arrayIterator(request.arguments.openFiles), file => ({ + fileName: file.file, + content: file.fileContent, + scriptKind: file.scriptKindName, + projectRootPath: file.projectRootPath + })), + request.arguments.changedFiles && mapIterator(arrayIterator(request.arguments.changedFiles), file => ({ + fileName: file.fileName, + changes: mapDefinedIterator(arrayReverseIterator(file.textChanges), change => { + const scriptInfo = Debug.assertDefined(this.projectService.getScriptInfo(file.fileName)); + const start = scriptInfo.lineOffsetToPosition(change.start.line, change.start.offset); + const end = scriptInfo.lineOffsetToPosition(change.end.line, change.end.offset); + return start >= 0 ? { span: { start, length: end - start }, newText: change.newText } : undefined; + }) + })), + request.arguments.closedFiles + ); + return this.requiredResponse(/*response*/ true); + }, [CommandNames.ApplyChangedToOpenFiles]: (request: protocol.ApplyChangedToOpenFilesRequest) => { this.changeSeq++; - this.projectService.applyChangesInOpenFiles(request.arguments.openFiles, request.arguments.changedFiles!, request.arguments.closedFiles!); // TODO: GH#18217 + this.projectService.applyChangesInOpenFiles( + request.arguments.openFiles && arrayIterator(request.arguments.openFiles), + request.arguments.changedFiles && mapIterator(arrayIterator(request.arguments.changedFiles), file => ({ + fileName: file.fileName, + // apply changes in reverse order + changes: arrayReverseIterator(file.changes) + })), + request.arguments.closedFiles + ); // TODO: report errors return this.requiredResponse(/*response*/ true); }, diff --git a/src/services/codefixes/convertFunctionToEs6Class.ts b/src/services/codefixes/convertFunctionToEs6Class.ts index 78e10ce2044..b87a78106ad 100644 --- a/src/services/codefixes/convertFunctionToEs6Class.ts +++ b/src/services/codefixes/convertFunctionToEs6Class.ts @@ -35,7 +35,7 @@ namespace ts.codefix { precedingNode = ctorDeclaration.parent.parent; newClassDeclaration = createClassFromVariableDeclaration(ctorDeclaration as VariableDeclaration); if ((ctorDeclaration.parent).declarations.length === 1) { - copyComments(precedingNode, newClassDeclaration!, sourceFile); // TODO: GH#18217 + copyLeadingComments(precedingNode, newClassDeclaration!, sourceFile); // TODO: GH#18217 changes.delete(sourceFile, precedingNode); } else { @@ -48,7 +48,7 @@ namespace ts.codefix { return undefined; } - copyComments(ctorDeclaration, newClassDeclaration, sourceFile); + copyLeadingComments(ctorDeclaration, newClassDeclaration, sourceFile); // Because the preceding node could be touched, we need to insert nodes before delete nodes. changes.insertNodeAfter(sourceFile, precedingNode!, newClassDeclaration); @@ -112,7 +112,7 @@ namespace ts.codefix { const fullModifiers = concatenate(modifiers, getModifierKindFromSource(functionExpression, SyntaxKind.AsyncKeyword)); const method = createMethod(/*decorators*/ undefined, fullModifiers, /*asteriskToken*/ undefined, memberDeclaration.name, /*questionToken*/ undefined, /*typeParameters*/ undefined, functionExpression.parameters, /*type*/ undefined, functionExpression.body); - copyComments(assignmentBinaryExpression, method, sourceFile); + copyLeadingComments(assignmentBinaryExpression, method, sourceFile); return method; } @@ -132,7 +132,7 @@ namespace ts.codefix { const fullModifiers = concatenate(modifiers, getModifierKindFromSource(arrowFunction, SyntaxKind.AsyncKeyword)); const method = createMethod(/*decorators*/ undefined, fullModifiers, /*asteriskToken*/ undefined, memberDeclaration.name, /*questionToken*/ undefined, /*typeParameters*/ undefined, arrowFunction.parameters, /*type*/ undefined, bodyBlock); - copyComments(assignmentBinaryExpression, method, sourceFile); + copyLeadingComments(assignmentBinaryExpression, method, sourceFile); return method; } @@ -143,7 +143,7 @@ namespace ts.codefix { } const prop = createProperty(/*decorators*/ undefined, modifiers, memberDeclaration.name, /*questionToken*/ undefined, /*type*/ undefined, assignmentBinaryExpression.right); - copyComments(assignmentBinaryExpression.parent, prop, sourceFile); + copyLeadingComments(assignmentBinaryExpression.parent, prop, sourceFile); return prop; } } diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index f47f618f79d..ecf2841e249 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -304,30 +304,6 @@ namespace ts.codefix { } } - function getTypeNodeIfAccessible(type: Type, enclosingScope: Node, program: Program, host: LanguageServiceHost): TypeNode | undefined { - const checker = program.getTypeChecker(); - let typeIsAccessible = true; - const notAccessible = () => { typeIsAccessible = false; }; - const res = checker.typeToTypeNode(type, enclosingScope, /*flags*/ undefined, { - trackSymbol: (symbol, declaration, meaning) => { - // TODO: GH#18217 - typeIsAccessible = typeIsAccessible && checker.isSymbolAccessible(symbol, declaration, meaning!, /*shouldComputeAliasToMarkVisible*/ false).accessibility === SymbolAccessibility.Accessible; - }, - reportInaccessibleThisError: notAccessible, - reportPrivateInBaseOfClassExpression: notAccessible, - reportInaccessibleUniqueSymbolError: notAccessible, - moduleResolverHost: { - readFile: host.readFile, - fileExists: host.fileExists, - directoryExists: host.directoryExists, - getSourceFiles: program.getSourceFiles, - getCurrentDirectory: program.getCurrentDirectory, - getCommonSourceDirectory: program.getCommonSourceDirectory, - } - }); - return typeIsAccessible ? res : undefined; - } - function getReferences(token: PropertyName | Token, program: Program, cancellationToken: CancellationToken): ReadonlyArray { // Position shouldn't matter since token is not a SourceFile. return mapDefined(FindAllReferences.getReferenceEntriesForNode(-1, token, program, program.getSourceFiles(), cancellationToken), entry => diff --git a/src/services/organizeImports.ts b/src/services/organizeImports.ts index 157ba98e262..5bfa0c74ab1 100644 --- a/src/services/organizeImports.ts +++ b/src/services/organizeImports.ts @@ -68,8 +68,8 @@ namespace ts.OrganizeImports { else { // Note: Delete the surrounding trivia because it will have been retained in newImportDecls. changeTracker.replaceNodeWithNodes(sourceFile, oldImportDecls[0], newImportDecls, { - useNonAdjustedStartPosition: true, // Leave header comment in place - useNonAdjustedEndPosition: false, + leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, // Leave header comment in place + trailingTriviaOption: textChanges.TrailingTriviaOption.Include, suffix: getNewLineOrDefaultFromHost(host, formatContext.options), }); } diff --git a/src/services/refactors/addOrRemoveBracesToArrowFunction.ts b/src/services/refactors/addOrRemoveBracesToArrowFunction.ts index c5fccde13db..97d6f4d6667 100644 --- a/src/services/refactors/addOrRemoveBracesToArrowFunction.ts +++ b/src/services/refactors/addOrRemoveBracesToArrowFunction.ts @@ -48,13 +48,13 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction { const returnStatement = createReturn(expression); body = createBlock([returnStatement], /* multiLine */ true); suppressLeadingAndTrailingTrivia(body); - copyComments(expression!, returnStatement, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ true); + copyLeadingComments(expression!, returnStatement, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ true); } else if (actionName === removeBracesActionName && returnStatement) { const actualExpression = expression || createVoidZero(); body = needsParentheses(actualExpression) ? createParen(actualExpression) : actualExpression; suppressLeadingAndTrailingTrivia(body); - copyComments(returnStatement, body, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ false); + copyLeadingComments(returnStatement, body, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ false); } else { Debug.fail("invalid action"); diff --git a/src/services/refactors/convertToNamedParameters.ts b/src/services/refactors/convertToNamedParameters.ts new file mode 100644 index 00000000000..61e9ccf9811 --- /dev/null +++ b/src/services/refactors/convertToNamedParameters.ts @@ -0,0 +1,520 @@ +/* @internal */ +namespace ts.refactor.convertToNamedParameters { + const refactorName = "Convert to named parameters"; + const minimumParameterLength = 2; + registerRefactor(refactorName, { getEditsForAction, getAvailableActions }); + + + function getAvailableActions(context: RefactorContext): ReadonlyArray { + const { file, startPosition } = context; + const isJSFile = isSourceFileJS(file); + if (isJSFile) return emptyArray; // TODO: GH#30113 + const functionDeclaration = getFunctionDeclarationAtPosition(file, startPosition, context.program.getTypeChecker()); + if (!functionDeclaration) return emptyArray; + + const description = getLocaleSpecificMessage(Diagnostics.Convert_to_named_parameters); + return [{ + name: refactorName, + description, + actions: [{ + name: refactorName, + description + }] + }]; + } + + function getEditsForAction(context: RefactorContext, actionName: string): RefactorEditInfo | undefined { + Debug.assert(actionName === refactorName); + const { file, startPosition, program, cancellationToken, host } = context; + const functionDeclaration = getFunctionDeclarationAtPosition(file, startPosition, program.getTypeChecker()); + if (!functionDeclaration || !cancellationToken) return undefined; + + const groupedReferences = getGroupedReferences(functionDeclaration, program, cancellationToken); + if (groupedReferences.valid) { + const edits = textChanges.ChangeTracker.with(context, t => doChange(file, program, host, t, functionDeclaration, groupedReferences)); + return { renameFilename: undefined, renameLocation: undefined, edits }; + } + + return { edits: [] }; // TODO: GH#30113 + } + + function doChange( + sourceFile: SourceFile, + program: Program, + host: LanguageServiceHost, + changes: textChanges.ChangeTracker, + functionDeclaration: ValidFunctionDeclaration, + groupedReferences: GroupedReferences): void { + const newParamDeclaration = map(createNewParameters(functionDeclaration, program, host), param => getSynthesizedDeepClone(param)); + changes.replaceNodeRangeWithNodes( + sourceFile, + first(functionDeclaration.parameters), + last(functionDeclaration.parameters), + newParamDeclaration, + { joiner: ", ", + // indentation is set to 0 because otherwise the object parameter will be indented if there is a `this` parameter + indentation: 0, + leadingTriviaOption: textChanges.LeadingTriviaOption.IncludeAll, + trailingTriviaOption: textChanges.TrailingTriviaOption.Include + }); + + const functionCalls = sortAndDeduplicate(groupedReferences.functionCalls, /*comparer*/ (a, b) => compareValues(a.pos, b.pos)); + for (const call of functionCalls) { + if (call.arguments && call.arguments.length) { + const newArgument = getSynthesizedDeepClone(createNewArgument(functionDeclaration, call.arguments), /*includeTrivia*/ true); + changes.replaceNodeRange( + getSourceFileOfNode(call), + first(call.arguments), + last(call.arguments), + newArgument, + { leadingTriviaOption: textChanges.LeadingTriviaOption.IncludeAll, trailingTriviaOption: textChanges.TrailingTriviaOption.Include }); + } + } + } + + function getGroupedReferences(functionDeclaration: ValidFunctionDeclaration, program: Program, cancellationToken: CancellationToken): GroupedReferences { + const functionNames = getFunctionNames(functionDeclaration); + const classNames = isConstructorDeclaration(functionDeclaration) ? getClassNames(functionDeclaration) : []; + const names = deduplicate([...functionNames, ...classNames], equateValues); + const checker = program.getTypeChecker(); + + const references = flatMap(names, /*mapfn*/ name => FindAllReferences.getReferenceEntriesForNode(-1, name, program, program.getSourceFiles(), cancellationToken)); + const groupedReferences = groupReferences(references); + + if (!every(groupedReferences.declarations, decl => contains(names, decl))) { + groupedReferences.valid = false; + } + + return groupedReferences; + + function groupReferences(referenceEntries: ReadonlyArray): GroupedReferences { + const classReferences: ClassReferences = { accessExpressions: [], typeUsages: [] }; + const groupedReferences: GroupedReferences = { functionCalls: [], declarations: [], classReferences, valid: true }; + const functionSymbols = map(functionNames, checker.getSymbolAtLocation); + const classSymbols = map(classNames, checker.getSymbolAtLocation); + const isConstructor = isConstructorDeclaration(functionDeclaration); + + for (const entry of referenceEntries) { + if (entry.kind !== FindAllReferences.EntryKind.Node) { + groupedReferences.valid = false; + continue; + } + if (contains(functionSymbols, checker.getSymbolAtLocation(entry.node), symbolComparer)) { + const decl = entryToDeclaration(entry); + if (decl) { + groupedReferences.declarations.push(decl); + continue; + } + + const call = entryToFunctionCall(entry); + if (call) { + groupedReferences.functionCalls.push(call); + continue; + } + } + // if the refactored function is a constructor, we must also check if the references to its class are valid + if (isConstructor && contains(classSymbols, checker.getSymbolAtLocation(entry.node), symbolComparer)) { + const decl = entryToDeclaration(entry); + if (decl) { + groupedReferences.declarations.push(decl); + continue; + } + + const accessExpression = entryToAccessExpression(entry); + if (accessExpression) { + classReferences.accessExpressions.push(accessExpression); + continue; + } + + // Only class declarations are allowed to be used as a type (in a heritage clause), + // otherwise `findAllReferences` might not be able to track constructor calls. + if (isClassDeclaration(functionDeclaration.parent)) { + const type = entryToType(entry); + if (type) { + classReferences.typeUsages.push(type); + continue; + } + } + } + groupedReferences.valid = false; + } + + return groupedReferences; + } + } + + function symbolComparer(a: Symbol, b: Symbol): boolean { + return getSymbolTarget(a) === getSymbolTarget(b); + } + + function entryToDeclaration(entry: FindAllReferences.NodeEntry): Node | undefined { + if (isDeclaration(entry.node.parent)) { + return entry.node; + } + return undefined; + } + + function entryToFunctionCall(entry: FindAllReferences.NodeEntry): CallExpression | NewExpression | undefined { + if (entry.node.parent) { + const functionReference = entry.node; + const parent = functionReference.parent; + switch (parent.kind) { + // Function call (foo(...) or super(...)) + case SyntaxKind.CallExpression: + const callExpression = tryCast(parent, isCallExpression); + if (callExpression && callExpression.expression === functionReference) { + return callExpression; + } + break; + // Constructor call (new Foo(...)) + case SyntaxKind.NewExpression: + const newExpression = tryCast(parent, isNewExpression); + if (newExpression && newExpression.expression === functionReference) { + return newExpression; + } + break; + // Method call (x.foo(...)) + case SyntaxKind.PropertyAccessExpression: + const propertyAccessExpression = tryCast(parent, isPropertyAccessExpression); + if (propertyAccessExpression && propertyAccessExpression.parent && propertyAccessExpression.name === functionReference) { + const callExpression = tryCast(propertyAccessExpression.parent, isCallExpression); + if (callExpression && callExpression.expression === propertyAccessExpression) { + return callExpression; + } + } + break; + // Method call (x["foo"](...)) + case SyntaxKind.ElementAccessExpression: + const elementAccessExpression = tryCast(parent, isElementAccessExpression); + if (elementAccessExpression && elementAccessExpression.parent && elementAccessExpression.argumentExpression === functionReference) { + const callExpression = tryCast(elementAccessExpression.parent, isCallExpression); + if (callExpression && callExpression.expression === elementAccessExpression) { + return callExpression; + } + } + break; + } + } + return undefined; + } + + function entryToAccessExpression(entry: FindAllReferences.NodeEntry): ElementAccessExpression | PropertyAccessExpression | undefined { + if (entry.node.parent) { + const reference = entry.node; + const parent = reference.parent; + switch (parent.kind) { + // `C.foo` + case SyntaxKind.PropertyAccessExpression: + const propertyAccessExpression = tryCast(parent, isPropertyAccessExpression); + if (propertyAccessExpression && propertyAccessExpression.expression === reference) { + return propertyAccessExpression; + } + break; + // `C["foo"]` + case SyntaxKind.ElementAccessExpression: + const elementAccessExpression = tryCast(parent, isElementAccessExpression); + if (elementAccessExpression && elementAccessExpression.expression === reference) { + return elementAccessExpression; + } + break; + } + } + return undefined; + } + + function entryToType(entry: FindAllReferences.NodeEntry): Node | undefined { + const reference = entry.node; + if (getMeaningFromLocation(reference) === SemanticMeaning.Type || isExpressionWithTypeArgumentsInClassExtendsClause(reference.parent)) { + return reference; + } + return undefined; + } + + function getFunctionDeclarationAtPosition(file: SourceFile, startPosition: number, checker: TypeChecker): ValidFunctionDeclaration | undefined { + const node = getTouchingToken(file, startPosition); + const functionDeclaration = getContainingFunction(node); + if (functionDeclaration + && isValidFunctionDeclaration(functionDeclaration, checker) + && rangeContainsRange(functionDeclaration, node) + && !(functionDeclaration.body && rangeContainsRange(functionDeclaration.body, node))) return functionDeclaration; + + return undefined; + } + + function isValidFunctionDeclaration(functionDeclaration: SignatureDeclaration, checker: TypeChecker): functionDeclaration is ValidFunctionDeclaration { + if (!isValidParameterNodeArray(functionDeclaration.parameters)) return false; + switch (functionDeclaration.kind) { + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.MethodDeclaration: + return !!functionDeclaration.name && !!functionDeclaration.body && !checker.isImplementationOfOverload(functionDeclaration); + case SyntaxKind.Constructor: + if (isClassDeclaration(functionDeclaration.parent)) { + return !!functionDeclaration.body && !!functionDeclaration.parent.name && !checker.isImplementationOfOverload(functionDeclaration); + } + else { + return isValidVariableDeclaration(functionDeclaration.parent.parent) && !!functionDeclaration.body && !checker.isImplementationOfOverload(functionDeclaration); + } + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + return isValidVariableDeclaration(functionDeclaration.parent); + } + return false; + } + + function isValidParameterNodeArray(parameters: NodeArray): parameters is ValidParameterNodeArray { + return getRefactorableParametersLength(parameters) >= minimumParameterLength && every(parameters, isValidParameterDeclaration); + } + + function isValidParameterDeclaration(paramDeclaration: ParameterDeclaration): paramDeclaration is ValidParameterDeclaration { + return !paramDeclaration.modifiers && !paramDeclaration.decorators && isIdentifier(paramDeclaration.name); + } + + function isValidVariableDeclaration(node: Node): node is ValidVariableDeclaration { + return isVariableDeclaration(node) && isVarConst(node) && isIdentifier(node.name) && !node.type; // TODO: GH#30113 + } + + function hasThisParameter(parameters: NodeArray): boolean { + return parameters.length > 0 && isThis(parameters[0].name); + } + + function getRefactorableParametersLength(parameters: NodeArray): number { + if (hasThisParameter(parameters)) { + return parameters.length - 1; + } + return parameters.length; + } + + function getRefactorableParameters(parameters: NodeArray): NodeArray { + if (hasThisParameter(parameters)) { + parameters = createNodeArray(parameters.slice(1), parameters.hasTrailingComma); + } + return parameters; + } + + function createNewArgument(functionDeclaration: ValidFunctionDeclaration, functionArguments: NodeArray): ObjectLiteralExpression { + const parameters = getRefactorableParameters(functionDeclaration.parameters); + const hasRestParameter = isRestParameter(last(parameters)); + const nonRestArguments = hasRestParameter ? functionArguments.slice(0, parameters.length - 1) : functionArguments; + const properties = map(nonRestArguments, (arg, i) => { + const property = createPropertyAssignment(getParameterName(parameters[i]), arg); + suppressLeadingAndTrailingTrivia(property.initializer); + copyComments(arg, property); + return property; + }); + + if (hasRestParameter && functionArguments.length >= parameters.length) { + const restArguments = functionArguments.slice(parameters.length - 1); + const restProperty = createPropertyAssignment(getParameterName(last(parameters)), createArrayLiteral(restArguments)); + properties.push(restProperty); + } + + const objectLiteral = createObjectLiteral(properties, /*multiLine*/ false); + return objectLiteral; + } + + function createNewParameters(functionDeclaration: ValidFunctionDeclaration, program: Program, host: LanguageServiceHost): NodeArray { + const refactorableParameters = getRefactorableParameters(functionDeclaration.parameters); + const bindingElements = map(refactorableParameters, createBindingElementFromParameterDeclaration); + const objectParameterName = createObjectBindingPattern(bindingElements); + const objectParameterType = createParameterTypeNode(refactorableParameters); + const checker = program.getTypeChecker(); + + let objectInitializer: Expression | undefined; + // If every parameter in the original function was optional, add an empty object initializer to the new object parameter + if (every(refactorableParameters, checker.isOptionalParameter)) { + objectInitializer = createObjectLiteral(); + } + + const objectParameter = createParameter( + /*decorators*/ undefined, + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + objectParameterName, + /*questionToken*/ undefined, + objectParameterType, + objectInitializer); + + if (hasThisParameter(functionDeclaration.parameters)) { + const thisParameter = functionDeclaration.parameters[0]; + const newThisParameter = createParameter( + /*decorators*/ undefined, + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + thisParameter.name, + /*questionToken*/ undefined, + thisParameter.type); + + suppressLeadingAndTrailingTrivia(newThisParameter.name); + copyComments(thisParameter.name, newThisParameter.name); + if (thisParameter.type) { + suppressLeadingAndTrailingTrivia(newThisParameter.type!); + copyComments(thisParameter.type, newThisParameter.type!); + } + + return createNodeArray([newThisParameter, objectParameter]); + } + return createNodeArray([objectParameter]); + + function createParameterTypeNode(parameters: NodeArray): TypeLiteralNode { + const members = map(parameters, createPropertySignatureFromParameterDeclaration); + const typeNode = addEmitFlags(createTypeLiteralNode(members), EmitFlags.SingleLine); + return typeNode; + } + + function createPropertySignatureFromParameterDeclaration(parameterDeclaration: ValidParameterDeclaration): PropertySignature { + let parameterType = parameterDeclaration.type; + if (!parameterType && (parameterDeclaration.initializer || isRestParameter(parameterDeclaration))) { + parameterType = getTypeNode(parameterDeclaration); + } + + const propertySignature = createPropertySignature( + /*modifiers*/ undefined, + getParameterName(parameterDeclaration), + parameterDeclaration.initializer || isRestParameter(parameterDeclaration) ? createToken(SyntaxKind.QuestionToken) : parameterDeclaration.questionToken, + parameterType, + /*initializer*/ undefined); + + suppressLeadingAndTrailingTrivia(propertySignature); + copyComments(parameterDeclaration.name, propertySignature.name); + if (parameterDeclaration.type && propertySignature.type) { + copyComments(parameterDeclaration.type, propertySignature.type); + } + + return propertySignature; + } + + function getTypeNode(node: Node): TypeNode | undefined { + const checker = program.getTypeChecker(); + const type = checker.getTypeAtLocation(node); + return getTypeNodeIfAccessible(type, node, program, host); + } + } + + function createBindingElementFromParameterDeclaration(parameterDeclaration: ValidParameterDeclaration): BindingElement { + const element = createBindingElement( + /*dotDotDotToken*/ undefined, + /*propertyName*/ undefined, + getParameterName(parameterDeclaration), + isRestParameter(parameterDeclaration) ? createArrayLiteral() : parameterDeclaration.initializer); + + suppressLeadingAndTrailingTrivia(element); + if (parameterDeclaration.initializer && element.initializer) { + copyComments(parameterDeclaration.initializer, element.initializer); + } + return element; + } + + function copyComments(sourceNode: Node, targetNode: Node) { + const sourceFile = sourceNode.getSourceFile(); + const text = sourceFile.text; + if (hasLeadingLineBreak(sourceNode, text)) { + copyLeadingComments(sourceNode, targetNode, sourceFile); + } + else { + copyTrailingAsLeadingComments(sourceNode, targetNode, sourceFile); + } + copyTrailingComments(sourceNode, targetNode, sourceFile); + } + + function hasLeadingLineBreak(node: Node, text: string) { + const start = node.getFullStart(); + const end = node.getStart(); + for (let i = start; i < end; i++) { + if (text.charCodeAt(i) === CharacterCodes.lineFeed) return true; + } + return false; + } + + function getParameterName(paramDeclaration: ValidParameterDeclaration) { + return getTextOfIdentifierOrLiteral(paramDeclaration.name); + } + + function getClassNames(constructorDeclaration: ValidConstructor): Identifier[] { + switch (constructorDeclaration.parent.kind) { + case SyntaxKind.ClassDeclaration: + const classDeclaration = constructorDeclaration.parent; + return [classDeclaration.name]; + case SyntaxKind.ClassExpression: + const classExpression = constructorDeclaration.parent; + const variableDeclaration = constructorDeclaration.parent.parent; + const className = classExpression.name; + if (className) return [className, variableDeclaration.name]; + return [variableDeclaration.name]; + } + } + + function getFunctionNames(functionDeclaration: ValidFunctionDeclaration): Node[] { + switch (functionDeclaration.kind) { + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.MethodDeclaration: + return [functionDeclaration.name]; + case SyntaxKind.Constructor: + const ctrKeyword = findChildOfKind(functionDeclaration, SyntaxKind.ConstructorKeyword, functionDeclaration.getSourceFile())!; + if (functionDeclaration.parent.kind === SyntaxKind.ClassExpression) { + const variableDeclaration = functionDeclaration.parent.parent; + return [variableDeclaration.name, ctrKeyword]; + } + return [ctrKeyword]; + case SyntaxKind.ArrowFunction: + return [functionDeclaration.parent.name]; + case SyntaxKind.FunctionExpression: + if (functionDeclaration.name) return [functionDeclaration.name, functionDeclaration.parent.name]; + return [functionDeclaration.parent.name]; + default: + return Debug.assertNever(functionDeclaration); + } + } + + type ValidParameterNodeArray = NodeArray; + + interface ValidVariableDeclaration extends VariableDeclaration { + name: Identifier; + type: undefined; + } + + interface ValidConstructor extends ConstructorDeclaration { + parent: (ClassDeclaration & { name: Identifier }) | (ClassExpression & { parent: ValidVariableDeclaration }); + parameters: NodeArray; + body: FunctionBody; + } + + interface ValidFunction extends FunctionDeclaration { + name: Identifier; + parameters: NodeArray; + body: FunctionBody; + } + + interface ValidMethod extends MethodDeclaration { + parameters: NodeArray; + body: FunctionBody; + } + + interface ValidFunctionExpression extends FunctionExpression { + parent: ValidVariableDeclaration; + parameters: NodeArray; + } + + interface ValidArrowFunction extends ArrowFunction { + parent: ValidVariableDeclaration; + parameters: NodeArray; + } + + type ValidFunctionDeclaration = ValidConstructor | ValidFunction | ValidMethod | ValidArrowFunction | ValidFunctionExpression; + + interface ValidParameterDeclaration extends ParameterDeclaration { + name: Identifier; + modifiers: undefined; + decorators: undefined; + } + + interface GroupedReferences { + functionCalls: (CallExpression | NewExpression)[]; + declarations: Node[]; + classReferences?: ClassReferences; + valid: boolean; + } + interface ClassReferences { + accessExpressions: Node[]; + typeUsages: Node[]; + } +} \ No newline at end of file diff --git a/src/services/services.ts b/src/services/services.ts index 622c9de7ba3..7f5772d1489 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1798,7 +1798,7 @@ namespace ts { const span = createTextSpanFromBounds(start, end); const formatContext = formatting.getFormatContext(formatOptions); - return flatMap(deduplicate(errorCodes, equateValues, compareValues), errorCode => { + return flatMap(deduplicate(errorCodes, equateValues, compareValues), errorCode => { cancellationToken.throwIfCancellationRequested(); return codefix.getFixes({ errorCode, sourceFile, span, program, host, cancellationToken, formatContext, preferences }); }); diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index 4689e18508c..81441627635 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -28,17 +28,27 @@ namespace ts.textChanges { } export interface ConfigurableStart { - /** True to use getStart() (NB, not getFullStart()) without adjustment. */ - useNonAdjustedStartPosition?: boolean; + leadingTriviaOption?: LeadingTriviaOption; } export interface ConfigurableEnd { - /** True to use getEnd() without adjustment. */ - useNonAdjustedEndPosition?: boolean; + trailingTriviaOption?: TrailingTriviaOption; } - export enum Position { - FullStart, - Start + export enum LeadingTriviaOption { + /** Exclude all leading trivia (use getStart()) */ + Exclude, + /** Include leading trivia and, + * if there are no line breaks between the node and the previous token, + * include all trivia between the node and the previous token + */ + IncludeAll, + } + + export enum TrailingTriviaOption { + /** Exclude all trailing trivia (use getEnd()) */ + Exclude, + /** Include trailing trivia */ + Include, } function skipWhitespacesAndLineBreaks(text: string, start: number) { @@ -68,13 +78,14 @@ namespace ts.textChanges { * Usually leading trivia of the variable declaration 'y' should not include trailing trivia (whitespace, comment 'this is x' and newline) from the preceding * variable declaration and trailing trivia for 'y' should include (whitespace, comment 'this is y', newline). * By default when removing nodes we adjust start and end positions to respect specification of the trivia above. - * If pos\end should be interpreted literally 'useNonAdjustedStartPosition' or 'useNonAdjustedEndPosition' should be set to true + * If pos\end should be interpreted literally (that is, withouth including leading and trailing trivia), `leadingTriviaOption` should be set to `LeadingTriviaOption.Exclude` + * and `trailingTriviaOption` to `TrailingTriviaOption.Exclude`. */ export interface ConfigurableStartEnd extends ConfigurableStart, ConfigurableEnd {} - export const useNonAdjustedPositions: ConfigurableStartEnd = { - useNonAdjustedStartPosition: true, - useNonAdjustedEndPosition: true, + const useNonAdjustedPositions: ConfigurableStartEnd = { + leadingTriviaOption: LeadingTriviaOption.Exclude, + trailingTriviaOption: TrailingTriviaOption.Exclude, }; export interface InsertNodeOptions { @@ -143,11 +154,12 @@ namespace ts.textChanges { } function getAdjustedRange(sourceFile: SourceFile, startNode: Node, endNode: Node, options: ConfigurableStartEnd): TextRange { - return { pos: getAdjustedStartPosition(sourceFile, startNode, options, Position.Start), end: getAdjustedEndPosition(sourceFile, endNode, options) }; + return { pos: getAdjustedStartPosition(sourceFile, startNode, options), end: getAdjustedEndPosition(sourceFile, endNode, options) }; } - function getAdjustedStartPosition(sourceFile: SourceFile, node: Node, options: ConfigurableStart, position: Position) { - if (options.useNonAdjustedStartPosition) { + function getAdjustedStartPosition(sourceFile: SourceFile, node: Node, options: ConfigurableStart) { + const { leadingTriviaOption } = options; + if (leadingTriviaOption === LeadingTriviaOption.Exclude) { return node.getStart(sourceFile); } const fullStart = node.getFullStart(); @@ -165,7 +177,7 @@ namespace ts.textChanges { // fullstart // when b is replaced - we usually want to keep the leading trvia // when b is deleted - we delete it - return position === Position.Start ? start : fullStart; + return leadingTriviaOption === LeadingTriviaOption.IncludeAll ? fullStart : start; } // get start position of the line following the line that contains fullstart position // (but only if the fullstart isn't the very beginning of the file) @@ -178,11 +190,12 @@ namespace ts.textChanges { function getAdjustedEndPosition(sourceFile: SourceFile, node: Node, options: ConfigurableEnd) { const { end } = node; - if (options.useNonAdjustedEndPosition || isExpression(node)) { + const { trailingTriviaOption } = options; + if (trailingTriviaOption === TrailingTriviaOption.Exclude || (isExpression(node) && trailingTriviaOption !== TrailingTriviaOption.Include)) { return end; } const newEnd = skipTrivia(sourceFile.text, end, /*stopAfterLineBreak*/ true); - return newEnd !== end && isLineBreak(sourceFile.text.charCodeAt(newEnd - 1)) + return newEnd !== end && (trailingTriviaOption === TrailingTriviaOption.Include || isLineBreak(sourceFile.text.charCodeAt(newEnd - 1))) ? newEnd : end; } @@ -240,15 +253,15 @@ namespace ts.textChanges { this.deleteRange(sourceFile, { pos: modifier.getStart(sourceFile), end: skipTrivia(sourceFile.text, modifier.end, /*stopAfterLineBreak*/ true) }); } - public deleteNodeRange(sourceFile: SourceFile, startNode: Node, endNode: Node, options: ConfigurableStartEnd = {}): void { - const startPosition = getAdjustedStartPosition(sourceFile, startNode, options, Position.FullStart); + public deleteNodeRange(sourceFile: SourceFile, startNode: Node, endNode: Node, options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }): void { + const startPosition = getAdjustedStartPosition(sourceFile, startNode, options); const endPosition = getAdjustedEndPosition(sourceFile, endNode, options); this.deleteRange(sourceFile, { pos: startPosition, end: endPosition }); } - public deleteNodeRangeExcludingEnd(sourceFile: SourceFile, startNode: Node, afterEndNode: Node | undefined, options: ConfigurableStartEnd = {}): void { - const startPosition = getAdjustedStartPosition(sourceFile, startNode, options, Position.FullStart); - const endPosition = afterEndNode === undefined ? sourceFile.text.length : getAdjustedStartPosition(sourceFile, afterEndNode, options, Position.FullStart); + public deleteNodeRangeExcludingEnd(sourceFile: SourceFile, startNode: Node, afterEndNode: Node | undefined, options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }): void { + const startPosition = getAdjustedStartPosition(sourceFile, startNode, options); + const endPosition = afterEndNode === undefined ? sourceFile.text.length : getAdjustedStartPosition(sourceFile, afterEndNode, options); this.deleteRange(sourceFile, { pos: startPosition, end: endPosition }); } @@ -307,7 +320,7 @@ namespace ts.textChanges { } public insertNodeBefore(sourceFile: SourceFile, before: Node, newNode: Node, blankLineBetween = false): void { - this.insertNodeAt(sourceFile, getAdjustedStartPosition(sourceFile, before, {}, Position.Start), newNode, this.getOptionsForInsertNodeBefore(before, blankLineBetween)); + this.insertNodeAt(sourceFile, getAdjustedStartPosition(sourceFile, before, {}), newNode, this.getOptionsForInsertNodeBefore(before, blankLineBetween)); } public insertModifierBefore(sourceFile: SourceFile, modifier: SyntaxKind, before: Node): void { @@ -427,7 +440,7 @@ namespace ts.textChanges { } public insertNodeAtEndOfScope(sourceFile: SourceFile, scope: Node, newNode: Node): void { - const pos = getAdjustedStartPosition(sourceFile, scope.getLastToken()!, {}, Position.Start); + const pos = getAdjustedStartPosition(sourceFile, scope.getLastToken()!, {}); this.insertNodeAt(sourceFile, pos, newNode, { prefix: isLineBreak(sourceFile.text.charCodeAt(scope.getLastToken()!.pos)) ? this.newLineCharacter : this.newLineCharacter + this.newLineCharacter, suffix: this.newLineCharacter @@ -736,7 +749,7 @@ namespace ts.textChanges { // find first non-whitespace position in the leading trivia of the node function startPositionToDeleteNodeInList(sourceFile: SourceFile, node: Node): number { - return skipTrivia(sourceFile.text, getAdjustedStartPosition(sourceFile, node, {}, Position.FullStart), /*stopAfterLineBreak*/ false, /*stopAtComments*/ true); + return skipTrivia(sourceFile.text, getAdjustedStartPosition(sourceFile, node, { leadingTriviaOption: LeadingTriviaOption.IncludeAll }), /*stopAfterLineBreak*/ false, /*stopAtComments*/ true); } function getClassOrObjectBraceEnds(cls: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression, sourceFile: SourceFile): [number, number] { @@ -1090,7 +1103,7 @@ namespace ts.textChanges { case SyntaxKind.ImportDeclaration: deleteNode(changes, sourceFile, node, // For first import, leave header comment in place - node === sourceFile.imports[0].parent ? { useNonAdjustedStartPosition: true, useNonAdjustedEndPosition: false } : undefined); + node === sourceFile.imports[0].parent ? { leadingTriviaOption: LeadingTriviaOption.Exclude } : undefined); break; case SyntaxKind.BindingElement: @@ -1134,7 +1147,7 @@ namespace ts.textChanges { deleteNodeInList(changes, deletedNodesInLists, sourceFile, node); } else { - deleteNode(changes, sourceFile, node, node.kind === SyntaxKind.SemicolonToken ? { useNonAdjustedEndPosition: true } : undefined); + deleteNode(changes, sourceFile, node, node.kind === SyntaxKind.SemicolonToken ? { trailingTriviaOption: TrailingTriviaOption.Exclude } : undefined); } } } @@ -1213,8 +1226,8 @@ namespace ts.textChanges { /** Warning: This deletes comments too. See `copyComments` in `convertFunctionToEs6Class`. */ // Exported for tests only! (TODO: improve tests to not need this) - export function deleteNode(changes: ChangeTracker, sourceFile: SourceFile, node: Node, options: ConfigurableStartEnd = {}): void { - const startPosition = getAdjustedStartPosition(sourceFile, node, options, Position.FullStart); + export function deleteNode(changes: ChangeTracker, sourceFile: SourceFile, node: Node, options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }): void { + const startPosition = getAdjustedStartPosition(sourceFile, node, options); const endPosition = getAdjustedEndPosition(sourceFile, node, options); changes.deleteRange(sourceFile, { pos: startPosition, end: endPosition }); } diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index 21be663055a..793089e62c8 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -84,6 +84,7 @@ "refactors/generateGetAccessorAndSetAccessor.ts", "refactors/moveToNewFile.ts", "refactors/addOrRemoveBracesToArrowFunction.ts", + "refactors/convertToNamedParameters.ts", "services.ts", "breakpoints.ts", "transform.ts", diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 285ca0cc6a9..004135a526e 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1664,6 +1664,18 @@ namespace ts { return ensureScriptKind(fileName, host && host.getScriptKind && host.getScriptKind(fileName)); } + export function getSymbolTarget(symbol: Symbol): Symbol { + let next: Symbol = symbol; + while (isTransientSymbol(next) && next.target) { + next = next.target; + } + return next; + } + + function isTransientSymbol(symbol: Symbol): symbol is TransientSymbol { + return (symbol.flags & SymbolFlags.Transient) !== 0; + } + export function getUniqueSymbolId(symbol: Symbol, checker: TypeChecker) { return getSymbolId(skipAlias(symbol, checker)); } @@ -1821,8 +1833,28 @@ namespace ts { return lastPos; } - export function copyComments(sourceNode: Node, targetNode: Node, sourceFile: SourceFile, commentKind?: CommentKind, hasTrailingNewLine?: boolean) { - forEachLeadingCommentRange(sourceFile.text, sourceNode.pos, (pos, end, kind, htnl) => { + export function copyLeadingComments(sourceNode: Node, targetNode: Node, sourceFile: SourceFile, commentKind?: CommentKind, hasTrailingNewLine?: boolean) { + forEachLeadingCommentRange(sourceFile.text, sourceNode.pos, getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticLeadingComment)); + } + + + export function copyTrailingComments(sourceNode: Node, targetNode: Node, sourceFile: SourceFile, commentKind?: CommentKind, hasTrailingNewLine?: boolean) { + forEachTrailingCommentRange(sourceFile.text, sourceNode.end, getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticTrailingComment)); + } + + /** + * This function copies the trailing comments for the token that comes before `sourceNode`, as leading comments of `targetNode`. + * This is useful because sometimes a comment that refers to `sourceNode` will be a leading comment for `sourceNode`, according to the + * notion of trivia ownership, and instead will be a trailing comment for the token before `sourceNode`, e.g.: + * `function foo(\* not leading comment for a *\ a: string) {}` + * The comment refers to `a` but belongs to the `(` token, but we might want to copy it. + */ + export function copyTrailingAsLeadingComments(sourceNode: Node, targetNode: Node, sourceFile: SourceFile, commentKind?: CommentKind, hasTrailingNewLine?: boolean) { + forEachTrailingCommentRange(sourceFile.text, sourceNode.pos, getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticLeadingComment)); + } + + function getAddCommentsFunction(targetNode: Node, sourceFile: SourceFile, commentKind: CommentKind | undefined, hasTrailingNewLine: boolean | undefined, cb: (node: Node, kind: CommentKind, text: string, hasTrailingNewLine?: boolean) => void) { + return (pos: number, end: number, kind: CommentKind, htnl: boolean) => { if (kind === SyntaxKind.MultiLineCommentTrivia) { // Remove leading /* pos += 2; @@ -1833,8 +1865,8 @@ namespace ts { // Remove leading // pos += 2; } - addSyntheticLeadingComment(targetNode, commentKind || kind, sourceFile.text.slice(pos, end), hasTrailingNewLine !== undefined ? hasTrailingNewLine : htnl); - }); + cb(targetNode, commentKind || kind, sourceFile.text.slice(pos, end), hasTrailingNewLine !== undefined ? hasTrailingNewLine : htnl); + }; } function indexInTextChange(change: string, name: string): number { @@ -1914,4 +1946,28 @@ namespace ts { export function getSwitchedType(caseClause: CaseClause, checker: TypeChecker): Type | undefined { return checker.getTypeAtLocation(caseClause.parent.parent.expression); } + + export function getTypeNodeIfAccessible(type: Type, enclosingScope: Node, program: Program, host: LanguageServiceHost): TypeNode | undefined { + const checker = program.getTypeChecker(); + let typeIsAccessible = true; + const notAccessible = () => { typeIsAccessible = false; }; + const res = checker.typeToTypeNode(type, enclosingScope, /*flags*/ undefined, { + trackSymbol: (symbol, declaration, meaning) => { + // TODO: GH#18217 + typeIsAccessible = typeIsAccessible && checker.isSymbolAccessible(symbol, declaration, meaning!, /*shouldComputeAliasToMarkVisible*/ false).accessibility === SymbolAccessibility.Accessible; + }, + reportInaccessibleThisError: notAccessible, + reportPrivateInBaseOfClassExpression: notAccessible, + reportInaccessibleUniqueSymbolError: notAccessible, + moduleResolverHost: { + readFile: host.readFile, + fileExists: host.fileExists, + directoryExists: host.directoryExists, + getSourceFiles: program.getSourceFiles, + getCurrentDirectory: program.getCurrentDirectory, + getCommonSourceDirectory: program.getCommonSourceDirectory, + } + }); + return typeIsAccessible ? res : undefined; + } } diff --git a/src/testRunner/parallel/host.ts b/src/testRunner/parallel/host.ts index 597013ed0d9..3e531561e58 100644 --- a/src/testRunner/parallel/host.ts +++ b/src/testRunner/parallel/host.ts @@ -538,25 +538,23 @@ namespace Harness.Parallel.Host { let xunitReporter: import("mocha").reporters.XUnit | undefined; let failedTestReporter: import("../../../scripts/failed-tests") | undefined; - if (Utils.getExecutionEnvironment() !== Utils.ExecutionEnvironment.Browser) { - if (process.env.CI === "true") { - xunitReporter = new Mocha.reporters.XUnit(replayRunner, { - reporterOptions: { - suiteName: "Tests", - output: "./TEST-results.xml" - } - }); - patchStats(xunitReporter.stats); - xunitReporter.write(`\n`); - } - else { - failedTestReporter = new FailedTestReporter(replayRunner, { - reporterOptions: { - file: path.resolve(".failed-tests"), - keepFailed - } - }); - } + if (process.env.CI === "true") { + xunitReporter = new Mocha.reporters.XUnit(replayRunner, { + reporterOptions: { + suiteName: "Tests", + output: "./TEST-results.xml" + } + }); + patchStats(xunitReporter.stats); + xunitReporter.write(`\n`); + } + else { + failedTestReporter = new FailedTestReporter(replayRunner, { + reporterOptions: { + file: path.resolve(".failed-tests"), + keepFailed + } + }); } const savedUseColors = Base.useColors; diff --git a/src/testRunner/runner.ts b/src/testRunner/runner.ts index e528678ab83..be46d935297 100644 --- a/src/testRunner/runner.ts +++ b/src/testRunner/runner.ts @@ -182,10 +182,7 @@ function handleTestConfig() { runners.push(new CompilerBaselineRunner(CompilerTestType.Conformance)); runners.push(new CompilerBaselineRunner(CompilerTestType.Regressions)); - // TODO: project tests don"t work in the browser yet - if (Utils.getExecutionEnvironment() !== Utils.ExecutionEnvironment.Browser) { - runners.push(new project.ProjectRunner()); - } + runners.push(new project.ProjectRunner()); // language services runners.push(new FourSlashRunner(FourSlash.FourSlashTestType.Native)); @@ -195,7 +192,7 @@ function handleTestConfig() { // runners.push(new GeneratedFourslashRunner()); // CRON-only tests - if (Utils.getExecutionEnvironment() !== Utils.ExecutionEnvironment.Browser && process.env.TRAVIS_EVENT_TYPE === "cron") { + if (process.env.TRAVIS_EVENT_TYPE === "cron") { runners.push(new UserCodeRunner()); } } @@ -229,13 +226,11 @@ function beginTests() { let isWorker: boolean; function startTestEnvironment() { isWorker = handleTestConfig(); - if (Utils.getExecutionEnvironment() !== Utils.ExecutionEnvironment.Browser) { - if (isWorker) { - return Harness.Parallel.Worker.start(); - } - else if (taskConfigsFolder && workerCount && workerCount > 1) { - return Harness.Parallel.Host.start(); - } + if (isWorker) { + return Harness.Parallel.Worker.start(); + } + else if (taskConfigsFolder && workerCount && workerCount > 1) { + return Harness.Parallel.Host.start(); } beginTests(); } diff --git a/src/testRunner/tsconfig.json b/src/testRunner/tsconfig.json index 39d57804d39..d912e229b4b 100644 --- a/src/testRunner/tsconfig.json +++ b/src/testRunner/tsconfig.json @@ -105,6 +105,7 @@ "unittests/tscWatch/resolutionCache.ts", "unittests/tscWatch/watchEnvironment.ts", "unittests/tscWatch/watchApi.ts", + "unittests/tsserver/applyChangesToOpenFiles.ts", "unittests/tsserver/cachingFileSystemInformation.ts", "unittests/tsserver/cancellationToken.ts", "unittests/tsserver/compileOnSave.ts", diff --git a/src/testRunner/unittests/services/textChanges.ts b/src/testRunner/unittests/services/textChanges.ts index de92efafbeb..27195c30034 100644 --- a/src/testRunner/unittests/services/textChanges.ts +++ b/src/testRunner/unittests/services/textChanges.ts @@ -140,13 +140,13 @@ var z = 3; // comment 4 deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile)); }); runSingleFileTest("deleteNode2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { useNonAdjustedStartPosition: true }); + deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude }); }); runSingleFileTest("deleteNode3", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { useNonAdjustedEndPosition: true }); + deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude }); }); runSingleFileTest("deleteNode4", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { useNonAdjustedStartPosition: true, useNonAdjustedEndPosition: true }); + deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude }); }); runSingleFileTest("deleteNode5", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { deleteNode(changeTracker, sourceFile, findVariableStatementContaining("x", sourceFile)); @@ -167,15 +167,15 @@ var a = 4; // comment 7 }); runSingleFileTest("deleteNodeRange2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { changeTracker.deleteNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), - { useNonAdjustedStartPosition: true }); + { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude }); }); runSingleFileTest("deleteNodeRange3", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { changeTracker.deleteNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), - { useNonAdjustedEndPosition: true }); + { trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude }); }); runSingleFileTest("deleteNodeRange4", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { changeTracker.deleteNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), - { useNonAdjustedStartPosition: true, useNonAdjustedEndPosition: true }); + { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude }); }); } function createTestVariableDeclaration(name: string) { @@ -254,16 +254,16 @@ var a = 4; // comment 7`; changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { suffix: newLineCharacter }); }); runSingleFileTest("replaceNode2", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { useNonAdjustedStartPosition: true, suffix: newLineCharacter, prefix: newLineCharacter }); + changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, suffix: newLineCharacter, prefix: newLineCharacter }); }); runSingleFileTest("replaceNode3", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { useNonAdjustedEndPosition: true, suffix: newLineCharacter }); + changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude, suffix: newLineCharacter }); }); runSingleFileTest("replaceNode4", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { useNonAdjustedStartPosition: true, useNonAdjustedEndPosition: true }); + changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude }); }); runSingleFileTest("replaceNode5", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNode(sourceFile, findVariableStatementContaining("x", sourceFile), createTestClass(), { useNonAdjustedStartPosition: true, useNonAdjustedEndPosition: true }); + changeTracker.replaceNode(sourceFile, findVariableStatementContaining("x", sourceFile), createTestClass(), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude }); }); } { @@ -279,13 +279,13 @@ var a = 4; // comment 7`; changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { suffix: newLineCharacter }); }); runSingleFileTest("replaceNodeRange2", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { useNonAdjustedStartPosition: true, suffix: newLineCharacter, prefix: newLineCharacter }); + changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, suffix: newLineCharacter, prefix: newLineCharacter }); }); runSingleFileTest("replaceNodeRange3", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { useNonAdjustedEndPosition: true, suffix: newLineCharacter }); + changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude, suffix: newLineCharacter }); }); runSingleFileTest("replaceNodeRange4", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { useNonAdjustedStartPosition: true, useNonAdjustedEndPosition: true }); + changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude }); }); } { diff --git a/src/testRunner/unittests/tsserver/applyChangesToOpenFiles.ts b/src/testRunner/unittests/tsserver/applyChangesToOpenFiles.ts new file mode 100644 index 00000000000..316ecc8b652 --- /dev/null +++ b/src/testRunner/unittests/tsserver/applyChangesToOpenFiles.ts @@ -0,0 +1,148 @@ +namespace ts.projectSystem { + describe("unittests:: tsserver:: applyChangesToOpenFiles", () => { + const configFile: File = { + path: "/a/b/tsconfig.json", + content: "{}" + }; + const file3: File = { + path: "/a/b/file3.ts", + content: "let xyz = 1;" + }; + const app: File = { + path: "/a/b/app.ts", + content: "let z = 1;" + }; + + function fileContentWithComment(file: File) { + return `// some copy right notice +${file.content}`; + } + + function verifyText(service: server.ProjectService, file: string, expected: string) { + const info = service.getScriptInfo(file)!; + const snap = info.getSnapshot(); + // Verified applied in reverse order + assert.equal(snap.getText(0, snap.getLength()), expected, `Text of changed file: ${file}`); + } + + function verifyProjectVersion(project: server.Project, expected: number) { + assert.equal(Number(project.getProjectVersion()), expected); + } + + function verify(applyChangesToOpen: (session: TestSession) => void) { + const host = createServerHost([app, file3, commonFile1, commonFile2, libFile, configFile]); + const session = createSession(host); + session.executeCommandSeq({ + command: protocol.CommandTypes.Open, + arguments: { file: app.path } + }); + const service = session.getProjectService(); + const project = service.configuredProjects.get(configFile.path)!; + assert.isDefined(project); + verifyProjectVersion(project, 1); + session.executeCommandSeq({ + command: protocol.CommandTypes.Open, + arguments: { + file: file3.path, + fileContent: fileContentWithComment(file3) + } + }); + verifyProjectVersion(project, 2); + + // Verify Texts + verifyText(service, commonFile1.path, commonFile1.content); + verifyText(service, commonFile2.path, commonFile2.content); + verifyText(service, app.path, app.content); + verifyText(service, file3.path, fileContentWithComment(file3)); + + // Apply changes + applyChangesToOpen(session); + + // Verify again + verifyProjectVersion(project, 3); + // Open file contents + verifyText(service, commonFile1.path, fileContentWithComment(commonFile1)); + verifyText(service, commonFile2.path, fileContentWithComment(commonFile2)); + verifyText(service, app.path, "let zzz = 10;let zz = 10;let z = 1;"); + verifyText(service, file3.path, file3.content); + } + + it("with applyChangedToOpenFiles request", () => { + verify(session => + session.executeCommandSeq({ + command: protocol.CommandTypes.ApplyChangedToOpenFiles, + arguments: { + openFiles: [ + { + fileName: commonFile1.path, + content: fileContentWithComment(commonFile1) + }, + { + fileName: commonFile2.path, + content: fileContentWithComment(commonFile2) + } + ], + changedFiles: [ + { + fileName: app.path, + changes: [ + { + span: { start: 0, length: 0 }, + newText: "let zzz = 10;" + }, + { + span: { start: 0, length: 0 }, + newText: "let zz = 10;" + } + ] + } + ], + closedFiles: [ + file3.path + ] + } + }) + ); + }); + + it("with updateOpen request", () => { + verify(session => + session.executeCommandSeq({ + command: protocol.CommandTypes.UpdateOpen, + arguments: { + openFiles: [ + { + file: commonFile1.path, + fileContent: fileContentWithComment(commonFile1) + }, + { + file: commonFile2.path, + fileContent: fileContentWithComment(commonFile2) + } + ], + changedFiles: [ + { + fileName: app.path, + textChanges: [ + { + start: { line: 1, offset: 1 }, + end: { line: 1, offset: 1 }, + newText: "let zzz = 10;", + }, + { + start: { line: 1, offset: 1 }, + end: { line: 1, offset: 1 }, + newText: "let zz = 10;", + } + ] + } + ], + closedFiles: [ + file3.path + ] + } + }) + ); + }); + }); +} diff --git a/src/testRunner/unittests/tsserver/documentRegistry.ts b/src/testRunner/unittests/tsserver/documentRegistry.ts index 1761e413833..10723300cc0 100644 --- a/src/testRunner/unittests/tsserver/documentRegistry.ts +++ b/src/testRunner/unittests/tsserver/documentRegistry.ts @@ -41,13 +41,13 @@ namespace ts.projectSystem { function changeFileToNotImportModule(service: TestProjectService) { const info = service.getScriptInfo(file.path)!; - service.applyChangesToFile(info, [{ span: { start: 0, length: importModuleContent.length }, newText: "" }]); + service.applyChangesToFile(info, singleIterator({ span: { start: 0, length: importModuleContent.length }, newText: "" })); checkProject(service, /*moduleIsOrphan*/ true); } function changeFileToImportModule(service: TestProjectService) { const info = service.getScriptInfo(file.path)!; - service.applyChangesToFile(info, [{ span: { start: 0, length: 0 }, newText: importModuleContent }]); + service.applyChangesToFile(info, singleIterator({ span: { start: 0, length: 0 }, newText: importModuleContent })); checkProject(service, /*moduleIsOrphan*/ false); } diff --git a/src/testRunner/unittests/tsserver/externalProjects.ts b/src/testRunner/unittests/tsserver/externalProjects.ts index 2055141538a..82c706500d3 100644 --- a/src/testRunner/unittests/tsserver/externalProjects.ts +++ b/src/testRunner/unittests/tsserver/externalProjects.ts @@ -161,7 +161,7 @@ namespace ts.projectSystem { checkNumberOfInferredProjects(projectService, 0); externalFiles[0].content = "let x =1;"; - projectService.applyChangesInOpenFiles(externalFiles, [], []); + projectService.applyChangesInOpenFiles(arrayIterator(externalFiles)); }); it("external project that included config files", () => { @@ -790,9 +790,7 @@ namespace ts.projectSystem { rootFiles: [{ fileName: tsconfig.path }, { fileName: jsFilePath }], options: { allowJs: false } }]); - service.applyChangesInOpenFiles([ - { fileName: jsFilePath, scriptKind: ScriptKind.JS, content: "" } - ], /*changedFiles*/ undefined, /*closedFiles*/ undefined); + service.applyChangesInOpenFiles(singleIterator({ fileName: jsFilePath, scriptKind: ScriptKind.JS, content: "" })); checkNumberOfProjects(service, { configuredProjects: 1, inferredProjects: 1 }); checkProjectActualFiles(configProject, [tsconfig.path]); const inferredProject = service.inferredProjects[0]; diff --git a/src/testRunner/unittests/tsserver/projects.ts b/src/testRunner/unittests/tsserver/projects.ts index 264dbff285e..81a62c6832e 100644 --- a/src/testRunner/unittests/tsserver/projects.ts +++ b/src/testRunner/unittests/tsserver/projects.ts @@ -202,7 +202,7 @@ namespace ts.projectSystem { const host = createServerHost([file1, config1]); const projectService = createProjectService(host, { useSingleInferredProject: true }, { syntaxOnly: true }); - projectService.applyChangesInOpenFiles([{ fileName: file1.path, content: file1.content }], [], []); + projectService.applyChangesInOpenFiles(singleIterator({ fileName: file1.path, content: file1.content })); checkNumberOfProjects(projectService, { inferredProjects: 1 }); const proj = projectService.inferredProjects[0]; @@ -588,11 +588,11 @@ namespace ts.projectSystem { const host = createServerHost([]); const projectService = createProjectService(host); - projectService.applyChangesInOpenFiles([tsFile], [], []); + projectService.applyChangesInOpenFiles(singleIterator(tsFile)); const projs = projectService.synchronizeProjectList([]); projectService.findProject(projs[0].info!.projectName)!.getLanguageService().getNavigationBarItems(tsFile.fileName); projectService.synchronizeProjectList([projs[0].info!]); - projectService.applyChangesInOpenFiles([jsFile], [], []); + projectService.applyChangesInOpenFiles(singleIterator(jsFile)); }); it("config file is deleted", () => { @@ -696,11 +696,12 @@ namespace ts.projectSystem { checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path, config.path]); // Open HTML file - projectService.applyChangesInOpenFiles( - /*openFiles*/[{ fileName: file2.path, hasMixedContent: true, scriptKind: ScriptKind.JS, content: `var hello = "hello";` }], - /*changedFiles*/ undefined, - /*closedFiles*/ undefined); - + projectService.applyChangesInOpenFiles(singleIterator({ + fileName: file2.path, + hasMixedContent: true, + scriptKind: ScriptKind.JS, + content: `var hello = "hello";` + })); // Now HTML file is included in the project checkNumberOfProjects(projectService, { configuredProjects: 1 }); checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path, config.path]); @@ -853,7 +854,7 @@ namespace ts.projectSystem { checkNumberOfProjects(projectService, { inferredProjects: 1 }); projectService.applyChangesInOpenFiles( /*openFiles*/ undefined, - /*changedFiles*/[{ fileName: file1.path, changes: [{ span: createTextSpan(0, file1.path.length), newText: "let y = 1" }] }], + /*changedFiles*/singleIterator({ fileName: file1.path, changes: singleIterator({ span: createTextSpan(0, file1.path.length), newText: "let y = 1" }) }), /*closedFiles*/ undefined); checkNumberOfProjects(projectService, { inferredProjects: 1 }); diff --git a/src/testRunner/unittests/tsserver/watchEnvironment.ts b/src/testRunner/unittests/tsserver/watchEnvironment.ts index 2c195e0c7d2..bc8e84a8025 100644 --- a/src/testRunner/unittests/tsserver/watchEnvironment.ts +++ b/src/testRunner/unittests/tsserver/watchEnvironment.ts @@ -132,4 +132,79 @@ namespace ts.projectSystem { verifyRootedDirectoryWatch("c:/users/username/"); }); }); + + it(`unittests:: tsserver:: watchEnvironment:: tsserverProjectSystem recursive watch directory implementation does not watch files/directories in node_modules starting with "."`, () => { + const projectFolder = "/a/username/project"; + const projectSrcFolder = `${projectFolder}/src`; + const configFile: File = { + path: `${projectFolder}/tsconfig.json`, + content: "{}" + }; + const index: File = { + path: `${projectSrcFolder}/index.ts`, + content: `import {} from "file"` + }; + const file1: File = { + path: `${projectSrcFolder}/file1.ts`, + content: "" + }; + const nodeModulesExistingUnusedFile: File = { + path: `${projectFolder}/node_modules/someFile.d.ts`, + content: "" + }; + + const fileNames = [index, file1, configFile, libFile].map(file => file.path); + // All closed files(files other than index), project folder, project/src folder and project/node_modules/@types folder + const expectedWatchedFiles = arrayToMap(fileNames.slice(1), identity, () => 1); + const expectedWatchedDirectories = arrayToMap([projectFolder, projectSrcFolder, `${projectFolder}/${nodeModules}`, `${projectFolder}/${nodeModulesAtTypes}`], identity, () => 1); + + const environmentVariables = createMap(); + environmentVariables.set("TSC_WATCHDIRECTORY", Tsc_WatchDirectory.NonRecursiveWatchDirectory); + const host = createServerHost([index, file1, configFile, libFile, nodeModulesExistingUnusedFile], { environmentVariables }); + const projectService = createProjectService(host); + projectService.openClientFile(index.path); + + const project = Debug.assertDefined(projectService.configuredProjects.get(configFile.path)); + verifyProject(); + + const nodeModulesIgnoredFileFromIgnoreDirectory: File = { + path: `${projectFolder}/node_modules/.cache/someFile.d.ts`, + content: "" + }; + host.ensureFileOrFolder(nodeModulesIgnoredFileFromIgnoreDirectory); + host.checkTimeoutQueueLength(0); + verifyProject(); + + const nodeModulesIgnoredFile: File = { + path: `${projectFolder}/node_modules/.cacheFile.ts`, + content: "" + }; + host.ensureFileOrFolder(nodeModulesIgnoredFile); + host.checkTimeoutQueueLength(0); + verifyProject(); + + const gitIgnoredFileFromIgnoreDirectory: File = { + path: `${projectFolder}/.git/someFile.d.ts`, + content: "" + }; + host.ensureFileOrFolder(gitIgnoredFileFromIgnoreDirectory); + host.checkTimeoutQueueLength(0); + verifyProject(); + + const gitIgnoredFile: File = { + path: `${projectFolder}/.gitCache.d.ts`, + content: "" + }; + host.ensureFileOrFolder(gitIgnoredFile); + host.checkTimeoutQueueLength(0); + verifyProject(); + + function verifyProject() { + checkWatchedDirectories(host, emptyArray, /*recursive*/ true); + checkWatchedFilesDetailed(host, expectedWatchedFiles); + checkWatchedDirectoriesDetailed(host, expectedWatchedDirectories, /*recursive*/ false); + checkProjectActualFiles(project, fileNames); + } + }); + } diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 840a0d5a4ca..e99261be3f3 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -5769,6 +5769,7 @@ declare namespace ts.server.protocol { OpenExternalProject = "openExternalProject", OpenExternalProjects = "openExternalProjects", CloseExternalProject = "closeExternalProject", + UpdateOpen = "updateOpen", GetOutliningSpans = "getOutliningSpans", TodoComments = "todoComments", Indentation = "indentation", @@ -6837,6 +6838,30 @@ declare namespace ts.server.protocol { */ interface CloseExternalProjectResponse extends Response { } + /** + * Request to synchronize list of open files with the client + */ + interface UpdateOpenRequest extends Request { + command: CommandTypes.UpdateOpen; + arguments: UpdateOpenRequestArgs; + } + /** + * Arguments to UpdateOpenRequest + */ + interface UpdateOpenRequestArgs { + /** + * List of newly open files + */ + openFiles?: OpenRequestArgs[]; + /** + * List of open files files that were changes + */ + changedFiles?: FileCodeEdits[]; + /** + * List of files that were closed + */ + closedFiles?: string[]; + } /** * Request to set compiler options for inferred projects. * External projects are opened / closed explicitly. @@ -8676,6 +8701,7 @@ declare namespace ts.server { */ private onConfigFileChangeForOpenScriptInfo; private removeProject; + private assignOrphanScriptInfosToInferredProject; /** * Remove this file from the set of open, non-configured files. * @param info The file that has been closed or newly configured @@ -8794,6 +8820,9 @@ declare namespace ts.server { */ openClientFile(fileName: string, fileContent?: string, scriptKind?: ScriptKind, projectRootPath?: string): OpenConfiguredProjectResult; private findExternalProjectContainingOpenScriptInfo; + private getOrCreateOpenScriptInfo; + private assignProjectToOpenedScriptInfo; + private cleanupAfterOpeningFile; openClientFileWithNormalizedPath(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, projectRootPath?: NormalizedPath): OpenConfiguredProjectResult; private removeOrphanConfiguredProjects; private removeOrphanScriptInfos; diff --git a/tests/baselines/reference/contextualSignatureInstantiation1.types b/tests/baselines/reference/contextualSignatureInstantiation1.types index 82e0d7cb6fd..9bb1ff030ca 100644 --- a/tests/baselines/reference/contextualSignatureInstantiation1.types +++ b/tests/baselines/reference/contextualSignatureInstantiation1.types @@ -15,8 +15,8 @@ var e = (x: string, y?: K) => x.length; >length : number var r99 = map(e); // should be {}[] for S since a generic lambda is not inferentially typed ->r99 : (a: {}[]) => number[] ->map(e) : (a: {}[]) => number[] +>r99 : (a: string[]) => number[] +>map(e) : (a: string[]) => number[] >map : (f: (x: S) => T) => (a: S[]) => T[] >e : (x: string, y?: K) => number @@ -37,8 +37,8 @@ var e2 = (x: string, y?: K) => x.length; >length : number var r100 = map2(e2); // type arg inference should fail for S since a generic lambda is not inferentially typed. Falls back to { length: number } ->r100 : (a: { length: number; }[]) => number[] ->map2(e2) : (a: { length: number; }[]) => number[] +>r100 : (a: string[]) => number[] +>map2(e2) : (a: string[]) => number[] >map2 : (f: (x: S) => T) => (a: S[]) => T[] >e2 : (x: string, y?: K) => number diff --git a/tests/baselines/reference/contextualSignatureInstantiation2.types b/tests/baselines/reference/contextualSignatureInstantiation2.types index dbd526ab556..44776b5c01e 100644 --- a/tests/baselines/reference/contextualSignatureInstantiation2.types +++ b/tests/baselines/reference/contextualSignatureInstantiation2.types @@ -31,8 +31,8 @@ var id: (x:T) => T; >x : T var r23 = dot(id)(id); ->r23 : (_: {}) => {} ->dot(id)(id) : (_: {}) => {} +>r23 : (_: T) => {} +>dot(id)(id) : (_: T) => {} >dot(id) : (g: (_: U) => {}) => (_: U) => {} >dot : (f: (_: T) => S) => (g: (_: U) => T) => (_: U) => S >id : (x: T) => T diff --git a/tests/baselines/reference/declarationEmitMappedPrivateTypeTypeParameter.errors.txt b/tests/baselines/reference/declarationEmitMappedPrivateTypeTypeParameter.errors.txt new file mode 100644 index 00000000000..cb7c4f760ad --- /dev/null +++ b/tests/baselines/reference/declarationEmitMappedPrivateTypeTypeParameter.errors.txt @@ -0,0 +1,15 @@ +/FromFactor.ts(2,15): error TS2304: Cannot find name 'StringKeyOf'. +/FromFactor.ts(2,15): error TS4103: Type parameter 'TName' of exported mapped object type is using private name 'StringKeyOf'. + + +==== /Helpers.ts (0 errors) ==== + export type StringKeyOf = Extract; + +==== /FromFactor.ts (2 errors) ==== + export type RowToColumns = { + [TName in StringKeyOf]: any; + ~~~~~~~~~~~ +!!! error TS2304: Cannot find name 'StringKeyOf'. + ~~~~~~~~~~~ +!!! error TS4103: Type parameter 'TName' of exported mapped object type is using private name 'StringKeyOf'. + } \ No newline at end of file diff --git a/tests/baselines/reference/declarationEmitMappedPrivateTypeTypeParameter.js b/tests/baselines/reference/declarationEmitMappedPrivateTypeTypeParameter.js new file mode 100644 index 00000000000..79debe1b4b8 --- /dev/null +++ b/tests/baselines/reference/declarationEmitMappedPrivateTypeTypeParameter.js @@ -0,0 +1,20 @@ +//// [tests/cases/compiler/declarationEmitMappedPrivateTypeTypeParameter.ts] //// + +//// [Helpers.ts] +export type StringKeyOf = Extract; + +//// [FromFactor.ts] +export type RowToColumns = { + [TName in StringKeyOf]: any; +} + +//// [Helpers.js] +"use strict"; +exports.__esModule = true; +//// [FromFactor.js] +"use strict"; +exports.__esModule = true; + + +//// [Helpers.d.ts] +export declare type StringKeyOf = Extract; diff --git a/tests/baselines/reference/declarationEmitMappedPrivateTypeTypeParameter.symbols b/tests/baselines/reference/declarationEmitMappedPrivateTypeTypeParameter.symbols new file mode 100644 index 00000000000..073e34762cd --- /dev/null +++ b/tests/baselines/reference/declarationEmitMappedPrivateTypeTypeParameter.symbols @@ -0,0 +1,16 @@ +=== /Helpers.ts === +export type StringKeyOf = Extract; +>StringKeyOf : Symbol(StringKeyOf, Decl(Helpers.ts, 0, 0)) +>TObj : Symbol(TObj, Decl(Helpers.ts, 0, 24)) +>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --)) +>TObj : Symbol(TObj, Decl(Helpers.ts, 0, 24)) + +=== /FromFactor.ts === +export type RowToColumns = { +>RowToColumns : Symbol(RowToColumns, Decl(FromFactor.ts, 0, 0)) +>TColumns : Symbol(TColumns, Decl(FromFactor.ts, 0, 25)) + + [TName in StringKeyOf]: any; +>TName : Symbol(TName, Decl(FromFactor.ts, 1, 5)) +>TColumns : Symbol(TColumns, Decl(FromFactor.ts, 0, 25)) +} diff --git a/tests/baselines/reference/declarationEmitMappedPrivateTypeTypeParameter.types b/tests/baselines/reference/declarationEmitMappedPrivateTypeTypeParameter.types new file mode 100644 index 00000000000..142549c4d01 --- /dev/null +++ b/tests/baselines/reference/declarationEmitMappedPrivateTypeTypeParameter.types @@ -0,0 +1,10 @@ +=== /Helpers.ts === +export type StringKeyOf = Extract; +>StringKeyOf : Extract + +=== /FromFactor.ts === +export type RowToColumns = { +>RowToColumns : RowToColumns + + [TName in StringKeyOf]: any; +} diff --git a/tests/baselines/reference/genericFunctionInference1.errors.txt b/tests/baselines/reference/genericFunctionInference1.errors.txt new file mode 100644 index 00000000000..9b082d39ab2 --- /dev/null +++ b/tests/baselines/reference/genericFunctionInference1.errors.txt @@ -0,0 +1,193 @@ +tests/cases/compiler/genericFunctionInference1.ts(83,14): error TS2345: Argument of type '(value: { key: a; }) => a' is not assignable to parameter of type '(value: Data) => string'. + Type 'number' is not assignable to type 'string'. + + +==== tests/cases/compiler/genericFunctionInference1.ts (1 errors) ==== + declare function pipe(ab: (...args: A) => B): (...args: A) => B; + declare function pipe(ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; + declare function pipe(ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; + + declare function list(a: T): T[]; + declare function box(x: V): { value: V }; + declare function foo(x: T): T; + + const f00 = pipe(list); + const f01 = pipe(list, box); + const f02 = pipe(box, list); + const f03 = pipe(x => list(x), box); + const f04 = pipe(list, x => box(x)); + const f05 = pipe(x => list(x), x => box(x)) + const f06 = pipe(list, pipe(box)); + const f07 = pipe(x => list(x), pipe(box)); + const f08 = pipe(x => list(x), pipe(x => box(x))); + const f09 = pipe(list, x => x.length); + const f10 = pipe(foo); + const f11 = pipe(foo, foo); + + const g00: (x: T) => T[] = pipe(list); + const g01: (x: T) => { value: T[] } = pipe(list, box); + const g02: (x: T) => { value: T }[] = pipe(box, list); + const g03: (x: T) => { value: T[] } = pipe(x => list(x), box); + const g04: (x: T) => { value: T[] } = pipe(list, x => box(x)); + const g05: (x: T) => { value: T[] } = pipe(x => list(x), x => box(x)) + const g06: (x: T) => { value: T[] } = pipe(list, pipe(box)); + const g07: (x: T) => { value: T[] } = pipe(x => list(x), pipe(box)); + const g08: (x: T) => { value: T[] } = pipe(x => list(x), pipe(x => box(x))); + const g09: (x: T) => number = pipe(list, x => x.length); + const g10: (x: T) => T = pipe(foo); + const g12: (x: T) => T = pipe(foo, foo); + + declare function pipe2(ab: (a: A) => B, cd: (c: C) => D): (a: [A, C]) => [B, D]; + + const f20 = pipe2(list, box); + const f21 = pipe2(box, list); + const f22 = pipe2(list, list); + const f23 = pipe2(box, box); + const f24 = pipe2(f20, f20); + const f25 = pipe2(foo, foo); + const f26 = pipe2(f25, f25); + + declare function pipe3(ab: (a: A) => B, ac: (a: A) => C): (a: A) => [B, C]; + + const f30 = pipe3(list, box); + const f31 = pipe3(box, list); + const f32 = pipe3(list, list); + + declare function pipe4(funcs: [(a: A) => B, (b: B) => C]): (a: A) => C; + + const f40 = pipe4([list, box]); + const f41 = pipe4([box, list]); + + declare function pipe5(f: (a: A) => B): { f: (a: A) => B }; + + const f50 = pipe5(list); // No higher order inference + + // #417 + + function mirror(f: (a: A) => B): (a: A) => B { return f; } + var identityM = mirror(identity); + + var x = 1; + var y = identity(x); + var z = identityM(x); + + // #3038 + + export function keyOf(value: { key: a; }): a { + return value.key; + } + export interface Data { + key: number; + value: Date; + } + + var data: Data[] = []; + + declare function toKeys(values: a[], toKey: (value: a) => string): string[]; + + toKeys(data, keyOf); // Error + ~~~~~ +!!! error TS2345: Argument of type '(value: { key: a; }) => a' is not assignable to parameter of type '(value: Data) => string'. +!!! error TS2345: Type 'number' is not assignable to type 'string'. + + // #9366 + + function flip(f: (a: a, b: b) => c): (b: b, a: a) => c { + return (b: b, a: a) => f(a, b); + } + function zip(x: T, y: U): [T, U] { + return [x, y]; + } + + var expected: (y: U, x: T) => [T, U] = flip(zip); + var actual = flip(zip); + + // #9366 + + const map = (transform: (t: T) => U) => + (arr: T[]) => arr.map(transform) + + const identityStr = (t: string) => t; + + const arr: string[] = map(identityStr)(['a']); + const arr1: string[] = map(identity)(['a']); + + // #9949 + + function of2(one: a, two: b): [a, b] { + return [one, two]; + } + + const flipped = flip(of2); + + // #29904.1 + + type Component

= (props: P) => {}; + + declare const myHoc1:

(C: Component

) => Component

; + declare const myHoc2:

(C: Component

) => Component

; + + declare const MyComponent1: Component<{ foo: 1 }>; + + const enhance = pipe( + myHoc1, + myHoc2, + ); + + const MyComponent2 = enhance(MyComponent1); + + // #29904.2 + + const fn20 = pipe((_a?: {}) => 1); + + // #29904.3 + + type Fn = (n: number) => number; + const fn30: Fn = pipe( + x => x + 1, + x => x * 2, + ); + + const promise = Promise.resolve(1); + promise.then( + pipe( + x => x + 1, + x => x * 2, + ), + ); + + // #29904.4 + + declare const getString: () => string; + declare const orUndefined: (name: string) => string | undefined; + declare const identity: (value: T) => T; + + const fn40 = pipe( + getString, + string => orUndefined(string), + identity, + ); + + // #29904.6 + + declare const getArray: () => string[]; + declare const first: (ts: T[]) => T; + + const fn60 = pipe( + getArray, + x => x, + first, + ); + + const fn61 = pipe( + getArray, + identity, + first, + ); + + const fn62 = pipe( + getArray, + x => x, + x => first(x), + ); + \ No newline at end of file diff --git a/tests/baselines/reference/genericFunctionInference1.js b/tests/baselines/reference/genericFunctionInference1.js new file mode 100644 index 00000000000..4e89f9c0795 --- /dev/null +++ b/tests/baselines/reference/genericFunctionInference1.js @@ -0,0 +1,267 @@ +//// [genericFunctionInference1.ts] +declare function pipe(ab: (...args: A) => B): (...args: A) => B; +declare function pipe(ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; +declare function pipe(ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; + +declare function list(a: T): T[]; +declare function box(x: V): { value: V }; +declare function foo(x: T): T; + +const f00 = pipe(list); +const f01 = pipe(list, box); +const f02 = pipe(box, list); +const f03 = pipe(x => list(x), box); +const f04 = pipe(list, x => box(x)); +const f05 = pipe(x => list(x), x => box(x)) +const f06 = pipe(list, pipe(box)); +const f07 = pipe(x => list(x), pipe(box)); +const f08 = pipe(x => list(x), pipe(x => box(x))); +const f09 = pipe(list, x => x.length); +const f10 = pipe(foo); +const f11 = pipe(foo, foo); + +const g00: (x: T) => T[] = pipe(list); +const g01: (x: T) => { value: T[] } = pipe(list, box); +const g02: (x: T) => { value: T }[] = pipe(box, list); +const g03: (x: T) => { value: T[] } = pipe(x => list(x), box); +const g04: (x: T) => { value: T[] } = pipe(list, x => box(x)); +const g05: (x: T) => { value: T[] } = pipe(x => list(x), x => box(x)) +const g06: (x: T) => { value: T[] } = pipe(list, pipe(box)); +const g07: (x: T) => { value: T[] } = pipe(x => list(x), pipe(box)); +const g08: (x: T) => { value: T[] } = pipe(x => list(x), pipe(x => box(x))); +const g09: (x: T) => number = pipe(list, x => x.length); +const g10: (x: T) => T = pipe(foo); +const g12: (x: T) => T = pipe(foo, foo); + +declare function pipe2(ab: (a: A) => B, cd: (c: C) => D): (a: [A, C]) => [B, D]; + +const f20 = pipe2(list, box); +const f21 = pipe2(box, list); +const f22 = pipe2(list, list); +const f23 = pipe2(box, box); +const f24 = pipe2(f20, f20); +const f25 = pipe2(foo, foo); +const f26 = pipe2(f25, f25); + +declare function pipe3(ab: (a: A) => B, ac: (a: A) => C): (a: A) => [B, C]; + +const f30 = pipe3(list, box); +const f31 = pipe3(box, list); +const f32 = pipe3(list, list); + +declare function pipe4(funcs: [(a: A) => B, (b: B) => C]): (a: A) => C; + +const f40 = pipe4([list, box]); +const f41 = pipe4([box, list]); + +declare function pipe5(f: (a: A) => B): { f: (a: A) => B }; + +const f50 = pipe5(list); // No higher order inference + +// #417 + +function mirror(f: (a: A) => B): (a: A) => B { return f; } +var identityM = mirror(identity); + +var x = 1; +var y = identity(x); +var z = identityM(x); + +// #3038 + +export function keyOf(value: { key: a; }): a { + return value.key; +} +export interface Data { + key: number; + value: Date; +} + +var data: Data[] = []; + +declare function toKeys(values: a[], toKey: (value: a) => string): string[]; + +toKeys(data, keyOf); // Error + +// #9366 + +function flip(f: (a: a, b: b) => c): (b: b, a: a) => c { + return (b: b, a: a) => f(a, b); +} +function zip(x: T, y: U): [T, U] { + return [x, y]; +} + +var expected: (y: U, x: T) => [T, U] = flip(zip); +var actual = flip(zip); + +// #9366 + +const map = (transform: (t: T) => U) => + (arr: T[]) => arr.map(transform) + +const identityStr = (t: string) => t; + +const arr: string[] = map(identityStr)(['a']); +const arr1: string[] = map(identity)(['a']); + +// #9949 + +function of2(one: a, two: b): [a, b] { + return [one, two]; +} + +const flipped = flip(of2); + +// #29904.1 + +type Component

= (props: P) => {}; + +declare const myHoc1:

(C: Component

) => Component

; +declare const myHoc2:

(C: Component

) => Component

; + +declare const MyComponent1: Component<{ foo: 1 }>; + +const enhance = pipe( + myHoc1, + myHoc2, +); + +const MyComponent2 = enhance(MyComponent1); + +// #29904.2 + +const fn20 = pipe((_a?: {}) => 1); + +// #29904.3 + +type Fn = (n: number) => number; +const fn30: Fn = pipe( + x => x + 1, + x => x * 2, +); + +const promise = Promise.resolve(1); +promise.then( + pipe( + x => x + 1, + x => x * 2, + ), +); + +// #29904.4 + +declare const getString: () => string; +declare const orUndefined: (name: string) => string | undefined; +declare const identity: (value: T) => T; + +const fn40 = pipe( + getString, + string => orUndefined(string), + identity, +); + +// #29904.6 + +declare const getArray: () => string[]; +declare const first: (ts: T[]) => T; + +const fn60 = pipe( + getArray, + x => x, + first, +); + +const fn61 = pipe( + getArray, + identity, + first, +); + +const fn62 = pipe( + getArray, + x => x, + x => first(x), +); + + +//// [genericFunctionInference1.js] +const f00 = pipe(list); +const f01 = pipe(list, box); +const f02 = pipe(box, list); +const f03 = pipe(x => list(x), box); +const f04 = pipe(list, x => box(x)); +const f05 = pipe(x => list(x), x => box(x)); +const f06 = pipe(list, pipe(box)); +const f07 = pipe(x => list(x), pipe(box)); +const f08 = pipe(x => list(x), pipe(x => box(x))); +const f09 = pipe(list, x => x.length); +const f10 = pipe(foo); +const f11 = pipe(foo, foo); +const g00 = pipe(list); +const g01 = pipe(list, box); +const g02 = pipe(box, list); +const g03 = pipe(x => list(x), box); +const g04 = pipe(list, x => box(x)); +const g05 = pipe(x => list(x), x => box(x)); +const g06 = pipe(list, pipe(box)); +const g07 = pipe(x => list(x), pipe(box)); +const g08 = pipe(x => list(x), pipe(x => box(x))); +const g09 = pipe(list, x => x.length); +const g10 = pipe(foo); +const g12 = pipe(foo, foo); +const f20 = pipe2(list, box); +const f21 = pipe2(box, list); +const f22 = pipe2(list, list); +const f23 = pipe2(box, box); +const f24 = pipe2(f20, f20); +const f25 = pipe2(foo, foo); +const f26 = pipe2(f25, f25); +const f30 = pipe3(list, box); +const f31 = pipe3(box, list); +const f32 = pipe3(list, list); +const f40 = pipe4([list, box]); +const f41 = pipe4([box, list]); +const f50 = pipe5(list); // No higher order inference +// #417 +function mirror(f) { return f; } +var identityM = mirror(identity); +var x = 1; +var y = identity(x); +var z = identityM(x); +// #3038 +export function keyOf(value) { + return value.key; +} +var data = []; +toKeys(data, keyOf); // Error +// #9366 +function flip(f) { + return (b, a) => f(a, b); +} +function zip(x, y) { + return [x, y]; +} +var expected = flip(zip); +var actual = flip(zip); +// #9366 +const map = (transform) => (arr) => arr.map(transform); +const identityStr = (t) => t; +const arr = map(identityStr)(['a']); +const arr1 = map(identity)(['a']); +// #9949 +function of2(one, two) { + return [one, two]; +} +const flipped = flip(of2); +const enhance = pipe(myHoc1, myHoc2); +const MyComponent2 = enhance(MyComponent1); +// #29904.2 +const fn20 = pipe((_a) => 1); +const fn30 = pipe(x => x + 1, x => x * 2); +const promise = Promise.resolve(1); +promise.then(pipe(x => x + 1, x => x * 2)); +const fn40 = pipe(getString, string => orUndefined(string), identity); +const fn60 = pipe(getArray, x => x, first); +const fn61 = pipe(getArray, identity, first); +const fn62 = pipe(getArray, x => x, x => first(x)); diff --git a/tests/baselines/reference/genericFunctionInference1.symbols b/tests/baselines/reference/genericFunctionInference1.symbols new file mode 100644 index 00000000000..9ee085feae8 --- /dev/null +++ b/tests/baselines/reference/genericFunctionInference1.symbols @@ -0,0 +1,850 @@ +=== tests/cases/compiler/genericFunctionInference1.ts === +declare function pipe(ab: (...args: A) => B): (...args: A) => B; +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 0, 22)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 0, 38)) +>ab : Symbol(ab, Decl(genericFunctionInference1.ts, 0, 42)) +>args : Symbol(args, Decl(genericFunctionInference1.ts, 0, 47)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 0, 22)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 0, 38)) +>args : Symbol(args, Decl(genericFunctionInference1.ts, 0, 67)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 0, 22)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 0, 38)) + +declare function pipe(ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 1, 22)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 1, 38)) +>C : Symbol(C, Decl(genericFunctionInference1.ts, 1, 41)) +>ab : Symbol(ab, Decl(genericFunctionInference1.ts, 1, 45)) +>args : Symbol(args, Decl(genericFunctionInference1.ts, 1, 50)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 1, 22)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 1, 38)) +>bc : Symbol(bc, Decl(genericFunctionInference1.ts, 1, 67)) +>b : Symbol(b, Decl(genericFunctionInference1.ts, 1, 73)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 1, 38)) +>C : Symbol(C, Decl(genericFunctionInference1.ts, 1, 41)) +>args : Symbol(args, Decl(genericFunctionInference1.ts, 1, 87)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 1, 22)) +>C : Symbol(C, Decl(genericFunctionInference1.ts, 1, 41)) + +declare function pipe(ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 2, 22)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 2, 38)) +>C : Symbol(C, Decl(genericFunctionInference1.ts, 2, 41)) +>D : Symbol(D, Decl(genericFunctionInference1.ts, 2, 44)) +>ab : Symbol(ab, Decl(genericFunctionInference1.ts, 2, 48)) +>args : Symbol(args, Decl(genericFunctionInference1.ts, 2, 53)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 2, 22)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 2, 38)) +>bc : Symbol(bc, Decl(genericFunctionInference1.ts, 2, 70)) +>b : Symbol(b, Decl(genericFunctionInference1.ts, 2, 76)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 2, 38)) +>C : Symbol(C, Decl(genericFunctionInference1.ts, 2, 41)) +>cd : Symbol(cd, Decl(genericFunctionInference1.ts, 2, 87)) +>c : Symbol(c, Decl(genericFunctionInference1.ts, 2, 93)) +>C : Symbol(C, Decl(genericFunctionInference1.ts, 2, 41)) +>D : Symbol(D, Decl(genericFunctionInference1.ts, 2, 44)) +>args : Symbol(args, Decl(genericFunctionInference1.ts, 2, 107)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 2, 22)) +>D : Symbol(D, Decl(genericFunctionInference1.ts, 2, 44)) + +declare function list(a: T): T[]; +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 4, 22)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 4, 25)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 4, 22)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 4, 22)) + +declare function box(x: V): { value: V }; +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) +>V : Symbol(V, Decl(genericFunctionInference1.ts, 5, 21)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 5, 24)) +>V : Symbol(V, Decl(genericFunctionInference1.ts, 5, 21)) +>value : Symbol(value, Decl(genericFunctionInference1.ts, 5, 32)) +>V : Symbol(V, Decl(genericFunctionInference1.ts, 5, 21)) + +declare function foo(x: T): T; +>foo : Symbol(foo, Decl(genericFunctionInference1.ts, 5, 44)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 6, 21)) +>value : Symbol(value, Decl(genericFunctionInference1.ts, 6, 32)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 6, 21)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 6, 45)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 6, 21)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 6, 21)) + +const f00 = pipe(list); +>f00 : Symbol(f00, Decl(genericFunctionInference1.ts, 8, 5)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) + +const f01 = pipe(list, box); +>f01 : Symbol(f01, Decl(genericFunctionInference1.ts, 9, 5)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) + +const f02 = pipe(box, list); +>f02 : Symbol(f02, Decl(genericFunctionInference1.ts, 10, 5)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) + +const f03 = pipe(x => list(x), box); +>f03 : Symbol(f03, Decl(genericFunctionInference1.ts, 11, 5)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 11, 17)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 11, 17)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) + +const f04 = pipe(list, x => box(x)); +>f04 : Symbol(f04, Decl(genericFunctionInference1.ts, 12, 5)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 12, 22)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 12, 22)) + +const f05 = pipe(x => list(x), x => box(x)) +>f05 : Symbol(f05, Decl(genericFunctionInference1.ts, 13, 5)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 13, 17)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 13, 17)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 13, 30)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 13, 30)) + +const f06 = pipe(list, pipe(box)); +>f06 : Symbol(f06, Decl(genericFunctionInference1.ts, 14, 5)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) + +const f07 = pipe(x => list(x), pipe(box)); +>f07 : Symbol(f07, Decl(genericFunctionInference1.ts, 15, 5)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 15, 17)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 15, 17)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) + +const f08 = pipe(x => list(x), pipe(x => box(x))); +>f08 : Symbol(f08, Decl(genericFunctionInference1.ts, 16, 5)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 16, 17)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 16, 17)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 16, 36)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 16, 36)) + +const f09 = pipe(list, x => x.length); +>f09 : Symbol(f09, Decl(genericFunctionInference1.ts, 17, 5)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 17, 22)) +>x.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 17, 22)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) + +const f10 = pipe(foo); +>f10 : Symbol(f10, Decl(genericFunctionInference1.ts, 18, 5)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>foo : Symbol(foo, Decl(genericFunctionInference1.ts, 5, 44)) + +const f11 = pipe(foo, foo); +>f11 : Symbol(f11, Decl(genericFunctionInference1.ts, 19, 5)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>foo : Symbol(foo, Decl(genericFunctionInference1.ts, 5, 44)) +>foo : Symbol(foo, Decl(genericFunctionInference1.ts, 5, 44)) + +const g00: (x: T) => T[] = pipe(list); +>g00 : Symbol(g00, Decl(genericFunctionInference1.ts, 21, 5)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 21, 12)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 21, 15)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 21, 12)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 21, 12)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) + +const g01: (x: T) => { value: T[] } = pipe(list, box); +>g01 : Symbol(g01, Decl(genericFunctionInference1.ts, 22, 5)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 22, 12)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 22, 15)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 22, 12)) +>value : Symbol(value, Decl(genericFunctionInference1.ts, 22, 25)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 22, 12)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) + +const g02: (x: T) => { value: T }[] = pipe(box, list); +>g02 : Symbol(g02, Decl(genericFunctionInference1.ts, 23, 5)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 23, 12)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 23, 15)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 23, 12)) +>value : Symbol(value, Decl(genericFunctionInference1.ts, 23, 25)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 23, 12)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) + +const g03: (x: T) => { value: T[] } = pipe(x => list(x), box); +>g03 : Symbol(g03, Decl(genericFunctionInference1.ts, 24, 5)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 24, 12)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 24, 15)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 24, 12)) +>value : Symbol(value, Decl(genericFunctionInference1.ts, 24, 25)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 24, 12)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 24, 46)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 24, 46)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) + +const g04: (x: T) => { value: T[] } = pipe(list, x => box(x)); +>g04 : Symbol(g04, Decl(genericFunctionInference1.ts, 25, 5)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 25, 12)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 25, 15)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 25, 12)) +>value : Symbol(value, Decl(genericFunctionInference1.ts, 25, 25)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 25, 12)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 25, 51)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 25, 51)) + +const g05: (x: T) => { value: T[] } = pipe(x => list(x), x => box(x)) +>g05 : Symbol(g05, Decl(genericFunctionInference1.ts, 26, 5)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 26, 12)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 26, 15)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 26, 12)) +>value : Symbol(value, Decl(genericFunctionInference1.ts, 26, 25)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 26, 12)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 26, 46)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 26, 46)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 26, 59)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 26, 59)) + +const g06: (x: T) => { value: T[] } = pipe(list, pipe(box)); +>g06 : Symbol(g06, Decl(genericFunctionInference1.ts, 27, 5)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 27, 12)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 27, 15)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 27, 12)) +>value : Symbol(value, Decl(genericFunctionInference1.ts, 27, 25)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 27, 12)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) + +const g07: (x: T) => { value: T[] } = pipe(x => list(x), pipe(box)); +>g07 : Symbol(g07, Decl(genericFunctionInference1.ts, 28, 5)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 28, 12)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 28, 15)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 28, 12)) +>value : Symbol(value, Decl(genericFunctionInference1.ts, 28, 25)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 28, 12)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 28, 46)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 28, 46)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) + +const g08: (x: T) => { value: T[] } = pipe(x => list(x), pipe(x => box(x))); +>g08 : Symbol(g08, Decl(genericFunctionInference1.ts, 29, 5)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 29, 12)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 29, 15)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 29, 12)) +>value : Symbol(value, Decl(genericFunctionInference1.ts, 29, 25)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 29, 12)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 29, 46)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 29, 46)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 29, 65)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 29, 65)) + +const g09: (x: T) => number = pipe(list, x => x.length); +>g09 : Symbol(g09, Decl(genericFunctionInference1.ts, 30, 5)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 30, 12)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 30, 15)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 30, 12)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 30, 43)) +>x.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 30, 43)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) + +const g10: (x: T) => T = pipe(foo); +>g10 : Symbol(g10, Decl(genericFunctionInference1.ts, 31, 5)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 31, 12)) +>value : Symbol(value, Decl(genericFunctionInference1.ts, 31, 23)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 31, 12)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 31, 36)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 31, 12)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 31, 12)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>foo : Symbol(foo, Decl(genericFunctionInference1.ts, 5, 44)) + +const g12: (x: T) => T = pipe(foo, foo); +>g12 : Symbol(g12, Decl(genericFunctionInference1.ts, 32, 5)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 32, 12)) +>value : Symbol(value, Decl(genericFunctionInference1.ts, 32, 23)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 32, 12)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 32, 36)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 32, 12)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 32, 12)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>foo : Symbol(foo, Decl(genericFunctionInference1.ts, 5, 44)) +>foo : Symbol(foo, Decl(genericFunctionInference1.ts, 5, 44)) + +declare function pipe2(ab: (a: A) => B, cd: (c: C) => D): (a: [A, C]) => [B, D]; +>pipe2 : Symbol(pipe2, Decl(genericFunctionInference1.ts, 32, 64)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 34, 23)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 34, 25)) +>C : Symbol(C, Decl(genericFunctionInference1.ts, 34, 28)) +>D : Symbol(D, Decl(genericFunctionInference1.ts, 34, 31)) +>ab : Symbol(ab, Decl(genericFunctionInference1.ts, 34, 35)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 34, 40)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 34, 23)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 34, 25)) +>cd : Symbol(cd, Decl(genericFunctionInference1.ts, 34, 51)) +>c : Symbol(c, Decl(genericFunctionInference1.ts, 34, 57)) +>C : Symbol(C, Decl(genericFunctionInference1.ts, 34, 28)) +>D : Symbol(D, Decl(genericFunctionInference1.ts, 34, 31)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 34, 71)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 34, 23)) +>C : Symbol(C, Decl(genericFunctionInference1.ts, 34, 28)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 34, 25)) +>D : Symbol(D, Decl(genericFunctionInference1.ts, 34, 31)) + +const f20 = pipe2(list, box); +>f20 : Symbol(f20, Decl(genericFunctionInference1.ts, 36, 5)) +>pipe2 : Symbol(pipe2, Decl(genericFunctionInference1.ts, 32, 64)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) + +const f21 = pipe2(box, list); +>f21 : Symbol(f21, Decl(genericFunctionInference1.ts, 37, 5)) +>pipe2 : Symbol(pipe2, Decl(genericFunctionInference1.ts, 32, 64)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) + +const f22 = pipe2(list, list); +>f22 : Symbol(f22, Decl(genericFunctionInference1.ts, 38, 5)) +>pipe2 : Symbol(pipe2, Decl(genericFunctionInference1.ts, 32, 64)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) + +const f23 = pipe2(box, box); +>f23 : Symbol(f23, Decl(genericFunctionInference1.ts, 39, 5)) +>pipe2 : Symbol(pipe2, Decl(genericFunctionInference1.ts, 32, 64)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) + +const f24 = pipe2(f20, f20); +>f24 : Symbol(f24, Decl(genericFunctionInference1.ts, 40, 5)) +>pipe2 : Symbol(pipe2, Decl(genericFunctionInference1.ts, 32, 64)) +>f20 : Symbol(f20, Decl(genericFunctionInference1.ts, 36, 5)) +>f20 : Symbol(f20, Decl(genericFunctionInference1.ts, 36, 5)) + +const f25 = pipe2(foo, foo); +>f25 : Symbol(f25, Decl(genericFunctionInference1.ts, 41, 5)) +>pipe2 : Symbol(pipe2, Decl(genericFunctionInference1.ts, 32, 64)) +>foo : Symbol(foo, Decl(genericFunctionInference1.ts, 5, 44)) +>foo : Symbol(foo, Decl(genericFunctionInference1.ts, 5, 44)) + +const f26 = pipe2(f25, f25); +>f26 : Symbol(f26, Decl(genericFunctionInference1.ts, 42, 5)) +>pipe2 : Symbol(pipe2, Decl(genericFunctionInference1.ts, 32, 64)) +>f25 : Symbol(f25, Decl(genericFunctionInference1.ts, 41, 5)) +>f25 : Symbol(f25, Decl(genericFunctionInference1.ts, 41, 5)) + +declare function pipe3(ab: (a: A) => B, ac: (a: A) => C): (a: A) => [B, C]; +>pipe3 : Symbol(pipe3, Decl(genericFunctionInference1.ts, 42, 28)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 44, 23)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 44, 25)) +>C : Symbol(C, Decl(genericFunctionInference1.ts, 44, 28)) +>ab : Symbol(ab, Decl(genericFunctionInference1.ts, 44, 32)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 44, 37)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 44, 23)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 44, 25)) +>ac : Symbol(ac, Decl(genericFunctionInference1.ts, 44, 48)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 44, 54)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 44, 23)) +>C : Symbol(C, Decl(genericFunctionInference1.ts, 44, 28)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 44, 68)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 44, 23)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 44, 25)) +>C : Symbol(C, Decl(genericFunctionInference1.ts, 44, 28)) + +const f30 = pipe3(list, box); +>f30 : Symbol(f30, Decl(genericFunctionInference1.ts, 46, 5)) +>pipe3 : Symbol(pipe3, Decl(genericFunctionInference1.ts, 42, 28)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) + +const f31 = pipe3(box, list); +>f31 : Symbol(f31, Decl(genericFunctionInference1.ts, 47, 5)) +>pipe3 : Symbol(pipe3, Decl(genericFunctionInference1.ts, 42, 28)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) + +const f32 = pipe3(list, list); +>f32 : Symbol(f32, Decl(genericFunctionInference1.ts, 48, 5)) +>pipe3 : Symbol(pipe3, Decl(genericFunctionInference1.ts, 42, 28)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) + +declare function pipe4(funcs: [(a: A) => B, (b: B) => C]): (a: A) => C; +>pipe4 : Symbol(pipe4, Decl(genericFunctionInference1.ts, 48, 30)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 50, 23)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 50, 25)) +>C : Symbol(C, Decl(genericFunctionInference1.ts, 50, 28)) +>funcs : Symbol(funcs, Decl(genericFunctionInference1.ts, 50, 32)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 50, 41)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 50, 23)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 50, 25)) +>b : Symbol(b, Decl(genericFunctionInference1.ts, 50, 54)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 50, 25)) +>C : Symbol(C, Decl(genericFunctionInference1.ts, 50, 28)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 50, 69)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 50, 23)) +>C : Symbol(C, Decl(genericFunctionInference1.ts, 50, 28)) + +const f40 = pipe4([list, box]); +>f40 : Symbol(f40, Decl(genericFunctionInference1.ts, 52, 5)) +>pipe4 : Symbol(pipe4, Decl(genericFunctionInference1.ts, 48, 30)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) + +const f41 = pipe4([box, list]); +>f41 : Symbol(f41, Decl(genericFunctionInference1.ts, 53, 5)) +>pipe4 : Symbol(pipe4, Decl(genericFunctionInference1.ts, 48, 30)) +>box : Symbol(box, Decl(genericFunctionInference1.ts, 4, 36)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) + +declare function pipe5(f: (a: A) => B): { f: (a: A) => B }; +>pipe5 : Symbol(pipe5, Decl(genericFunctionInference1.ts, 53, 31)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 55, 23)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 55, 25)) +>f : Symbol(f, Decl(genericFunctionInference1.ts, 55, 29)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 55, 33)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 55, 23)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 55, 25)) +>f : Symbol(f, Decl(genericFunctionInference1.ts, 55, 47)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 55, 52)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 55, 23)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 55, 25)) + +const f50 = pipe5(list); // No higher order inference +>f50 : Symbol(f50, Decl(genericFunctionInference1.ts, 57, 5)) +>pipe5 : Symbol(pipe5, Decl(genericFunctionInference1.ts, 53, 31)) +>list : Symbol(list, Decl(genericFunctionInference1.ts, 2, 124)) + +// #417 + +function mirror(f: (a: A) => B): (a: A) => B { return f; } +>mirror : Symbol(mirror, Decl(genericFunctionInference1.ts, 57, 24)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 61, 16)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 61, 18)) +>f : Symbol(f, Decl(genericFunctionInference1.ts, 61, 22)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 61, 26)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 61, 16)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 61, 18)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 61, 40)) +>A : Symbol(A, Decl(genericFunctionInference1.ts, 61, 16)) +>B : Symbol(B, Decl(genericFunctionInference1.ts, 61, 18)) +>f : Symbol(f, Decl(genericFunctionInference1.ts, 61, 22)) + +var identityM = mirror(identity); +>identityM : Symbol(identityM, Decl(genericFunctionInference1.ts, 62, 3)) +>mirror : Symbol(mirror, Decl(genericFunctionInference1.ts, 57, 24)) +>identity : Symbol(identity, Decl(genericFunctionInference1.ts, 154, 13)) + +var x = 1; +>x : Symbol(x, Decl(genericFunctionInference1.ts, 64, 3)) + +var y = identity(x); +>y : Symbol(y, Decl(genericFunctionInference1.ts, 65, 3)) +>identity : Symbol(identity, Decl(genericFunctionInference1.ts, 154, 13)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 64, 3)) + +var z = identityM(x); +>z : Symbol(z, Decl(genericFunctionInference1.ts, 66, 3)) +>identityM : Symbol(identityM, Decl(genericFunctionInference1.ts, 62, 3)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 64, 3)) + +// #3038 + +export function keyOf(value: { key: a; }): a { +>keyOf : Symbol(keyOf, Decl(genericFunctionInference1.ts, 66, 21)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 70, 22)) +>value : Symbol(value, Decl(genericFunctionInference1.ts, 70, 25)) +>key : Symbol(key, Decl(genericFunctionInference1.ts, 70, 33)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 70, 22)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 70, 22)) + + return value.key; +>value.key : Symbol(key, Decl(genericFunctionInference1.ts, 70, 33)) +>value : Symbol(value, Decl(genericFunctionInference1.ts, 70, 25)) +>key : Symbol(key, Decl(genericFunctionInference1.ts, 70, 33)) +} +export interface Data { +>Data : Symbol(Data, Decl(genericFunctionInference1.ts, 72, 1)) + + key: number; +>key : Symbol(Data.key, Decl(genericFunctionInference1.ts, 73, 23)) + + value: Date; +>value : Symbol(Data.value, Decl(genericFunctionInference1.ts, 74, 16)) +>Date : Symbol(Date, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.scripthost.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +} + +var data: Data[] = []; +>data : Symbol(data, Decl(genericFunctionInference1.ts, 78, 3)) +>Data : Symbol(Data, Decl(genericFunctionInference1.ts, 72, 1)) + +declare function toKeys(values: a[], toKey: (value: a) => string): string[]; +>toKeys : Symbol(toKeys, Decl(genericFunctionInference1.ts, 78, 22)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 80, 24)) +>values : Symbol(values, Decl(genericFunctionInference1.ts, 80, 27)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 80, 24)) +>toKey : Symbol(toKey, Decl(genericFunctionInference1.ts, 80, 39)) +>value : Symbol(value, Decl(genericFunctionInference1.ts, 80, 48)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 80, 24)) + +toKeys(data, keyOf); // Error +>toKeys : Symbol(toKeys, Decl(genericFunctionInference1.ts, 78, 22)) +>data : Symbol(data, Decl(genericFunctionInference1.ts, 78, 3)) +>keyOf : Symbol(keyOf, Decl(genericFunctionInference1.ts, 66, 21)) + +// #9366 + +function flip(f: (a: a, b: b) => c): (b: b, a: a) => c { +>flip : Symbol(flip, Decl(genericFunctionInference1.ts, 82, 20)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 86, 14)) +>b : Symbol(b, Decl(genericFunctionInference1.ts, 86, 16)) +>c : Symbol(c, Decl(genericFunctionInference1.ts, 86, 19)) +>f : Symbol(f, Decl(genericFunctionInference1.ts, 86, 23)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 86, 27)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 86, 14)) +>b : Symbol(b, Decl(genericFunctionInference1.ts, 86, 32)) +>b : Symbol(b, Decl(genericFunctionInference1.ts, 86, 16)) +>c : Symbol(c, Decl(genericFunctionInference1.ts, 86, 19)) +>b : Symbol(b, Decl(genericFunctionInference1.ts, 86, 47)) +>b : Symbol(b, Decl(genericFunctionInference1.ts, 86, 16)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 86, 52)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 86, 14)) +>c : Symbol(c, Decl(genericFunctionInference1.ts, 86, 19)) + + return (b: b, a: a) => f(a, b); +>b : Symbol(b, Decl(genericFunctionInference1.ts, 87, 10)) +>b : Symbol(b, Decl(genericFunctionInference1.ts, 86, 16)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 87, 15)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 86, 14)) +>f : Symbol(f, Decl(genericFunctionInference1.ts, 86, 23)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 87, 15)) +>b : Symbol(b, Decl(genericFunctionInference1.ts, 87, 10)) +} +function zip(x: T, y: U): [T, U] { +>zip : Symbol(zip, Decl(genericFunctionInference1.ts, 88, 1)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 89, 13)) +>U : Symbol(U, Decl(genericFunctionInference1.ts, 89, 15)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 89, 19)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 89, 13)) +>y : Symbol(y, Decl(genericFunctionInference1.ts, 89, 24)) +>U : Symbol(U, Decl(genericFunctionInference1.ts, 89, 15)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 89, 13)) +>U : Symbol(U, Decl(genericFunctionInference1.ts, 89, 15)) + + return [x, y]; +>x : Symbol(x, Decl(genericFunctionInference1.ts, 89, 19)) +>y : Symbol(y, Decl(genericFunctionInference1.ts, 89, 24)) +} + +var expected: (y: U, x: T) => [T, U] = flip(zip); +>expected : Symbol(expected, Decl(genericFunctionInference1.ts, 93, 3)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 93, 15)) +>U : Symbol(U, Decl(genericFunctionInference1.ts, 93, 17)) +>y : Symbol(y, Decl(genericFunctionInference1.ts, 93, 21)) +>U : Symbol(U, Decl(genericFunctionInference1.ts, 93, 17)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 93, 26)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 93, 15)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 93, 15)) +>U : Symbol(U, Decl(genericFunctionInference1.ts, 93, 17)) +>flip : Symbol(flip, Decl(genericFunctionInference1.ts, 82, 20)) +>zip : Symbol(zip, Decl(genericFunctionInference1.ts, 88, 1)) + +var actual = flip(zip); +>actual : Symbol(actual, Decl(genericFunctionInference1.ts, 94, 3)) +>flip : Symbol(flip, Decl(genericFunctionInference1.ts, 82, 20)) +>zip : Symbol(zip, Decl(genericFunctionInference1.ts, 88, 1)) + +// #9366 + +const map = (transform: (t: T) => U) => +>map : Symbol(map, Decl(genericFunctionInference1.ts, 98, 5)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 98, 13)) +>U : Symbol(U, Decl(genericFunctionInference1.ts, 98, 15)) +>transform : Symbol(transform, Decl(genericFunctionInference1.ts, 98, 19)) +>t : Symbol(t, Decl(genericFunctionInference1.ts, 98, 31)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 98, 13)) +>U : Symbol(U, Decl(genericFunctionInference1.ts, 98, 15)) + + (arr: T[]) => arr.map(transform) +>arr : Symbol(arr, Decl(genericFunctionInference1.ts, 99, 5)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 98, 13)) +>arr.map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) +>arr : Symbol(arr, Decl(genericFunctionInference1.ts, 99, 5)) +>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) +>transform : Symbol(transform, Decl(genericFunctionInference1.ts, 98, 19)) + +const identityStr = (t: string) => t; +>identityStr : Symbol(identityStr, Decl(genericFunctionInference1.ts, 101, 5)) +>t : Symbol(t, Decl(genericFunctionInference1.ts, 101, 21)) +>t : Symbol(t, Decl(genericFunctionInference1.ts, 101, 21)) + +const arr: string[] = map(identityStr)(['a']); +>arr : Symbol(arr, Decl(genericFunctionInference1.ts, 103, 5)) +>map : Symbol(map, Decl(genericFunctionInference1.ts, 98, 5)) +>identityStr : Symbol(identityStr, Decl(genericFunctionInference1.ts, 101, 5)) + +const arr1: string[] = map(identity)(['a']); +>arr1 : Symbol(arr1, Decl(genericFunctionInference1.ts, 104, 5)) +>map : Symbol(map, Decl(genericFunctionInference1.ts, 98, 5)) +>identity : Symbol(identity, Decl(genericFunctionInference1.ts, 154, 13)) + +// #9949 + +function of2(one: a, two: b): [a, b] { +>of2 : Symbol(of2, Decl(genericFunctionInference1.ts, 104, 44)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 108, 13)) +>b : Symbol(b, Decl(genericFunctionInference1.ts, 108, 15)) +>one : Symbol(one, Decl(genericFunctionInference1.ts, 108, 19)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 108, 13)) +>two : Symbol(two, Decl(genericFunctionInference1.ts, 108, 26)) +>b : Symbol(b, Decl(genericFunctionInference1.ts, 108, 15)) +>a : Symbol(a, Decl(genericFunctionInference1.ts, 108, 13)) +>b : Symbol(b, Decl(genericFunctionInference1.ts, 108, 15)) + + return [one, two]; +>one : Symbol(one, Decl(genericFunctionInference1.ts, 108, 19)) +>two : Symbol(two, Decl(genericFunctionInference1.ts, 108, 26)) +} + +const flipped = flip(of2); +>flipped : Symbol(flipped, Decl(genericFunctionInference1.ts, 112, 5)) +>flip : Symbol(flip, Decl(genericFunctionInference1.ts, 82, 20)) +>of2 : Symbol(of2, Decl(genericFunctionInference1.ts, 104, 44)) + +// #29904.1 + +type Component

= (props: P) => {}; +>Component : Symbol(Component, Decl(genericFunctionInference1.ts, 112, 26)) +>P : Symbol(P, Decl(genericFunctionInference1.ts, 116, 15)) +>props : Symbol(props, Decl(genericFunctionInference1.ts, 116, 21)) +>P : Symbol(P, Decl(genericFunctionInference1.ts, 116, 15)) + +declare const myHoc1:

(C: Component

) => Component

; +>myHoc1 : Symbol(myHoc1, Decl(genericFunctionInference1.ts, 118, 13)) +>P : Symbol(P, Decl(genericFunctionInference1.ts, 118, 23)) +>C : Symbol(C, Decl(genericFunctionInference1.ts, 118, 26)) +>Component : Symbol(Component, Decl(genericFunctionInference1.ts, 112, 26)) +>P : Symbol(P, Decl(genericFunctionInference1.ts, 118, 23)) +>Component : Symbol(Component, Decl(genericFunctionInference1.ts, 112, 26)) +>P : Symbol(P, Decl(genericFunctionInference1.ts, 118, 23)) + +declare const myHoc2:

(C: Component

) => Component

; +>myHoc2 : Symbol(myHoc2, Decl(genericFunctionInference1.ts, 119, 13)) +>P : Symbol(P, Decl(genericFunctionInference1.ts, 119, 23)) +>C : Symbol(C, Decl(genericFunctionInference1.ts, 119, 26)) +>Component : Symbol(Component, Decl(genericFunctionInference1.ts, 112, 26)) +>P : Symbol(P, Decl(genericFunctionInference1.ts, 119, 23)) +>Component : Symbol(Component, Decl(genericFunctionInference1.ts, 112, 26)) +>P : Symbol(P, Decl(genericFunctionInference1.ts, 119, 23)) + +declare const MyComponent1: Component<{ foo: 1 }>; +>MyComponent1 : Symbol(MyComponent1, Decl(genericFunctionInference1.ts, 121, 13)) +>Component : Symbol(Component, Decl(genericFunctionInference1.ts, 112, 26)) +>foo : Symbol(foo, Decl(genericFunctionInference1.ts, 121, 39)) + +const enhance = pipe( +>enhance : Symbol(enhance, Decl(genericFunctionInference1.ts, 123, 5)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) + + myHoc1, +>myHoc1 : Symbol(myHoc1, Decl(genericFunctionInference1.ts, 118, 13)) + + myHoc2, +>myHoc2 : Symbol(myHoc2, Decl(genericFunctionInference1.ts, 119, 13)) + +); + +const MyComponent2 = enhance(MyComponent1); +>MyComponent2 : Symbol(MyComponent2, Decl(genericFunctionInference1.ts, 128, 5)) +>enhance : Symbol(enhance, Decl(genericFunctionInference1.ts, 123, 5)) +>MyComponent1 : Symbol(MyComponent1, Decl(genericFunctionInference1.ts, 121, 13)) + +// #29904.2 + +const fn20 = pipe((_a?: {}) => 1); +>fn20 : Symbol(fn20, Decl(genericFunctionInference1.ts, 132, 5)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) +>_a : Symbol(_a, Decl(genericFunctionInference1.ts, 132, 19)) + +// #29904.3 + +type Fn = (n: number) => number; +>Fn : Symbol(Fn, Decl(genericFunctionInference1.ts, 132, 34)) +>n : Symbol(n, Decl(genericFunctionInference1.ts, 136, 11)) + +const fn30: Fn = pipe( +>fn30 : Symbol(fn30, Decl(genericFunctionInference1.ts, 137, 5)) +>Fn : Symbol(Fn, Decl(genericFunctionInference1.ts, 132, 34)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) + + x => x + 1, +>x : Symbol(x, Decl(genericFunctionInference1.ts, 137, 22)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 137, 22)) + + x => x * 2, +>x : Symbol(x, Decl(genericFunctionInference1.ts, 138, 15)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 138, 15)) + +); + +const promise = Promise.resolve(1); +>promise : Symbol(promise, Decl(genericFunctionInference1.ts, 142, 5)) +>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) + +promise.then( +>promise.then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --)) +>promise : Symbol(promise, Decl(genericFunctionInference1.ts, 142, 5)) +>then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --)) + + pipe( +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) + + x => x + 1, +>x : Symbol(x, Decl(genericFunctionInference1.ts, 144, 9)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 144, 9)) + + x => x * 2, +>x : Symbol(x, Decl(genericFunctionInference1.ts, 145, 19)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 145, 19)) + + ), +); + +// #29904.4 + +declare const getString: () => string; +>getString : Symbol(getString, Decl(genericFunctionInference1.ts, 152, 13)) + +declare const orUndefined: (name: string) => string | undefined; +>orUndefined : Symbol(orUndefined, Decl(genericFunctionInference1.ts, 153, 13)) +>name : Symbol(name, Decl(genericFunctionInference1.ts, 153, 28)) + +declare const identity: (value: T) => T; +>identity : Symbol(identity, Decl(genericFunctionInference1.ts, 154, 13)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 154, 25)) +>value : Symbol(value, Decl(genericFunctionInference1.ts, 154, 28)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 154, 25)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 154, 25)) + +const fn40 = pipe( +>fn40 : Symbol(fn40, Decl(genericFunctionInference1.ts, 156, 5)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) + + getString, +>getString : Symbol(getString, Decl(genericFunctionInference1.ts, 152, 13)) + + string => orUndefined(string), +>string : Symbol(string, Decl(genericFunctionInference1.ts, 157, 14)) +>orUndefined : Symbol(orUndefined, Decl(genericFunctionInference1.ts, 153, 13)) +>string : Symbol(string, Decl(genericFunctionInference1.ts, 157, 14)) + + identity, +>identity : Symbol(identity, Decl(genericFunctionInference1.ts, 154, 13)) + +); + +// #29904.6 + +declare const getArray: () => string[]; +>getArray : Symbol(getArray, Decl(genericFunctionInference1.ts, 164, 13)) + +declare const first: (ts: T[]) => T; +>first : Symbol(first, Decl(genericFunctionInference1.ts, 165, 13)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 165, 22)) +>ts : Symbol(ts, Decl(genericFunctionInference1.ts, 165, 25)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 165, 22)) +>T : Symbol(T, Decl(genericFunctionInference1.ts, 165, 22)) + +const fn60 = pipe( +>fn60 : Symbol(fn60, Decl(genericFunctionInference1.ts, 167, 5)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) + + getArray, +>getArray : Symbol(getArray, Decl(genericFunctionInference1.ts, 164, 13)) + + x => x, +>x : Symbol(x, Decl(genericFunctionInference1.ts, 168, 13)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 168, 13)) + + first, +>first : Symbol(first, Decl(genericFunctionInference1.ts, 165, 13)) + +); + +const fn61 = pipe( +>fn61 : Symbol(fn61, Decl(genericFunctionInference1.ts, 173, 5)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) + + getArray, +>getArray : Symbol(getArray, Decl(genericFunctionInference1.ts, 164, 13)) + + identity, +>identity : Symbol(identity, Decl(genericFunctionInference1.ts, 154, 13)) + + first, +>first : Symbol(first, Decl(genericFunctionInference1.ts, 165, 13)) + +); + +const fn62 = pipe( +>fn62 : Symbol(fn62, Decl(genericFunctionInference1.ts, 179, 5)) +>pipe : Symbol(pipe, Decl(genericFunctionInference1.ts, 0, 0), Decl(genericFunctionInference1.ts, 0, 84), Decl(genericFunctionInference1.ts, 1, 104)) + + getArray, +>getArray : Symbol(getArray, Decl(genericFunctionInference1.ts, 164, 13)) + + x => x, +>x : Symbol(x, Decl(genericFunctionInference1.ts, 180, 13)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 180, 13)) + + x => first(x), +>x : Symbol(x, Decl(genericFunctionInference1.ts, 181, 11)) +>first : Symbol(first, Decl(genericFunctionInference1.ts, 165, 13)) +>x : Symbol(x, Decl(genericFunctionInference1.ts, 181, 11)) + +); + diff --git a/tests/baselines/reference/genericFunctionInference1.types b/tests/baselines/reference/genericFunctionInference1.types new file mode 100644 index 00000000000..e68b0ed6da0 --- /dev/null +++ b/tests/baselines/reference/genericFunctionInference1.types @@ -0,0 +1,801 @@ +=== tests/cases/compiler/genericFunctionInference1.ts === +declare function pipe(ab: (...args: A) => B): (...args: A) => B; +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>ab : (...args: A) => B +>args : A +>args : A + +declare function pipe(ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>ab : (...args: A) => B +>args : A +>bc : (b: B) => C +>b : B +>args : A + +declare function pipe(ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>ab : (...args: A) => B +>args : A +>bc : (b: B) => C +>b : B +>cd : (c: C) => D +>c : C +>args : A + +declare function list(a: T): T[]; +>list : (a: T) => T[] +>a : T + +declare function box(x: V): { value: V }; +>box : (x: V) => { value: V; } +>x : V +>value : V + +declare function foo(x: T): T; +>foo : (x: T) => T +>value : T +>x : T + +const f00 = pipe(list); +>f00 : (a: T) => T[] +>pipe(list) : (a: T) => T[] +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>list : (a: T) => T[] + +const f01 = pipe(list, box); +>f01 : (a: T) => { value: T[]; } +>pipe(list, box) : (a: T) => { value: T[]; } +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>list : (a: T) => T[] +>box : (x: V) => { value: V; } + +const f02 = pipe(box, list); +>f02 : (x: V) => { value: V; }[] +>pipe(box, list) : (x: V) => { value: V; }[] +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>box : (x: V) => { value: V; } +>list : (a: T) => T[] + +const f03 = pipe(x => list(x), box); +>f03 : (x: any) => { value: any[]; } +>pipe(x => list(x), box) : (x: any) => { value: any[]; } +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>x => list(x) : (x: any) => any[] +>x : any +>list(x) : any[] +>list : (a: T) => T[] +>x : any +>box : (x: V) => { value: V; } + +const f04 = pipe(list, x => box(x)); +>f04 : (a: T) => { value: T[]; } +>pipe(list, x => box(x)) : (a: T) => { value: T[]; } +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>list : (a: T) => T[] +>x => box(x) : (x: T[]) => { value: T[]; } +>x : T[] +>box(x) : { value: T[]; } +>box : (x: V) => { value: V; } +>x : T[] + +const f05 = pipe(x => list(x), x => box(x)) +>f05 : (x: any) => { value: any[]; } +>pipe(x => list(x), x => box(x)) : (x: any) => { value: any[]; } +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>x => list(x) : (x: any) => any[] +>x : any +>list(x) : any[] +>list : (a: T) => T[] +>x : any +>x => box(x) : (x: any[]) => { value: any[]; } +>x : any[] +>box(x) : { value: any[]; } +>box : (x: V) => { value: V; } +>x : any[] + +const f06 = pipe(list, pipe(box)); +>f06 : (a: T) => { value: T[]; } +>pipe(list, pipe(box)) : (a: T) => { value: T[]; } +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>list : (a: T) => T[] +>pipe(box) : (x: T[]) => { value: T[]; } +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>box : (x: V) => { value: V; } + +const f07 = pipe(x => list(x), pipe(box)); +>f07 : (x: any) => { value: any[]; } +>pipe(x => list(x), pipe(box)) : (x: any) => { value: any[]; } +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>x => list(x) : (x: any) => any[] +>x : any +>list(x) : any[] +>list : (a: T) => T[] +>x : any +>pipe(box) : (x: any[]) => { value: any[]; } +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>box : (x: V) => { value: V; } + +const f08 = pipe(x => list(x), pipe(x => box(x))); +>f08 : (x: any) => { value: any[]; } +>pipe(x => list(x), pipe(x => box(x))) : (x: any) => { value: any[]; } +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>x => list(x) : (x: any) => any[] +>x : any +>list(x) : any[] +>list : (a: T) => T[] +>x : any +>pipe(x => box(x)) : (x: any[]) => { value: any[]; } +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>x => box(x) : (x: any[]) => { value: any[]; } +>x : any[] +>box(x) : { value: any[]; } +>box : (x: V) => { value: V; } +>x : any[] + +const f09 = pipe(list, x => x.length); +>f09 : (a: T) => number +>pipe(list, x => x.length) : (a: T) => number +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>list : (a: T) => T[] +>x => x.length : (x: T[]) => number +>x : T[] +>x.length : number +>x : T[] +>length : number + +const f10 = pipe(foo); +>f10 : (x: T) => T +>pipe(foo) : (x: T) => T +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>foo : (x: T) => T + +const f11 = pipe(foo, foo); +>f11 : (x: T) => T +>pipe(foo, foo) : (x: T) => T +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>foo : (x: T) => T +>foo : (x: T) => T + +const g00: (x: T) => T[] = pipe(list); +>g00 : (x: T) => T[] +>x : T +>pipe(list) : (a: T) => T[] +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>list : (a: T) => T[] + +const g01: (x: T) => { value: T[] } = pipe(list, box); +>g01 : (x: T) => { value: T[]; } +>x : T +>value : T[] +>pipe(list, box) : (a: T) => { value: T[]; } +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>list : (a: T) => T[] +>box : (x: V) => { value: V; } + +const g02: (x: T) => { value: T }[] = pipe(box, list); +>g02 : (x: T) => { value: T; }[] +>x : T +>value : T +>pipe(box, list) : (x: T) => { value: T; }[] +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>box : (x: V) => { value: V; } +>list : (a: T) => T[] + +const g03: (x: T) => { value: T[] } = pipe(x => list(x), box); +>g03 : (x: T) => { value: T[]; } +>x : T +>value : T[] +>pipe(x => list(x), box) : (x: T) => { value: T[]; } +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>x => list(x) : (x: T) => T[] +>x : T +>list(x) : T[] +>list : (a: T) => T[] +>x : T +>box : (x: V) => { value: V; } + +const g04: (x: T) => { value: T[] } = pipe(list, x => box(x)); +>g04 : (x: T) => { value: T[]; } +>x : T +>value : T[] +>pipe(list, x => box(x)) : (a: T) => { value: T[]; } +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>list : (a: T) => T[] +>x => box(x) : (x: T[]) => { value: T[]; } +>x : T[] +>box(x) : { value: T[]; } +>box : (x: V) => { value: V; } +>x : T[] + +const g05: (x: T) => { value: T[] } = pipe(x => list(x), x => box(x)) +>g05 : (x: T) => { value: T[]; } +>x : T +>value : T[] +>pipe(x => list(x), x => box(x)) : (x: T) => { value: T[]; } +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>x => list(x) : (x: T) => T[] +>x : T +>list(x) : T[] +>list : (a: T) => T[] +>x : T +>x => box(x) : (x: T[]) => { value: T[]; } +>x : T[] +>box(x) : { value: T[]; } +>box : (x: V) => { value: V; } +>x : T[] + +const g06: (x: T) => { value: T[] } = pipe(list, pipe(box)); +>g06 : (x: T) => { value: T[]; } +>x : T +>value : T[] +>pipe(list, pipe(box)) : (a: T) => { value: T[]; } +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>list : (a: T) => T[] +>pipe(box) : (x: T[]) => { value: T[]; } +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>box : (x: V) => { value: V; } + +const g07: (x: T) => { value: T[] } = pipe(x => list(x), pipe(box)); +>g07 : (x: T) => { value: T[]; } +>x : T +>value : T[] +>pipe(x => list(x), pipe(box)) : (x: T) => { value: T[]; } +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>x => list(x) : (x: T) => T[] +>x : T +>list(x) : T[] +>list : (a: T) => T[] +>x : T +>pipe(box) : (x: T[]) => { value: T[]; } +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>box : (x: V) => { value: V; } + +const g08: (x: T) => { value: T[] } = pipe(x => list(x), pipe(x => box(x))); +>g08 : (x: T) => { value: T[]; } +>x : T +>value : T[] +>pipe(x => list(x), pipe(x => box(x))) : (x: T) => { value: T[]; } +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>x => list(x) : (x: T) => T[] +>x : T +>list(x) : T[] +>list : (a: T) => T[] +>x : T +>pipe(x => box(x)) : (x: T[]) => { value: T[]; } +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>x => box(x) : (x: T[]) => { value: T[]; } +>x : T[] +>box(x) : { value: T[]; } +>box : (x: V) => { value: V; } +>x : T[] + +const g09: (x: T) => number = pipe(list, x => x.length); +>g09 : (x: T) => number +>x : T +>pipe(list, x => x.length) : (a: T) => number +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>list : (a: T) => T[] +>x => x.length : (x: T[]) => number +>x : T[] +>x.length : number +>x : T[] +>length : number + +const g10: (x: T) => T = pipe(foo); +>g10 : (x: T) => T +>value : T +>x : T +>pipe(foo) : (x: T) => T +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>foo : (x: T) => T + +const g12: (x: T) => T = pipe(foo, foo); +>g12 : (x: T) => T +>value : T +>x : T +>pipe(foo, foo) : (x: T) => T +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>foo : (x: T) => T +>foo : (x: T) => T + +declare function pipe2(ab: (a: A) => B, cd: (c: C) => D): (a: [A, C]) => [B, D]; +>pipe2 : (ab: (a: A) => B, cd: (c: C) => D) => (a: [A, C]) => [B, D] +>ab : (a: A) => B +>a : A +>cd : (c: C) => D +>c : C +>a : [A, C] + +const f20 = pipe2(list, box); +>f20 : (a: [T, V]) => [T[], { value: V; }] +>pipe2(list, box) : (a: [T, V]) => [T[], { value: V; }] +>pipe2 : (ab: (a: A) => B, cd: (c: C) => D) => (a: [A, C]) => [B, D] +>list : (a: T) => T[] +>box : (x: V) => { value: V; } + +const f21 = pipe2(box, list); +>f21 : (a: [V, T]) => [{ value: V; }, T[]] +>pipe2(box, list) : (a: [V, T]) => [{ value: V; }, T[]] +>pipe2 : (ab: (a: A) => B, cd: (c: C) => D) => (a: [A, C]) => [B, D] +>box : (x: V) => { value: V; } +>list : (a: T) => T[] + +const f22 = pipe2(list, list); +>f22 : (a: [T, T1]) => [T[], T1[]] +>pipe2(list, list) : (a: [T, T1]) => [T[], T1[]] +>pipe2 : (ab: (a: A) => B, cd: (c: C) => D) => (a: [A, C]) => [B, D] +>list : (a: T) => T[] +>list : (a: T) => T[] + +const f23 = pipe2(box, box); +>f23 : (a: [V, V1]) => [{ value: V; }, { value: V1; }] +>pipe2(box, box) : (a: [V, V1]) => [{ value: V; }, { value: V1; }] +>pipe2 : (ab: (a: A) => B, cd: (c: C) => D) => (a: [A, C]) => [B, D] +>box : (x: V) => { value: V; } +>box : (x: V) => { value: V; } + +const f24 = pipe2(f20, f20); +>f24 : (a: [[T, V], [T1, V1]]) => [[T[], { value: V; }], [T1[], { value: V1; }]] +>pipe2(f20, f20) : (a: [[T, V], [T1, V1]]) => [[T[], { value: V; }], [T1[], { value: V1; }]] +>pipe2 : (ab: (a: A) => B, cd: (c: C) => D) => (a: [A, C]) => [B, D] +>f20 : (a: [T, V]) => [T[], { value: V; }] +>f20 : (a: [T, V]) => [T[], { value: V; }] + +const f25 = pipe2(foo, foo); +>f25 : (a: [T, T1]) => [T, T1] +>pipe2(foo, foo) : (a: [T, T1]) => [T, T1] +>pipe2 : (ab: (a: A) => B, cd: (c: C) => D) => (a: [A, C]) => [B, D] +>foo : (x: T) => T +>foo : (x: T) => T + +const f26 = pipe2(f25, f25); +>f26 : (a: [[T, T1], [T2, T3]]) => [[T, T1], [T2, T3]] +>pipe2(f25, f25) : (a: [[T, T1], [T2, T3]]) => [[T, T1], [T2, T3]] +>pipe2 : (ab: (a: A) => B, cd: (c: C) => D) => (a: [A, C]) => [B, D] +>f25 : (a: [T, T1]) => [T, T1] +>f25 : (a: [T, T1]) => [T, T1] + +declare function pipe3(ab: (a: A) => B, ac: (a: A) => C): (a: A) => [B, C]; +>pipe3 : (ab: (a: A) => B, ac: (a: A) => C) => (a: A) => [B, C] +>ab : (a: A) => B +>a : A +>ac : (a: A) => C +>a : A +>a : A + +const f30 = pipe3(list, box); +>f30 : (a: T) => [T[], { value: T; }] +>pipe3(list, box) : (a: T) => [T[], { value: T; }] +>pipe3 : (ab: (a: A) => B, ac: (a: A) => C) => (a: A) => [B, C] +>list : (a: T) => T[] +>box : (x: V) => { value: V; } + +const f31 = pipe3(box, list); +>f31 : (a: V) => [{ value: V; }, V[]] +>pipe3(box, list) : (a: V) => [{ value: V; }, V[]] +>pipe3 : (ab: (a: A) => B, ac: (a: A) => C) => (a: A) => [B, C] +>box : (x: V) => { value: V; } +>list : (a: T) => T[] + +const f32 = pipe3(list, list); +>f32 : (a: T) => [T[], T[]] +>pipe3(list, list) : (a: T) => [T[], T[]] +>pipe3 : (ab: (a: A) => B, ac: (a: A) => C) => (a: A) => [B, C] +>list : (a: T) => T[] +>list : (a: T) => T[] + +declare function pipe4(funcs: [(a: A) => B, (b: B) => C]): (a: A) => C; +>pipe4 : (funcs: [(a: A) => B, (b: B) => C]) => (a: A) => C +>funcs : [(a: A) => B, (b: B) => C] +>a : A +>b : B +>a : A + +const f40 = pipe4([list, box]); +>f40 : (a: T) => { value: T[]; } +>pipe4([list, box]) : (a: T) => { value: T[]; } +>pipe4 : (funcs: [(a: A) => B, (b: B) => C]) => (a: A) => C +>[list, box] : [(a: T) => T[], (x: V) => { value: V; }] +>list : (a: T) => T[] +>box : (x: V) => { value: V; } + +const f41 = pipe4([box, list]); +>f41 : (a: V) => { value: V; }[] +>pipe4([box, list]) : (a: V) => { value: V; }[] +>pipe4 : (funcs: [(a: A) => B, (b: B) => C]) => (a: A) => C +>[box, list] : [(x: V) => { value: V; }, (a: T) => T[]] +>box : (x: V) => { value: V; } +>list : (a: T) => T[] + +declare function pipe5(f: (a: A) => B): { f: (a: A) => B }; +>pipe5 : (f: (a: A) => B) => { f: (a: A) => B; } +>f : (a: A) => B +>a : A +>f : (a: A) => B +>a : A + +const f50 = pipe5(list); // No higher order inference +>f50 : { f: (a: {}) => {}[]; } +>pipe5(list) : { f: (a: {}) => {}[]; } +>pipe5 : (f: (a: A) => B) => { f: (a: A) => B; } +>list : (a: T) => T[] + +// #417 + +function mirror(f: (a: A) => B): (a: A) => B { return f; } +>mirror : (f: (a: A) => B) => (a: A) => B +>f : (a: A) => B +>a : A +>a : A +>f : (a: A) => B + +var identityM = mirror(identity); +>identityM : (a: T) => T +>mirror(identity) : (a: T) => T +>mirror : (f: (a: A) => B) => (a: A) => B +>identity : (value: T) => T + +var x = 1; +>x : number +>1 : 1 + +var y = identity(x); +>y : number +>identity(x) : number +>identity : (value: T) => T +>x : number + +var z = identityM(x); +>z : number +>identityM(x) : number +>identityM : (a: T) => T +>x : number + +// #3038 + +export function keyOf(value: { key: a; }): a { +>keyOf : (value: { key: a; }) => a +>value : { key: a; } +>key : a + + return value.key; +>value.key : a +>value : { key: a; } +>key : a +} +export interface Data { + key: number; +>key : number + + value: Date; +>value : Date +} + +var data: Data[] = []; +>data : Data[] +>[] : never[] + +declare function toKeys(values: a[], toKey: (value: a) => string): string[]; +>toKeys : (values: a[], toKey: (value: a) => string) => string[] +>values : a[] +>toKey : (value: a) => string +>value : a + +toKeys(data, keyOf); // Error +>toKeys(data, keyOf) : any +>toKeys : (values: a[], toKey: (value: a) => string) => string[] +>data : Data[] +>keyOf : (value: { key: a; }) => a + +// #9366 + +function flip(f: (a: a, b: b) => c): (b: b, a: a) => c { +>flip : (f: (a: a, b: b) => c) => (b: b, a: a) => c +>f : (a: a, b: b) => c +>a : a +>b : b +>b : b +>a : a + + return (b: b, a: a) => f(a, b); +>(b: b, a: a) => f(a, b) : (b: b, a: a) => c +>b : b +>a : a +>f(a, b) : c +>f : (a: a, b: b) => c +>a : a +>b : b +} +function zip(x: T, y: U): [T, U] { +>zip : (x: T, y: U) => [T, U] +>x : T +>y : U + + return [x, y]; +>[x, y] : [T, U] +>x : T +>y : U +} + +var expected: (y: U, x: T) => [T, U] = flip(zip); +>expected : (y: U, x: T) => [T, U] +>y : U +>x : T +>flip(zip) : (b: U, a: T) => [T, U] +>flip : (f: (a: a, b: b) => c) => (b: b, a: a) => c +>zip : (x: T, y: U) => [T, U] + +var actual = flip(zip); +>actual : (b: U, a: T) => [T, U] +>flip(zip) : (b: U, a: T) => [T, U] +>flip : (f: (a: a, b: b) => c) => (b: b, a: a) => c +>zip : (x: T, y: U) => [T, U] + +// #9366 + +const map = (transform: (t: T) => U) => +>map : (transform: (t: T) => U) => (arr: T[]) => U[] +>(transform: (t: T) => U) => (arr: T[]) => arr.map(transform) : (transform: (t: T) => U) => (arr: T[]) => U[] +>transform : (t: T) => U +>t : T + + (arr: T[]) => arr.map(transform) +>(arr: T[]) => arr.map(transform) : (arr: T[]) => U[] +>arr : T[] +>arr.map(transform) : U[] +>arr.map : (callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any) => U[] +>arr : T[] +>map : (callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any) => U[] +>transform : (t: T) => U + +const identityStr = (t: string) => t; +>identityStr : (t: string) => string +>(t: string) => t : (t: string) => string +>t : string +>t : string + +const arr: string[] = map(identityStr)(['a']); +>arr : string[] +>map(identityStr)(['a']) : string[] +>map(identityStr) : (arr: string[]) => string[] +>map : (transform: (t: T) => U) => (arr: T[]) => U[] +>identityStr : (t: string) => string +>['a'] : string[] +>'a' : "a" + +const arr1: string[] = map(identity)(['a']); +>arr1 : string[] +>map(identity)(['a']) : string[] +>map(identity) : (arr: T[]) => T[] +>map : (transform: (t: T) => U) => (arr: T[]) => U[] +>identity : (value: T) => T +>['a'] : string[] +>'a' : "a" + +// #9949 + +function of2(one: a, two: b): [a, b] { +>of2 : (one: a, two: b) => [a, b] +>one : a +>two : b + + return [one, two]; +>[one, two] : [a, b] +>one : a +>two : b +} + +const flipped = flip(of2); +>flipped : (b: b, a: a) => [a, b] +>flip(of2) : (b: b, a: a) => [a, b] +>flip : (f: (a: a, b: b) => c) => (b: b, a: a) => c +>of2 : (one: a, two: b) => [a, b] + +// #29904.1 + +type Component

= (props: P) => {}; +>Component : Component

+>props : P + +declare const myHoc1:

(C: Component

) => Component

; +>myHoc1 :

(C: Component

) => Component

+>C : Component

+ +declare const myHoc2:

(C: Component

) => Component

; +>myHoc2 :

(C: Component

) => Component

+>C : Component

+ +declare const MyComponent1: Component<{ foo: 1 }>; +>MyComponent1 : Component<{ foo: 1; }> +>foo : 1 + +const enhance = pipe( +>enhance :

(C: Component

) => Component

+>pipe( myHoc1, myHoc2,) :

(C: Component

) => Component

+>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } + + myHoc1, +>myHoc1 :

(C: Component

) => Component

+ + myHoc2, +>myHoc2 :

(C: Component

) => Component

+ +); + +const MyComponent2 = enhance(MyComponent1); +>MyComponent2 : Component<{ foo: 1; }> +>enhance(MyComponent1) : Component<{ foo: 1; }> +>enhance :

(C: Component

) => Component

+>MyComponent1 : Component<{ foo: 1; }> + +// #29904.2 + +const fn20 = pipe((_a?: {}) => 1); +>fn20 : (_a?: {} | undefined) => number +>pipe((_a?: {}) => 1) : (_a?: {} | undefined) => number +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } +>(_a?: {}) => 1 : (_a?: {} | undefined) => number +>_a : {} | undefined +>1 : 1 + +// #29904.3 + +type Fn = (n: number) => number; +>Fn : Fn +>n : number + +const fn30: Fn = pipe( +>fn30 : Fn +>pipe( x => x + 1, x => x * 2,) : (x: number) => number +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } + + x => x + 1, +>x => x + 1 : (x: number) => number +>x : number +>x + 1 : number +>x : number +>1 : 1 + + x => x * 2, +>x => x * 2 : (x: number) => number +>x : number +>x * 2 : number +>x : number +>2 : 2 + +); + +const promise = Promise.resolve(1); +>promise : Promise +>Promise.resolve(1) : Promise +>Promise.resolve : { (value: T | PromiseLike): Promise; (): Promise; } +>Promise : PromiseConstructor +>resolve : { (value: T | PromiseLike): Promise; (): Promise; } +>1 : 1 + +promise.then( +>promise.then( pipe( x => x + 1, x => x * 2, ),) : Promise +>promise.then : (onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined) => Promise +>promise : Promise +>then : (onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined) => Promise + + pipe( +>pipe( x => x + 1, x => x * 2, ) : (x: number) => number +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } + + x => x + 1, +>x => x + 1 : (x: number) => number +>x : number +>x + 1 : number +>x : number +>1 : 1 + + x => x * 2, +>x => x * 2 : (x: number) => number +>x : number +>x * 2 : number +>x : number +>2 : 2 + + ), +); + +// #29904.4 + +declare const getString: () => string; +>getString : () => string + +declare const orUndefined: (name: string) => string | undefined; +>orUndefined : (name: string) => string | undefined +>name : string + +declare const identity: (value: T) => T; +>identity : (value: T) => T +>value : T + +const fn40 = pipe( +>fn40 : () => string | undefined +>pipe( getString, string => orUndefined(string), identity,) : () => string | undefined +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } + + getString, +>getString : () => string + + string => orUndefined(string), +>string => orUndefined(string) : (string: string) => string | undefined +>string : string +>orUndefined(string) : string | undefined +>orUndefined : (name: string) => string | undefined +>string : string + + identity, +>identity : (value: T) => T + +); + +// #29904.6 + +declare const getArray: () => string[]; +>getArray : () => string[] + +declare const first: (ts: T[]) => T; +>first : (ts: T[]) => T +>ts : T[] + +const fn60 = pipe( +>fn60 : () => string +>pipe( getArray, x => x, first,) : () => string +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } + + getArray, +>getArray : () => string[] + + x => x, +>x => x : (x: string[]) => string[] +>x : string[] +>x : string[] + + first, +>first : (ts: T[]) => T + +); + +const fn61 = pipe( +>fn61 : () => string +>pipe( getArray, identity, first,) : () => string +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } + + getArray, +>getArray : () => string[] + + identity, +>identity : (value: T) => T + + first, +>first : (ts: T[]) => T + +); + +const fn62 = pipe( +>fn62 : () => string +>pipe( getArray, x => x, x => first(x),) : () => string +>pipe : { (ab: (...args: A) => B): (...args: A) => B; (ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; (ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; } + + getArray, +>getArray : () => string[] + + x => x, +>x => x : (x: string[]) => string[] +>x : string[] +>x : string[] + + x => first(x), +>x => first(x) : (x: string[]) => string +>x : string[] +>first(x) : string +>first : (ts: T[]) => T +>x : string[] + +); + diff --git a/tests/baselines/reference/genericRestParameters1.js b/tests/baselines/reference/genericRestParameters1.js index 3d8703213ac..2932f2b96cb 100644 --- a/tests/baselines/reference/genericRestParameters1.js +++ b/tests/baselines/reference/genericRestParameters1.js @@ -309,7 +309,7 @@ declare function f16(a: A, b: B): A | B; declare let x20: number; declare let x21: string; declare let x22: string | number; -declare let x23: unknown; +declare let x23: string | number; declare let x24: string | number; declare let x30: string; declare let x31: string | number; diff --git a/tests/baselines/reference/genericRestParameters1.types b/tests/baselines/reference/genericRestParameters1.types index 497561c8a98..c9067b38c97 100644 --- a/tests/baselines/reference/genericRestParameters1.types +++ b/tests/baselines/reference/genericRestParameters1.types @@ -462,8 +462,8 @@ let x22 = call(f15, "hello", 42); // string | number >42 : 42 let x23 = call(f16, "hello", 42); // unknown ->x23 : unknown ->call(f16, "hello", 42) : unknown +>x23 : string | number +>call(f16, "hello", 42) : string | number >call : (f: (...args: T) => U, ...args: T) => U >f16 : (a: A, b: B) => A | B >"hello" : "hello" diff --git a/tests/baselines/reference/genericTypeParameterEquivalence2.types b/tests/baselines/reference/genericTypeParameterEquivalence2.types index 1fafa5ad69d..63b9bb774f5 100644 --- a/tests/baselines/reference/genericTypeParameterEquivalence2.types +++ b/tests/baselines/reference/genericTypeParameterEquivalence2.types @@ -129,8 +129,8 @@ function curry1(f: (a: A, b: B) => C): (ax: A) => (bx: B) => C { } var cfilter = curry1(filter); ->cfilter : (ax: {}) => (bx: {}) => {}[] ->curry1(filter) : (ax: {}) => (bx: {}) => {}[] +>cfilter : (ax: (a: A) => boolean) => (bx: A[]) => A[] +>curry1(filter) : (ax: (a: A) => boolean) => (bx: A[]) => A[] >curry1 : (f: (a: A, b: B) => C) => (ax: A) => (bx: B) => C >filter : (f: (a: A) => boolean, ar: A[]) => A[] @@ -149,11 +149,11 @@ function countWhere_1(pred: (a: A) => boolean): (a: A[]) => number { >a : A[] return compose(length2, cfilter(pred)); ->compose(length2, cfilter(pred)) : (a: {}) => number +>compose(length2, cfilter(pred)) : (a: A[]) => number >compose : (f: (b: B) => C, g: (a: A) => B) => (a: A) => C >length2 : (ar: A[]) => number ->cfilter(pred) : (bx: {}) => {}[] ->cfilter : (ax: {}) => (bx: {}) => {}[] +>cfilter(pred) : (bx: A[]) => A[] +>cfilter : (ax: (a: A) => boolean) => (bx: A[]) => A[] >pred : (a: A) => boolean } @@ -164,14 +164,14 @@ function countWhere_2(pred: (a: A) => boolean): (a: A[]) => number { >a : A[] var where = cfilter(pred); ->where : (bx: {}) => {}[] ->cfilter(pred) : (bx: {}) => {}[] ->cfilter : (ax: {}) => (bx: {}) => {}[] +>where : (bx: A[]) => A[] +>cfilter(pred) : (bx: A[]) => A[] +>cfilter : (ax: (a: A) => boolean) => (bx: A[]) => A[] >pred : (a: A) => boolean return compose(length2, where); ->compose(length2, where) : (a: {}) => number +>compose(length2, where) : (a: A[]) => number >compose : (f: (b: B) => C, g: (a: A) => B) => (a: A) => C >length2 : (ar: A[]) => number ->where : (bx: {}) => {}[] +>where : (bx: A[]) => A[] } diff --git a/tests/baselines/reference/noCrashUMDMergedWithGlobalValue.js b/tests/baselines/reference/noCrashUMDMergedWithGlobalValue.js new file mode 100644 index 00000000000..7f8edd9c387 --- /dev/null +++ b/tests/baselines/reference/noCrashUMDMergedWithGlobalValue.js @@ -0,0 +1,14 @@ +//// [tests/cases/compiler/noCrashUMDMergedWithGlobalValue.ts] //// + +//// [other.d.ts] +export as namespace SomeInterface; +export type Action = "PUSH" | "POP" | "REPLACE"; + +//// [main.ts] +interface SomeInterface { + readonly length: number; +} +declare const value: SomeInterface; + + +//// [main.js] diff --git a/tests/baselines/reference/noCrashUMDMergedWithGlobalValue.symbols b/tests/baselines/reference/noCrashUMDMergedWithGlobalValue.symbols new file mode 100644 index 00000000000..c2249abe1d4 --- /dev/null +++ b/tests/baselines/reference/noCrashUMDMergedWithGlobalValue.symbols @@ -0,0 +1,18 @@ +=== /other.d.ts === +export as namespace SomeInterface; +>SomeInterface : Symbol(SomeInterface, Decl(other.d.ts, 0, 0)) + +export type Action = "PUSH" | "POP" | "REPLACE"; +>Action : Symbol(Action, Decl(other.d.ts, 0, 34)) + +=== /main.ts === +interface SomeInterface { +>SomeInterface : Symbol("/other", Decl(other.d.ts, 0, 0), Decl(main.ts, 0, 0)) + + readonly length: number; +>length : Symbol(length, Decl(main.ts, 0, 25)) +} +declare const value: SomeInterface; +>value : Symbol(value, Decl(main.ts, 3, 13)) +>SomeInterface : Symbol("/other", Decl(other.d.ts, 0, 0), Decl(main.ts, 0, 0)) + diff --git a/tests/baselines/reference/noCrashUMDMergedWithGlobalValue.types b/tests/baselines/reference/noCrashUMDMergedWithGlobalValue.types new file mode 100644 index 00000000000..f01fad2560e --- /dev/null +++ b/tests/baselines/reference/noCrashUMDMergedWithGlobalValue.types @@ -0,0 +1,15 @@ +=== /other.d.ts === +export as namespace SomeInterface; +>SomeInterface : typeof import("/other") + +export type Action = "PUSH" | "POP" | "REPLACE"; +>Action : Action + +=== /main.ts === +interface SomeInterface { + readonly length: number; +>length : number +} +declare const value: SomeInterface; +>value : import("/other") + diff --git a/tests/baselines/reference/returnTypePredicateIsInstantiateInContextOfTarget.js b/tests/baselines/reference/returnTypePredicateIsInstantiateInContextOfTarget.js new file mode 100644 index 00000000000..8428f81bd05 --- /dev/null +++ b/tests/baselines/reference/returnTypePredicateIsInstantiateInContextOfTarget.js @@ -0,0 +1,49 @@ +//// [returnTypePredicateIsInstantiateInContextOfTarget.tsx] +/// +import * as React from "react"; +class TestComponent extends React.Component<{ isAny: (obj: any) => obj is T }> { + static defaultProps = { + isAny: TestComponent.isAny + } + + // Type guard is defined as a static class property + static isAny(obj: any): obj is T { + return true; + } +} + +const TestRender = () => ; + +//// [returnTypePredicateIsInstantiateInContextOfTarget.js] +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +exports.__esModule = true; +/// +var React = require("react"); +var TestComponent = /** @class */ (function (_super) { + __extends(TestComponent, _super); + function TestComponent() { + return _super !== null && _super.apply(this, arguments) || this; + } + // Type guard is defined as a static class property + TestComponent.isAny = function (obj) { + return true; + }; + TestComponent.defaultProps = { + isAny: TestComponent.isAny + }; + return TestComponent; +}(React.Component)); +var TestRender = function () { return React.createElement(TestComponent, null); }; diff --git a/tests/baselines/reference/returnTypePredicateIsInstantiateInContextOfTarget.symbols b/tests/baselines/reference/returnTypePredicateIsInstantiateInContextOfTarget.symbols new file mode 100644 index 00000000000..9c7558aa642 --- /dev/null +++ b/tests/baselines/reference/returnTypePredicateIsInstantiateInContextOfTarget.symbols @@ -0,0 +1,42 @@ +=== tests/cases/compiler/returnTypePredicateIsInstantiateInContextOfTarget.tsx === +/// +import * as React from "react"; +>React : Symbol(React, Decl(returnTypePredicateIsInstantiateInContextOfTarget.tsx, 1, 6)) + +class TestComponent extends React.Component<{ isAny: (obj: any) => obj is T }> { +>TestComponent : Symbol(TestComponent, Decl(returnTypePredicateIsInstantiateInContextOfTarget.tsx, 1, 31)) +>React.Component : Symbol(React.Component, Decl(react16.d.ts, 345, 54), Decl(react16.d.ts, 349, 94)) +>React : Symbol(React, Decl(returnTypePredicateIsInstantiateInContextOfTarget.tsx, 1, 6)) +>Component : Symbol(React.Component, Decl(react16.d.ts, 345, 54), Decl(react16.d.ts, 349, 94)) +>isAny : Symbol(isAny, Decl(returnTypePredicateIsInstantiateInContextOfTarget.tsx, 2, 45)) +>T : Symbol(T, Decl(returnTypePredicateIsInstantiateInContextOfTarget.tsx, 2, 54)) +>obj : Symbol(obj, Decl(returnTypePredicateIsInstantiateInContextOfTarget.tsx, 2, 57)) +>obj : Symbol(obj, Decl(returnTypePredicateIsInstantiateInContextOfTarget.tsx, 2, 57)) +>T : Symbol(T, Decl(returnTypePredicateIsInstantiateInContextOfTarget.tsx, 2, 54)) + + static defaultProps = { +>defaultProps : Symbol(TestComponent.defaultProps, Decl(returnTypePredicateIsInstantiateInContextOfTarget.tsx, 2, 83)) + + isAny: TestComponent.isAny +>isAny : Symbol(isAny, Decl(returnTypePredicateIsInstantiateInContextOfTarget.tsx, 3, 27)) +>TestComponent.isAny : Symbol(TestComponent.isAny, Decl(returnTypePredicateIsInstantiateInContextOfTarget.tsx, 5, 5)) +>TestComponent : Symbol(TestComponent, Decl(returnTypePredicateIsInstantiateInContextOfTarget.tsx, 1, 31)) +>isAny : Symbol(TestComponent.isAny, Decl(returnTypePredicateIsInstantiateInContextOfTarget.tsx, 5, 5)) + } + + // Type guard is defined as a static class property + static isAny(obj: any): obj is T { +>isAny : Symbol(TestComponent.isAny, Decl(returnTypePredicateIsInstantiateInContextOfTarget.tsx, 5, 5)) +>T : Symbol(T, Decl(returnTypePredicateIsInstantiateInContextOfTarget.tsx, 8, 17)) +>obj : Symbol(obj, Decl(returnTypePredicateIsInstantiateInContextOfTarget.tsx, 8, 20)) +>obj : Symbol(obj, Decl(returnTypePredicateIsInstantiateInContextOfTarget.tsx, 8, 20)) +>T : Symbol(T, Decl(returnTypePredicateIsInstantiateInContextOfTarget.tsx, 8, 17)) + + return true; + } +} + +const TestRender = () => ; +>TestRender : Symbol(TestRender, Decl(returnTypePredicateIsInstantiateInContextOfTarget.tsx, 13, 5)) +>TestComponent : Symbol(TestComponent, Decl(returnTypePredicateIsInstantiateInContextOfTarget.tsx, 1, 31)) + diff --git a/tests/baselines/reference/returnTypePredicateIsInstantiateInContextOfTarget.types b/tests/baselines/reference/returnTypePredicateIsInstantiateInContextOfTarget.types new file mode 100644 index 00000000000..4780b2722e5 --- /dev/null +++ b/tests/baselines/reference/returnTypePredicateIsInstantiateInContextOfTarget.types @@ -0,0 +1,40 @@ +=== tests/cases/compiler/returnTypePredicateIsInstantiateInContextOfTarget.tsx === +/// +import * as React from "react"; +>React : typeof React + +class TestComponent extends React.Component<{ isAny: (obj: any) => obj is T }> { +>TestComponent : TestComponent +>React.Component : React.Component<{ isAny: (obj: any) => obj is T; }, {}, any> +>React : typeof React +>Component : typeof React.Component +>isAny : (obj: any) => obj is T +>obj : any + + static defaultProps = { +>defaultProps : { isAny: (obj: any) => obj is T; } +>{ isAny: TestComponent.isAny } : { isAny: (obj: any) => obj is T; } + + isAny: TestComponent.isAny +>isAny : (obj: any) => obj is T +>TestComponent.isAny : (obj: any) => obj is T +>TestComponent : typeof TestComponent +>isAny : (obj: any) => obj is T + } + + // Type guard is defined as a static class property + static isAny(obj: any): obj is T { +>isAny : (obj: any) => obj is T +>obj : any + + return true; +>true : true + } +} + +const TestRender = () => ; +>TestRender : () => JSX.Element +>() => : () => JSX.Element +> : JSX.Element +>TestComponent : typeof TestComponent + diff --git a/tests/cases/compiler/declarationEmitMappedPrivateTypeTypeParameter.ts b/tests/cases/compiler/declarationEmitMappedPrivateTypeTypeParameter.ts new file mode 100644 index 00000000000..b65480ea89b --- /dev/null +++ b/tests/cases/compiler/declarationEmitMappedPrivateTypeTypeParameter.ts @@ -0,0 +1,8 @@ +// @declaration: true +// @filename: /Helpers.ts +export type StringKeyOf = Extract; + +// @filename: /FromFactor.ts +export type RowToColumns = { + [TName in StringKeyOf]: any; +} \ No newline at end of file diff --git a/tests/cases/compiler/genericFunctionInference1.ts b/tests/cases/compiler/genericFunctionInference1.ts new file mode 100644 index 00000000000..f2a71ca7f02 --- /dev/null +++ b/tests/cases/compiler/genericFunctionInference1.ts @@ -0,0 +1,187 @@ +// @strict: true +// @target: es2015 + +declare function pipe(ab: (...args: A) => B): (...args: A) => B; +declare function pipe(ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C; +declare function pipe(ab: (...args: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...args: A) => D; + +declare function list(a: T): T[]; +declare function box(x: V): { value: V }; +declare function foo(x: T): T; + +const f00 = pipe(list); +const f01 = pipe(list, box); +const f02 = pipe(box, list); +const f03 = pipe(x => list(x), box); +const f04 = pipe(list, x => box(x)); +const f05 = pipe(x => list(x), x => box(x)) +const f06 = pipe(list, pipe(box)); +const f07 = pipe(x => list(x), pipe(box)); +const f08 = pipe(x => list(x), pipe(x => box(x))); +const f09 = pipe(list, x => x.length); +const f10 = pipe(foo); +const f11 = pipe(foo, foo); + +const g00: (x: T) => T[] = pipe(list); +const g01: (x: T) => { value: T[] } = pipe(list, box); +const g02: (x: T) => { value: T }[] = pipe(box, list); +const g03: (x: T) => { value: T[] } = pipe(x => list(x), box); +const g04: (x: T) => { value: T[] } = pipe(list, x => box(x)); +const g05: (x: T) => { value: T[] } = pipe(x => list(x), x => box(x)) +const g06: (x: T) => { value: T[] } = pipe(list, pipe(box)); +const g07: (x: T) => { value: T[] } = pipe(x => list(x), pipe(box)); +const g08: (x: T) => { value: T[] } = pipe(x => list(x), pipe(x => box(x))); +const g09: (x: T) => number = pipe(list, x => x.length); +const g10: (x: T) => T = pipe(foo); +const g12: (x: T) => T = pipe(foo, foo); + +declare function pipe2(ab: (a: A) => B, cd: (c: C) => D): (a: [A, C]) => [B, D]; + +const f20 = pipe2(list, box); +const f21 = pipe2(box, list); +const f22 = pipe2(list, list); +const f23 = pipe2(box, box); +const f24 = pipe2(f20, f20); +const f25 = pipe2(foo, foo); +const f26 = pipe2(f25, f25); + +declare function pipe3(ab: (a: A) => B, ac: (a: A) => C): (a: A) => [B, C]; + +const f30 = pipe3(list, box); +const f31 = pipe3(box, list); +const f32 = pipe3(list, list); + +declare function pipe4(funcs: [(a: A) => B, (b: B) => C]): (a: A) => C; + +const f40 = pipe4([list, box]); +const f41 = pipe4([box, list]); + +declare function pipe5(f: (a: A) => B): { f: (a: A) => B }; + +const f50 = pipe5(list); // No higher order inference + +// #417 + +function mirror(f: (a: A) => B): (a: A) => B { return f; } +var identityM = mirror(identity); + +var x = 1; +var y = identity(x); +var z = identityM(x); + +// #3038 + +export function keyOf(value: { key: a; }): a { + return value.key; +} +export interface Data { + key: number; + value: Date; +} + +var data: Data[] = []; + +declare function toKeys(values: a[], toKey: (value: a) => string): string[]; + +toKeys(data, keyOf); // Error + +// #9366 + +function flip(f: (a: a, b: b) => c): (b: b, a: a) => c { + return (b: b, a: a) => f(a, b); +} +function zip(x: T, y: U): [T, U] { + return [x, y]; +} + +var expected: (y: U, x: T) => [T, U] = flip(zip); +var actual = flip(zip); + +// #9366 + +const map = (transform: (t: T) => U) => + (arr: T[]) => arr.map(transform) + +const identityStr = (t: string) => t; + +const arr: string[] = map(identityStr)(['a']); +const arr1: string[] = map(identity)(['a']); + +// #9949 + +function of2(one: a, two: b): [a, b] { + return [one, two]; +} + +const flipped = flip(of2); + +// #29904.1 + +type Component

= (props: P) => {}; + +declare const myHoc1:

(C: Component

) => Component

; +declare const myHoc2:

(C: Component

) => Component

; + +declare const MyComponent1: Component<{ foo: 1 }>; + +const enhance = pipe( + myHoc1, + myHoc2, +); + +const MyComponent2 = enhance(MyComponent1); + +// #29904.2 + +const fn20 = pipe((_a?: {}) => 1); + +// #29904.3 + +type Fn = (n: number) => number; +const fn30: Fn = pipe( + x => x + 1, + x => x * 2, +); + +const promise = Promise.resolve(1); +promise.then( + pipe( + x => x + 1, + x => x * 2, + ), +); + +// #29904.4 + +declare const getString: () => string; +declare const orUndefined: (name: string) => string | undefined; +declare const identity: (value: T) => T; + +const fn40 = pipe( + getString, + string => orUndefined(string), + identity, +); + +// #29904.6 + +declare const getArray: () => string[]; +declare const first: (ts: T[]) => T; + +const fn60 = pipe( + getArray, + x => x, + first, +); + +const fn61 = pipe( + getArray, + identity, + first, +); + +const fn62 = pipe( + getArray, + x => x, + x => first(x), +); diff --git a/tests/cases/compiler/noCrashUMDMergedWithGlobalValue.ts b/tests/cases/compiler/noCrashUMDMergedWithGlobalValue.ts new file mode 100644 index 00000000000..0e37eecf91d --- /dev/null +++ b/tests/cases/compiler/noCrashUMDMergedWithGlobalValue.ts @@ -0,0 +1,9 @@ +//@filename: /other.d.ts +export as namespace SomeInterface; +export type Action = "PUSH" | "POP" | "REPLACE"; + +//@filename: /main.ts +interface SomeInterface { + readonly length: number; +} +declare const value: SomeInterface; diff --git a/tests/cases/compiler/returnTypePredicateIsInstantiateInContextOfTarget.tsx b/tests/cases/compiler/returnTypePredicateIsInstantiateInContextOfTarget.tsx new file mode 100644 index 00000000000..8a27e3fde7c --- /dev/null +++ b/tests/cases/compiler/returnTypePredicateIsInstantiateInContextOfTarget.tsx @@ -0,0 +1,16 @@ +// @jsx: react +// @strict: true +/// +import * as React from "react"; +class TestComponent extends React.Component<{ isAny: (obj: any) => obj is T }> { + static defaultProps = { + isAny: TestComponent.isAny + } + + // Type guard is defined as a static class property + static isAny(obj: any): obj is T { + return true; + } +} + +const TestRender = () => ; \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_allParamsOptional.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_allParamsOptional.ts new file mode 100644 index 00000000000..825b34c303d --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_allParamsOptional.ts @@ -0,0 +1,17 @@ +/// + +////function f(/*a*/a?: number, b: string = "1"/*b*/): string { +//// return b; +////} +////f(); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `function f({ a, b = "1" }: { a?: number; b?: string; } = {}): string { + return b; +} +f();` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_arrowFunction.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_arrowFunction.ts new file mode 100644 index 00000000000..6a5a8e328a5 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_arrowFunction.ts @@ -0,0 +1,13 @@ +/// + +////const foo = /*a*/(a: number, b: number)/*b*/ => { }; +////foo(1, 2); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `const foo = ({ a, b }: { a: number; b: number; }) => { }; +foo({ a: 1, b: 2 });` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_arrowFunctionWithContextualType.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_arrowFunctionWithContextualType.ts new file mode 100644 index 00000000000..05a0f6f54fa --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_arrowFunctionWithContextualType.ts @@ -0,0 +1,7 @@ +/// + +////const foo: (a: number, b: number) => number = /*a*/(a: number, b: number)/*b*/ => a + b; +////foo(1, 2); + +goTo.select("a", "b"); +verify.not.refactorAvailable("Convert to named parameters"); diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_callComments.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_callComments.ts new file mode 100644 index 00000000000..6fb06fe938b --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_callComments.ts @@ -0,0 +1,17 @@ +/// + +////function /*a*/foo/*b*/(a: number, b: number, ...rest: number[]) { +//// return a + b; +////} +////foo(/**a*/ 1 /**b*/, /**c*/ 2 /**d*/, /**e*/ 3 /**f*/, /**g*/ 4 /**h*/); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `function foo({ a, b, rest = [] }: { a: number; b: number; rest?: number[]; }) { + return a + b; +} +foo({ /**a*/ a: 1 /**b*/, /**c*/ b: 2 /**d*/, rest: [/**e*/ 3 /**f*/, /**g*/ 4 /**h*/] });` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_callComments2.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_callComments2.ts new file mode 100644 index 00000000000..96a56d7024d --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_callComments2.ts @@ -0,0 +1,34 @@ +/// + +////function /*a*/foo/*b*/(a: number, b: number, ...rest: number[]) { +//// return a + b; +////} +////foo( +//// /**a*/ +//// 1, +//// /**c*/ +//// 2, +//// /**e*/ +//// 3, +//// /**g*/ +//// 4); + +goTo.select("a", "b"); +/* The expected content is currently wrong. The new argument object has the wrong formatting. */ +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `function foo({ a, b, rest = [] }: { a: number; b: number; rest?: number[]; }) { + return a + b; +} +foo( + { /**a*/ + a: 1, /**c*/ + b: 2, rest: [ + /**e*/ + 3, + /**g*/ + 4] + });` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_chainedCall.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_chainedCall.ts new file mode 100644 index 00000000000..0fb20ec864d --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_chainedCall.ts @@ -0,0 +1,17 @@ +/// + +////function foo(/*a*/a: number, b: number/*b*/) { +//// return { bar: () => a + b }; +////} +////var x = foo(1, 2).bar(); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `function foo({ a, b }: { a: number; b: number; }) { + return { bar: () => a + b }; +} +var x = foo({ a: 1, b: 2 }).bar();` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_classDeclarationAliasing.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_classDeclarationAliasing.ts new file mode 100644 index 00000000000..0914dedd57d --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_classDeclarationAliasing.ts @@ -0,0 +1,20 @@ +/// + +////class Foo { +//// /*a*/constructor/*b*/(a: number, b: number) { } +////} +////const fooAlias = Foo; +////const newFoo = new fooAlias(1, 2); + +goTo.select("a", "b"); +// Refactor should not make changes +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `class Foo { + constructor(a: number, b: number) { } +} +const fooAlias = Foo; +const newFoo = new fooAlias(1, 2);` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_classDeclarationGoodUsages.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_classDeclarationGoodUsages.ts new file mode 100644 index 00000000000..858bccd60c1 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_classDeclarationGoodUsages.ts @@ -0,0 +1,31 @@ +/// + +////class C { +//// static a: number = 2; +//// /*a*/constructor/*b*/(a: number, b: number) { } +////} +////const newC = new C(1, 2); +////const b = C.a; +////C["a"] = 3; +////let c: C; +////function f(c: C) { } +////class B extends C { } +////class A implements C { } + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `class C { + static a: number = 2; + constructor({ a, b }: { a: number; b: number; }) { } +} +const newC = new C({ a: 1, b: 2 }); +const b = C.a; +C["a"] = 3; +let c: C; +function f(c: C) { } +class B extends C { } +class A implements C { }` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_classExpression.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_classExpression.ts new file mode 100644 index 00000000000..ee4b6051756 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_classExpression.ts @@ -0,0 +1,17 @@ +/// + +////const c = class { +//// constructor(/*a*/a: number, b = { x: 1 }/*b*/) { } +////} +////var x = new c(2); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `const c = class { + constructor({ a, b = { x: 1 } }: { a: number; b?: { x: number; }; }) { } +} +var x = new c({ a: 2 });` +}); diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_classExpressionGoodUsages.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_classExpressionGoodUsages.ts new file mode 100644 index 00000000000..f8023b9898c --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_classExpressionGoodUsages.ts @@ -0,0 +1,23 @@ +/// + +////const c = class C { +//// static a: number = 2; +//// /*a*/constructor/*b*/(a: number, b: number) { } +////} +////const a = new c(0, 1); +////const b = c.a; +////c["a"] = 3; + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `const c = class C { + static a: number = 2; + constructor({ a, b }: { a: number; b: number; }) { } +} +const a = new c({ a: 0, b: 1 }); +const b = c.a; +c["a"] = 3;` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_classExpressionHeritage.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_classExpressionHeritage.ts new file mode 100644 index 00000000000..14b9639c2ad --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_classExpressionHeritage.ts @@ -0,0 +1,26 @@ +/// + +////const foo = class Foo { +//// /*a*/constructor/*b*/(a: number, b: number) { } +////} +////class Bar extends foo { +//// constructor() { +//// super(1, 2); +//// } +////} + +goTo.select("a", "b"); +// Refactor should not make changes +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `const foo = class Foo { + constructor(a: number, b: number) { } +} +class Bar extends foo { + constructor() { + super(1, 2); + } +}` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_classTypeParameters.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_classTypeParameters.ts new file mode 100644 index 00000000000..7d626215572 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_classTypeParameters.ts @@ -0,0 +1,23 @@ +/// + +////class Foo { +//// /*a*/bar/*b*/(t: T, s: T) { +//// return s; +//// } +////} +////var foo = new Foo(); +////foo.bar("a", "b"); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `class Foo { + bar({ t, s }: { t: T; s: T; }) { + return s; + } +} +var foo = new Foo(); +foo.bar({ t: "a", s: "b" });` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_constructor.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_constructor.ts new file mode 100644 index 00000000000..86b1f9eb610 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_constructor.ts @@ -0,0 +1,27 @@ +/// + +////class Foo { +//// t: string; +//// s: string; +//// /*a*/constructor/*b*/(t: string, s: string) { +//// this.t = t; +//// this.s = s; +//// } +////} +////var foo = new Foo("a", "b"); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `class Foo { + t: string; + s: string; + constructor({ t, s }: { t: string; s: string; }) { + this.t = t; + this.s = s; + } +} +var foo = new Foo({ t: "a", s: "b" });` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_defaultClass.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_defaultClass.ts new file mode 100644 index 00000000000..a056a82871b --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_defaultClass.ts @@ -0,0 +1,8 @@ +/// + +/////export default class { +//// constructor(/*a*/a: number, b = { x: 1 }/*b*/) {} +////} + +goTo.select("a", "b"); +verify.not.refactorAvailable("Convert to named parameters"); diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_function.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_function.ts new file mode 100644 index 00000000000..0834bf288fc --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_function.ts @@ -0,0 +1,17 @@ +/// + +////function f(/*a*/a: number, b: string/*b*/): string { +//// return b; +////} +////f(4, "b"); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `function f({ a, b }: { a: number; b: string; }): string { + return b; +} +f({ a: 4, b: "b" });` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_functionComments.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_functionComments.ts new file mode 100644 index 00000000000..20238ac81de --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_functionComments.ts @@ -0,0 +1,23 @@ +/// + +////foo(1, 2); /**a*/ +/////**b*/ function /*a*/foo/*b*/(/**this1*/ this /**this2*/: /**void1*/ void /**void2*/, /**c*/ a /**d*/: /**e*/ number /**f*/, /**g*/ b /**h*/: /**i*/ number /**j*/ = /**k*/ 1 /**l*/) { +//// // m +//// /**n*/ return a + b; // o +//// // p +////} // q +/////**r*/ foo(1); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `foo({ a: 1, b: 2 }); /**a*/ +/**b*/ function foo(/**this1*/ this /**this2*/: /**void1*/ void /**void2*/, { a, b = /**k*/ 1 /**l*/ }: { /**c*/ a /**d*/: /**e*/ number /**f*/; /**g*/ b /**h*/?: /**i*/ number /**j*/; }) { + // m + /**n*/ return a + b; // o + // p +} // q +/**r*/ foo({ a: 1 });` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_functionComments1.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_functionComments1.ts new file mode 100644 index 00000000000..e0d34c8fe65 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_functionComments1.ts @@ -0,0 +1,15 @@ +/// + +////function /*a*/foo/*b*/(a: number /** a */, b: number /** b */) { +//// return a + b; +////} + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `function foo({ a, b }: { a: number /** a */; b: number /** b */; }) { + return a + b; +}` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_functionComments2.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_functionComments2.ts new file mode 100644 index 00000000000..923b49b4198 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_functionComments2.ts @@ -0,0 +1,26 @@ +/// + +////function /*a*/foo/*b*/(// comment +//// // a comment +//// a: number, +//// // b comment +//// b: number +////) { +//// return a + b; +////} + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `function foo(// comment +{ a, b }: { + // a comment + a: number; + // b comment + b: number; +}) { + return a + b; +}` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_functionExpression.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_functionExpression.ts new file mode 100644 index 00000000000..e8aa6a92dd8 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_functionExpression.ts @@ -0,0 +1,13 @@ +/// + +////const foo = /*a*/function/*b*/(a: number, b: number) { }; +////foo(1, 2); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `const foo = function({ a, b }: { a: number; b: number; }) { }; +foo({ a: 1, b: 2 });` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_functionTypeParameters.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_functionTypeParameters.ts new file mode 100644 index 00000000000..a1597fdeed1 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_functionTypeParameters.ts @@ -0,0 +1,17 @@ +/// + +////function foo(/*a*/t: T, s: S/*b*/) { +//// return s; +////} +////foo("a", "b"); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `function foo({ t, s }: { t: T; s: S; }) { + return s; +} +foo({ t: "a", s: "b" });` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_inheritedConstructor.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_inheritedConstructor.ts new file mode 100644 index 00000000000..bde7839a60e --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_inheritedConstructor.ts @@ -0,0 +1,24 @@ +/// + +////class Foo { +//// /*a*/constructor/*b*/(t: string, s: string) { } +////} +////class Bar extends Foo { } +////var bar = new Bar("a", "b"); +////var foo = new Foo("c", "d"); + +goTo.select("a", "b"); +/* The expected new content is currently wrong. + `new Bar("a", "b")` should be modified by the refactor to be `new Bar({ t: "a", s: "b" })` +*/ +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `class Foo { + constructor({ t, s }: { t: string; s: string; }) { } +} +class Bar extends Foo { } +var bar = new Bar("a", "b"); +var foo = new Foo({ t: "c", s: "d" });` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_inheritedMethod.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_inheritedMethod.ts new file mode 100644 index 00000000000..3214ea4bf53 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_inheritedMethod.ts @@ -0,0 +1,25 @@ +/// + +////class Foo { +//// /*a*/bar/*b*/(t: string, s: string): string { +//// return s + t; +//// } +////} +////class Bar extends Foo { } +////var bar = new Bar(); +////bar.bar("a", "b"); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `class Foo { + bar({ t, s }: { t: string; s: string; }): string { + return s + t; + } +} +class Bar extends Foo { } +var bar = new Bar(); +bar.bar({ t: "a", s: "b" });` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_initializer.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_initializer.ts new file mode 100644 index 00000000000..1e63f44fc35 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_initializer.ts @@ -0,0 +1,17 @@ +/// + +////function f(/*a*/a: number, b: string = "1"/*b*/): string { +//// return b; +////} +////f(4, "b"); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `function f({ a, b = "1" }: { a: number; b?: string; }): string { + return b; +} +f({ a: 4, b: "b" });` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_initializerInference.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_initializerInference.ts new file mode 100644 index 00000000000..b6bdb7a88c2 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_initializerInference.ts @@ -0,0 +1,17 @@ +/// + +////function f(/*a*/a: number, b = { x: 1, z: { s: true } }/*b*/) { +//// return b; +////} +////f(2); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `function f({ a, b = { x: 1, z: { s: true } } }: { a: number; b?: { x: number; z: { s: boolean; }; }; }) { + return b; +} +f({ a: 2 });` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_method.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_method.ts new file mode 100644 index 00000000000..d7dce948cae --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_method.ts @@ -0,0 +1,23 @@ +/// + +////class Foo { +//// /*a*/bar/*b*/(t: string, s: string): string { +//// return s + t; +//// } +////} +////var foo = new Foo(); +////foo.bar("a", "b"); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `class Foo { + bar({ t, s }: { t: string; s: string; }): string { + return s + t; + } +} +var foo = new Foo(); +foo.bar({ t: "a", s: "b" });` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_methodCallUnion.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_methodCallUnion.ts new file mode 100644 index 00000000000..e4cafbeff3e --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_methodCallUnion.ts @@ -0,0 +1,29 @@ +/// + +////class A { +//// /*a*/foo/*b*/(a: number, b: number) { return a + b; } +////} +////class B { +//// foo(c: number, d: number) { return c + d; } +////} +////function foo(ab: A | B) { +//// return ab.foo(1, 2); +////} + + +goTo.select("a", "b"); +// Refactor should not make changes +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `class A { + foo(a: number, b: number) { return a + b; } +} +class B { + foo(c: number, d: number) { return c + d; } +} +function foo(ab: A | B) { + return ab.foo(1, 2); +}` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_methodCalls.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_methodCalls.ts new file mode 100644 index 00000000000..f84e0d7b023 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_methodCalls.ts @@ -0,0 +1,25 @@ +/// + +////class Foo { +//// /*a*/bar/*b*/(t: string, s: string): string { +//// return s + t; +//// } +////} +////var foo = new Foo(); +////foo['bar']("a", "b"); +////foo.bar("a", "b"); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `class Foo { + bar({ t, s }: { t: string; s: string; }): string { + return s + t; + } +} +var foo = new Foo(); +foo['bar']({ t: "a", s: "b" }); +foo.bar({ t: "a", s: "b" });` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_methodOverrides.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_methodOverrides.ts new file mode 100644 index 00000000000..b6daac17dd4 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_methodOverrides.ts @@ -0,0 +1,45 @@ +/// + +////class A { +//// /*a*/foo/*b*/(a: number, b: number) { } +////} +////class B extends A { +//// /*c*/foo/*d*/(c: number, d: number) { } +////} +////var a = new A(); +////a.foo(3, 4); +////var b = new B(); +////b.foo(5, 6); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `class A { + foo(a: number, b: number) { } +} +class B extends A { + foo(c: number, d: number) { } +} +var a = new A(); +a.foo(3, 4); +var b = new B(); +b.foo(5, 6);` +}); +goTo.select("c", "d"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `class A { + foo(a: number, b: number) { } +} +class B extends A { + foo(c: number, d: number) { } +} +var a = new A(); +a.foo(3, 4); +var b = new B(); +b.foo(5, 6);` +}); diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_overloads.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_overloads.ts new file mode 100644 index 00000000000..772f8ea8848 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_overloads.ts @@ -0,0 +1,10 @@ +/// + +////function f(a: number, b: number); +////function f(/*a*/a: number, b = 1/*b*/) { +//// return b; +////} +////f(2); + +goTo.select("a", "b"); +verify.not.refactorAvailable("Convert to named parameters"); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_paramDecorator.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_paramDecorator.ts new file mode 100644 index 00000000000..180798af95d --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_paramDecorator.ts @@ -0,0 +1,11 @@ +/// + +////declare function required(target: Object, propertyKey: string | symbol, parameterIndex: number) +////class C { +//// /*a*/bar/*b*/(@required a: number, b: number) { +//// +//// } +////} + +goTo.select("a", "b"); +verify.not.refactorAvailable("Convert to named parameters"); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_recursiveFunction.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_recursiveFunction.ts new file mode 100644 index 00000000000..d1513cb7bf0 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_recursiveFunction.ts @@ -0,0 +1,20 @@ +/// + +////const f = function foo(/*a*/a: number, b: number/*b*/) { +//// foo(1, 2); +////} +////function foo(a: number, b: number) { } +////foo(3, 4); + + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `const f = function foo({ a, b }: { a: number; b: number; }) { + foo({ a: 1, b: 2 }); +} +function foo(a: number, b: number) { } +foo(3, 4);` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_restParamInference.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_restParamInference.ts new file mode 100644 index 00000000000..36ed5084fe2 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_restParamInference.ts @@ -0,0 +1,15 @@ +/// + +////function log(/*a*/a: number, b: number, ...args/*b*/) { } +////let l = log(-1, -2, 3, 4, 5); +////let k = log(1, 2); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `function log({ a, b, args = [] }: { a: number; b: number; args?: any[]; }) { } +let l = log({ a: -1, b: -2, args: [3, 4, 5] }); +let k = log({ a: 1, b: 2 });` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_staticMethod.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_staticMethod.ts new file mode 100644 index 00000000000..c84c1aa20d4 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_staticMethod.ts @@ -0,0 +1,21 @@ +/// + +////class Foo { +//// static /*a*/bar/*b*/(t: string, s: string): string { +//// return s + t; +//// } +////} +////Foo.bar("a", "b"); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `class Foo { + static bar({ t, s }: { t: string; s: string; }): string { + return s + t; + } +} +Foo.bar({ t: "a", s: "b" });` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_superCall.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_superCall.ts new file mode 100644 index 00000000000..c5d15903ef5 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_superCall.ts @@ -0,0 +1,25 @@ +/// + +////class A { +//// constructor(/*a*/a: string, b: string/*b*/) { } +////} +////class B extends A { +//// constructor(a: string, b: string, c: string) { +//// super(a, b); +//// } +////} + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `class A { + constructor({ a, b }: { a: string; b: string; }) { } +} +class B extends A { + constructor(a: string, b: string, c: string) { + super({ a: a, b: b }); + } +}` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_thisParam.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_thisParam.ts new file mode 100644 index 00000000000..e4a96bc7bf1 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_thisParam.ts @@ -0,0 +1,17 @@ +/// + +////function foo(this: void, /*a*/t: string, s: string/*b*/) { +//// return s; +////} +////foo("a", "b"); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `function foo(this: void, { t, s }: { t: string; s: string; }) { + return s; +} +foo({ t: "a", s: "b" });` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_typedRestParam.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_typedRestParam.ts new file mode 100644 index 00000000000..34e0331f466 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_typedRestParam.ts @@ -0,0 +1,15 @@ +/// + +////function /*a*/buildName/*b*/(firstName: string, middleName?: string, ...restOfName: string[]) { } +////let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie"); +////let myName = buildName("Joseph"); + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert to named parameters", + actionName: "Convert to named parameters", + actionDescription: "Convert to named parameters", + newContent: `function buildName({ firstName, middleName, restOfName = [] }: { firstName: string; middleName?: string; restOfName?: string[]; }) { } +let employeeName = buildName({ firstName: "Joseph", middleName: "Samuel", restOfName: ["Lucas", "MacKinzie"] }); +let myName = buildName({ firstName: "Joseph" });` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/refactorConvertToNamedParameters_varArrowFunction.ts b/tests/cases/fourslash/refactorConvertToNamedParameters_varArrowFunction.ts new file mode 100644 index 00000000000..ec25b50b067 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToNamedParameters_varArrowFunction.ts @@ -0,0 +1,7 @@ +/// + +////var foo = /*a*/(a: number, b: number)/*b*/ => {}; +////foo(1, 2); + +goTo.select("a", "b"); +verify.not.refactorAvailable("Convert to named parameters"); diff --git a/tests/perfsys.ts b/tests/perfsys.ts deleted file mode 100644 index abe09c88a0f..00000000000 --- a/tests/perfsys.ts +++ /dev/null @@ -1,104 +0,0 @@ -/// -/// - -namespace perftest { - interface IOLog { - resolvePath: ts.Map; - fileNames: string[]; - } - - export interface IO { - getOut(): string; - } - - export const readFile = ts.sys.readFile; - const writeFile = ts.sys.writeFile; - export const write = ts.sys.write; - const resolvePath = ts.sys.resolvePath; - export const getExecutingFilePath = ts.sys.getExecutingFilePath; - export const getCurrentDirectory = ts.sys.getCurrentDirectory; - // const exit = ts.sys.exit; - - const args = ts.sys.args; - - // augment sys so first ts.executeCommandLine call will be finish silently - ts.sys.write = (s: string) => { }; - ts.sys.exit = (code: number) => { }; - ts.sys.args = []; - - export function restoreSys() { - ts.sys.args = args; - ts.sys.write = write; - } - - export function hasLogIOFlag() { - return args.length > 2 && args[0] === "--logio"; - } - - export function getArgsWithoutLogIOFlag() { - return args.slice(2); - } - - export function getArgsWithoutIOLogFile() { - return args.slice(1); - } - - const resolvePathLog: ts.Map = {}; - - export function interceptIO() { - ts.sys.resolvePath = (s) => { - const result = resolvePath(s); - resolvePathLog[s] = result; - return result; - }; - } - - export function writeIOLog(fileNames: string[]) { - const path = args[1]; - const log: IOLog = { - fileNames: fileNames, - resolvePath: resolvePathLog - }; - - writeFile(path, JSON.stringify(log)); - } - - export function prepare(): IO { - const log = JSON.parse(readFile(args[0])); - - const files: ts.Map = {}; - log.fileNames.forEach(f => { files[f] = readFile(f); }); - - ts.sys.createDirectory = (s: string) => { }; - ts.sys.directoryExists = (s: string) => true; - ts.sys.fileExists = (s: string) => true; - - const currentDirectory = ts.sys.getCurrentDirectory(); - ts.sys.getCurrentDirectory = () => currentDirectory; - - const executingFilePath = ts.sys.getExecutingFilePath(); - ts.sys.getExecutingFilePath = () => executingFilePath; - - ts.sys.readFile = (s: string) => { - return files[s]; - }; - - ts.sys.resolvePath = (s: string) => { - const path = log.resolvePath[s]; - if (!path) { - throw new Error("Unexpected path '" + s + "'"); - } - return path; - }; - - ts.sys.writeFile = (path: string, data: string) => { }; - - let out = ""; - - ts.sys.write = (s: string) => { out += s; }; - - return { - getOut: () => out, - }; - } -} diff --git a/tests/perftsc.ts b/tests/perftsc.ts deleted file mode 100644 index 0753023853e..00000000000 --- a/tests/perftsc.ts +++ /dev/null @@ -1,30 +0,0 @@ -/// -/// - -// resolve all files used in this compilation -if (perftest.hasLogIOFlag()) { - perftest.interceptIO(); - - const compilerHost: ts.CompilerHost = { - getSourceFile: (s, v) => { - const content = perftest.readFile(s); - return content !== undefined ? ts.createSourceFile(s, content, v) : undefined; - }, - getDefaultLibFileName: () => ts.combinePaths(ts.getDirectoryPath(ts.normalizePath(perftest.getExecutingFilePath())), "lib.d.ts"), - writeFile: (f: string, content: string) => { throw new Error("Unexpected operation: writeFile"); }, - getCurrentDirectory: () => perftest.getCurrentDirectory(), - getCanonicalFileName: (f: string) => ts.sys.useCaseSensitiveFileNames ? f : f.toLowerCase(), - useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames, - getNewLine: () => ts.sys.newLine - }; - - const commandLine = ts.parseCommandLine(perftest.getArgsWithoutLogIOFlag()); - const program = ts.createProgram(commandLine.fileNames, commandLine.options, compilerHost); - const fileNames = program.getSourceFiles().map(f => f.fileName); - perftest.writeIOLog(fileNames); -} -else { - const io = perftest.prepare(); - ts.executeCommandLine(perftest.getArgsWithoutIOLogFile()); - perftest.write(io.getOut()); -} diff --git a/tests/perftsc.tsconfig.json b/tests/perftsc.tsconfig.json deleted file mode 100644 index dafd33f9def..00000000000 --- a/tests/perftsc.tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "es2015", - "module": "commonjs", - "declaration": false, - "removeComments": true, - "noResolve": false, - "stripInternal": false, - "sourceMap": true, - "outFile": "../built/local/perftsc.js" - }, - "files": [ - "perftsc.ts" - ] -} \ No newline at end of file diff --git a/tests/test.bat b/tests/test.bat deleted file mode 100644 index 4517d99f3c8..00000000000 --- a/tests/test.bat +++ /dev/null @@ -1,13 +0,0 @@ -@echo off -setlocal -set LF=^ - - -for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a" - -setlocal enableDelayedExpansion -echo "START" -echo "asdf!CR!asdf" -echo "AASDF!LF!ASDF" -echo "END" -findstr /S /R /M /C:"[^!CR!]!LF!" * diff --git a/tests/webTestResults.html b/tests/webTestResults.html deleted file mode 100644 index 487abfc117d..00000000000 --- a/tests/webTestResults.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - Mocha Tests - - - - - -

-
- - - - - - - - - \ No newline at end of file diff --git a/tests/webTestServer.ts b/tests/webTestServer.ts deleted file mode 100644 index c33196a99ca..00000000000 --- a/tests/webTestServer.ts +++ /dev/null @@ -1,1014 +0,0 @@ -/// -// tslint:disable:no-null-keyword - -import minimist = require("minimist"); -import http = require("http"); -import fs = require("fs"); -import path = require("path"); -import url = require("url"); -import URL = url.URL; -import child_process = require("child_process"); -import os = require("os"); -import crypto = require("crypto"); -import { Readable, Writable } from "stream"; -import { isBuffer, isString, isObject } from "util"; -import { install, getErrorSource } from "source-map-support"; - -install(); - -const port = 8888; // harness.ts and webTestResults.html depend on this exact port number. -const baseUrl = new URL(`http://localhost:${port}/`); -const rootDir = path.dirname(__dirname); -const useCaseSensitiveFileNames = isFileSystemCaseSensitive(); - -const defaultBrowser = os.platform() === "win32" ? "edge" : "chrome"; -let browser: "edge" | "chrome" | "none" = defaultBrowser; -let grep: string | undefined; -let verbose = false; - -interface FileBasedTest { - file: string; - configurations?: FileBasedTestConfiguration[]; -} - -interface FileBasedTestConfiguration { - [setting: string]: string; -} - -function isFileSystemCaseSensitive(): boolean { - // win32\win64 are case insensitive platforms - const platform = os.platform(); - if (platform === "win32" || platform === "win64") { - return false; - } - // If this file exists under a different case, we must be case-insensitve. - return !fs.existsSync(swapCase(__filename)); -} - -function swapCase(s: string): string { - return s.replace(/\w/g, (ch) => { - const up = ch.toUpperCase(); - return ch === up ? ch.toLowerCase() : up; - }); -} - -function hasLeadingSeparator(pathname: string) { - const ch = pathname.charAt(0); - return ch === "/" || ch === "\\"; -} - -function ensureLeadingSeparator(pathname: string) { - return hasLeadingSeparator(pathname) ? pathname : "/" + pathname; -} - -function trimLeadingSeparator(pathname: string) { - return hasLeadingSeparator(pathname) ? pathname.slice(1) : pathname; -} - -function normalizeSlashes(path: string) { - return path.replace(/\\+/g, "/"); -} - -function hasTrailingSeparator(pathname: string) { - const ch = pathname.charAt(pathname.length - 1); - return ch === "/" || ch === "\\"; -} - -function toServerPath(url: url.URL | string) { - if (typeof url === "string") url = new URL(url, baseUrl); - const pathname = decodeURIComponent(url.pathname); - return path.join(rootDir, pathname); -} - -function toClientPath(pathname: string) { - pathname = normalizeSlashes(pathname); - pathname = trimLeadingSeparator(pathname); - - const serverPath = path.resolve(rootDir, pathname); - if (serverPath.slice(0, rootDir.length) !== rootDir) { - return undefined; - } - - let clientPath = serverPath.slice(rootDir.length); - clientPath = ensureLeadingSeparator(clientPath); - clientPath = normalizeSlashes(clientPath); - return clientPath; -} - -function flatMap(array: T[], selector: (value: T) => U | U[]) { - let result: U[] = []; - for (const item of array) { - const mapped = selector(item); - if (Array.isArray(mapped)) { - result = result.concat(mapped); - } - else { - result.push(mapped); - } - } - return result; -} - -declare module "http" { - interface IncomingHttpHeaders { - "if-match"?: string; - "if-none-match"?: string; - "if-modified-since"?: string; - "if-unmodified-since"?: string; - "accept-charset"?: string; - "accept-encoding"?: string; - "range"?: string; - } -} - -function getQuality(value: T) { - return value.quality === undefined ? 1 : value.quality; -} - -function bestMatch(value: T, patterns: TPattern[], isMatch: (value: T, pattern: TPattern) => boolean) { - let match: TPattern | undefined; - for (const pattern of patterns) { - if (!isMatch(value, pattern)) continue; - if (match === undefined || getQuality(pattern) > getQuality(match)) { - match = pattern; - } - } - return match; -} - -const mediaTypeParser = /^([^\/]+)\/([^\/;]+)(?:;(.*))?$/; - -interface MediaType { - type: string; - subtype: string; - parameters: Record; - charset?: string; - quality?: number; -} - -function parseMediaType(mediaType: string): MediaType { - const match = mediaTypeParser.exec(mediaType); - if (!match) throw new Error("Invalid media type"); - const type = match[1].trim(); - const subtype = match[2].trim(); - if (type === "*" && subtype !== "*") throw new Error("Invalid media type"); - const parameters: Record = {}; - let charset: string | undefined; - let quality: number | undefined; - if (match[3]) { - for (const parameter of match[3].split(";")) { - const pair = parameter.split("="); - const name = pair[0].trim(); - const value = pair[1].trim(); - parameters[name] = value; - if (name === "charset") charset = value; - if (name === "q") quality = +value; - } - } - return { type, subtype, parameters, charset, quality }; -} - -function parseMediaTypes(value: string) { - const mediaTypes: MediaType[] = []; - for (const mediaRange of value.split(",")) { - mediaTypes.push(parseMediaType(mediaRange)); - } - return mediaTypes; -} - -function matchesMediaType(mediaType: MediaType, mediaTypePattern: MediaType) { - if (mediaTypePattern.type === "*") return true; - if (mediaTypePattern.type === mediaType.type) { - if (mediaTypePattern.subtype === "*") return true; - if (mediaTypePattern.subtype === mediaType.subtype) return true; - } - return false; -} - -interface StringWithQuality { - value: string; - quality?: number; -} - -const stringWithQualityParser = /^([^;]+)(;\s*q\s*=\s*([^\s]+)\s*)?$/; - -function parseStringWithQuality(value: string) { - const match = stringWithQualityParser.exec(value); - if (!match) throw new Error("Invalid header value"); - return { value: match[1].trim(), quality: match[2] ? +match[2] : undefined }; -} - -function parseStringsWithQuality(value: string) { - const charsets: StringWithQuality[] = []; - for (const charset of value.split(",")) { - charsets.push(parseStringWithQuality(charset)); - } - return charsets; -} - -function matchesCharSet(charset: string, charsetPattern: StringWithQuality) { - return charsetPattern.value === "*" || charsetPattern.value === charset; -} - -function computeETag(stats: fs.Stats) { - return JSON.stringify(crypto - .createHash("sha1") - .update(JSON.stringify({ - dev: stats.dev, - ino: stats.ino, - mtime: stats.mtimeMs, - size: stats.size - })) - .digest("base64")); -} - -function tryParseETags(value: string | undefined): "*" | string[] | undefined { - if (!value) return undefined; - if (value === "*") return value; - const etags: string[] = []; - for (const etag of value.split(",")) { - etags.push(etag.trim()); - } - return etags; -} - -function matchesETag(etag: string | undefined, condition: "*" | string[] | undefined) { - if (!condition) return true; - if (!etag) return false; - return condition === "*" || condition.indexOf(etag) >= 0; -} - -function tryParseDate(value: string | undefined) { - return value ? new Date(value) : undefined; -} - -interface ByteRange { - start: number; - end: number; -} - -const byteRangeParser = /^\s*(\d+)\s*-\s*(\d+)\s*$/; - -function tryParseByteRange(value: string, contentLength: number): ByteRange | undefined { - const match = byteRangeParser.exec(value); - const firstBytePos = match && match[1] ? +match[1] : undefined; - const lastBytePos = match && match[2] ? +match[2] : undefined; - if (firstBytePos !== undefined && lastBytePos !== undefined) { - if (lastBytePos < firstBytePos) return undefined; - return { start: firstBytePos, end: lastBytePos + 1 }; - } - if (firstBytePos !== undefined) return { start: firstBytePos, end: contentLength }; - if (lastBytePos !== undefined) return { start: contentLength - lastBytePos, end: contentLength }; - return undefined; -} - -function tryParseByteRanges(value: string, contentLength: number): ByteRange[] | undefined { - if (!value.startsWith("bytes=")) return; - const ranges: ByteRange[] = []; - for (const range of value.slice(6).split(",")) { - const byteRange = tryParseByteRange(range, contentLength); - if (byteRange === undefined) return undefined; - if (byteRange.start >= contentLength) continue; - ranges.push(byteRange); - } - return ranges; -} - -function once void>(callback: T): T; -function once(callback: (...args: any[]) => void) { - let called = false; - return (...args: any[]) => { - if (called) return; - called = true; - callback(...args); - }; -} - -function mkdirp(dirname: string, callback: (err: NodeJS.ErrnoException | null) => void) { - fs.mkdir(dirname, err => { - if (err && err.code === "EEXIST") err = null; - if (err && err.code === "ENOENT") { - const parentdir = path.dirname(dirname); - if (!parentdir || parentdir === dirname) return callback(err); - return mkdirp(parentdir, err => { - if (err) return callback(err); - return fs.mkdir(dirname, callback); - }); - } - return callback(err); - }); -} - -function getAccessibleFileSystemEntries(pathname: string) { - try { - const entries = fs.readdirSync(pathname).sort(); - const files: string[] = []; - const directories: string[] = []; - for (const entry of entries) { - // This is necessary because on some file system node fails to exclude - // "." and "..". See https://github.com/nodejs/node/issues/4002 - if (entry === "." || entry === "..") { - continue; - } - const name = path.join(pathname, entry); - - let stat: fs.Stats; - try { - stat = fs.statSync(name); - } - catch (e) { - continue; - } - - if (stat.isFile()) { - files.push(entry); - } - else if (stat.isDirectory()) { - directories.push(entry); - } - } - return { files, directories }; - } - catch (e) { - return { files: [], directories: [] }; - } -} - -function guessMediaType(pathname: string) { - switch (path.extname(pathname).toLowerCase()) { - case ".html": return "text/html; charset=utf-8"; - case ".css": return "text/css; charset=utf-8"; - case ".js": return "application/javascript; charset=utf-8"; - case ".mjs": return "application/javascript; charset=utf-8"; - case ".jsx": return "text/jsx; charset=utf-8"; - case ".ts": return "text/plain; charset=utf-8"; - case ".tsx": return "text/plain; charset=utf-8"; - case ".json": return "text/plain; charset=utf-8"; - case ".map": return "application/json; charset=utf-8"; - default: return "application/octet-stream"; - } -} - -function readContent(req: http.ServerRequest, callback: (err: NodeJS.ErrnoException | null, content: string | null) => void) { - const chunks: Buffer[] = []; - const done = once((err: NodeJS.ErrnoException | null) => { - if (err) return callback(err, /*content*/ null); - let content: string | null = null; - try { - content = Buffer.concat(chunks).toString("utf8"); - } - catch (e) { - err = e; - } - return callback(err, content); - }); - req.on("data", chunk => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf8"))); - req.on("error", err => done(err)); - req.on("end", () => done(/*err*/ null)); -} - -function saveToFile(file: string, readable: Readable, callback: (err: NodeJS.ErrnoException | null) => void) { - callback = once(callback); - const writable = fs.createWriteStream(file, { autoClose: true }); - writable.on("error", err => callback(err)); - readable.on("end", () => callback(/*err*/ null)); - readable.pipe(writable, { end: true }); -} - -function sendContent(res: http.ServerResponse, statusCode: number, content: string | Buffer, contentType: string): void; -function sendContent(res: http.ServerResponse, statusCode: number, content: Readable, contentType: string, contentLength: number): void; -function sendContent(res: http.ServerResponse, statusCode: number, content: string | Buffer | Readable, contentType: string, contentLength?: number) { - res.statusCode = statusCode; - res.setHeader("Content-Type", contentType); - if (isString(content)) { - res.setHeader("Content-Length", Buffer.byteLength(content, "utf8")); - res.end(content, "utf8"); - } - else if (isBuffer(content)) { - res.setHeader("Content-Length", content.byteLength); - res.end(content); - } - else { - if (contentLength !== undefined) res.setHeader("Content-Length", contentLength); - content.on("error", e => sendInternalServerError(res, e)); - content.pipe(res, { end: true }); - } -} - -function sendJson(res: http.ServerResponse, statusCode: number, value: any) { - try { - sendContent(res, statusCode, JSON.stringify(value), "application/json; charset=utf-8"); - } - catch (e) { - sendInternalServerError(res, e); - } -} - -function sendCreated(res: http.ServerResponse, location?: string, etag?: string) { - res.statusCode = 201; - if (location) res.setHeader("Location", location); - if (etag) res.setHeader("ETag", etag); - res.end(); -} - -function sendNoContent(res: http.ServerResponse) { - res.statusCode = 204; - res.end(); -} - -function sendFound(res: http.ServerResponse, location: string) { - res.statusCode = 302; - res.setHeader("Location", location); - res.end(); -} - -function sendNotModified(res: http.ServerResponse) { - res.statusCode = 304; - res.end(); -} - -function sendBadRequest(res: http.ServerResponse) { - res.statusCode = 400; - res.end(); -} - -function sendNotFound(res: http.ServerResponse) { - res.statusCode = 404; - res.end(); -} - -function sendMethodNotAllowed(res: http.ServerResponse, allowedMethods: string[]) { - res.statusCode = 405; - res.setHeader("Allow", allowedMethods); - res.end(); -} - -function sendNotAcceptable(res: http.ServerResponse) { - res.statusCode = 406; - res.end(); -} - -function sendPreconditionFailed(res: http.ServerResponse) { - res.statusCode = 412; - res.end(); -} - -function sendUnsupportedMediaType(res: http.ServerResponse) { - res.statusCode = 415; - res.end(); -} - -function sendRangeNotSatisfiable(res: http.ServerResponse) { - res.statusCode = 416; - res.end(); -} - -function sendInternalServerError(res: http.ServerResponse, error: Error) { - console.error(error); - return sendContent(res, /*statusCode*/ 500, error.stack, "text/plain; charset=utf8"); -} - -function sendNotImplemented(res: http.ServerResponse) { - res.statusCode = 501; - res.end(); -} - -function shouldIgnoreCache(url: URL) { - switch (url.pathname) { - case "/built/local/bundle.js": - case "/built/local/bundle.js.map": - return true; - default: - return false; - } -} - -function isAcceptable(req: http.ServerRequest, contentType: string) { - const mediaType = parseMediaType(contentType); - return isAcceptableMediaType(req, mediaType) - && isAcceptableCharSet(req, mediaType) - && isAcceptableEncoding(req); -} - -function isAcceptableMediaType(req: http.ServerRequest, mediaType: MediaType) { - if (!req.headers.accept) return true; - const acceptedMediaType = bestMatch(mediaType, parseMediaTypes(req.headers.accept), matchesMediaType); - return acceptedMediaType ? getQuality(acceptedMediaType) > 0 : false; -} - -function isAcceptableCharSet(req: http.ServerRequest, mediaType: MediaType) { - if (!req.headers["accept-charset"]) return true; - const acceptedCharSet = bestMatch(mediaType.charset || "utf-8", parseStringsWithQuality(req.headers["accept-charset"]), matchesCharSet); - return acceptedCharSet ? getQuality(acceptedCharSet) > 0 : false; -} - -function isAcceptableEncoding(req: http.ServerRequest) { - if (!req.headers["accept-encoding"]) return true; - const acceptedEncoding = bestMatch(/*value*/ undefined, parseStringsWithQuality(req.headers["accept-encoding"]), (_, pattern) => pattern.value === "*" || pattern.value === "identity"); - return acceptedEncoding ? getQuality(acceptedEncoding) > 0 : true; -} - -function shouldSendNotModified(req: http.ServerRequest, stats: fs.Stats, etag: string) { - const ifNoneMatch = tryParseETags(req.headers["if-none-match"]); - if (ifNoneMatch) return matchesETag(etag, ifNoneMatch); - - const ifModifiedSince = tryParseDate(req.headers["if-modified-since"]); - if (ifModifiedSince) return stats.mtime.getTime() <= ifModifiedSince.getTime(); - - return false; -} - -function shouldSendPreconditionFailed(req: http.ServerRequest, stats: fs.Stats, etag: string) { - const ifMatch = tryParseETags(req.headers["if-match"]); - if (ifMatch && !matchesETag(etag, ifMatch)) return true; - - const ifUnmodifiedSince = tryParseDate(req.headers["if-unmodified-since"]); - if (ifUnmodifiedSince && stats.mtime.getTime() > ifUnmodifiedSince.getTime()) return true; - - return false; -} - -function handleGetRequest(req: http.ServerRequest, res: http.ServerResponse) { - const url = new URL(req.url, baseUrl); - if (url.pathname === "/") { - url.pathname = "/tests/webTestResults.html"; - return sendFound(res, url.toString()); - } - - const file = toServerPath(url); - fs.stat(file, (err, stats) => { - try { - if (err) { - if (err.code === "ENOENT") return sendNotFound(res); - return sendInternalServerError(res, err); - } - if (stats && stats.isFile()) { - const contentType = guessMediaType(file); - if (!isAcceptable(req, contentType)) return sendNotAcceptable(res); - - const etag = computeETag(stats); - if (shouldSendNotModified(req, stats, etag)) return sendNotModified(res); - if (shouldSendPreconditionFailed(req, stats, etag)) return sendPreconditionFailed(res); - - if (shouldIgnoreCache(url)) res.setHeader("Cache-Control", "no-store"); - res.setHeader("Last-Modified", stats.mtime.toUTCString()); - res.setHeader("ETag", etag); - res.setHeader("Content-Type", contentType); - res.setHeader("Accept-Ranges", "bytes"); - - const ranges = req.headers.range && tryParseByteRanges(req.headers.range, stats.size); - if (ranges && ranges.length === 0) return sendRangeNotSatisfiable(res); - - let start: number | undefined; - let end: number | undefined; - if (ranges && ranges.length === 1) { - start = ranges[0].start; - end = ranges[0].end; - if (start >= stats.size || end > stats.size) return sendRangeNotSatisfiable(res); - res.statusCode = 206; - res.setHeader("Content-Length", end - start); - res.setHeader("Content-Range", `bytes ${start}-${end - 1}/${stats.size}`); - } - else { - res.statusCode = 200; - res.setHeader("Content-Length", stats.size); - } - if (req.method === "HEAD") return res.end(); - const readable = fs.createReadStream(file, { start, end, autoClose: true }); - readable.on("error", err => sendInternalServerError(res, err)); - readable.pipe(res, { end: true }); - } - else { - if (req.headers["if-match"] === "*") return sendPreconditionFailed(res); - return sendNotFound(res); - } - } - catch (e) { - return sendInternalServerError(res, e); - } - }); -} - -function handlePutRequest(req: http.ServerRequest, res: http.ServerResponse) { - if (req.headers["content-encoding"]) return sendUnsupportedMediaType(res); - if (req.headers["content-range"]) return sendNotImplemented(res); - const file = toServerPath(req.url); - fs.stat(file, (err, stats) => { - try { - if (err && err.code !== "ENOENT") return sendInternalServerError(res, err); - if (stats && !stats.isFile()) return sendMethodNotAllowed(res, []); - return mkdirp(path.dirname(file), err => { - if (err) return sendInternalServerError(res, err); - try { - const writable = fs.createWriteStream(file, { autoClose: true }); - writable.on("error", err => sendInternalServerError(res, err)); - writable.on("finish", () => { - if (stats) return sendNoContent(res); - fs.stat(file, (err, stats) => { - if (err) return sendInternalServerError(res, err); - return sendCreated(res, toClientPath(file), computeETag(stats)); - }); - }); - req.pipe(writable, { end: true }); - return; - } - catch (e) { - return sendInternalServerError(res, e); - } - }); - } - catch (e) { - return sendInternalServerError(res, e); - } - }); -} - -function handleDeleteRequest(req: http.ServerRequest, res: http.ServerResponse) { - const file = toServerPath(req.url); - fs.stat(file, (err, stats) => { - try { - if (err && err.code !== "ENOENT") return sendInternalServerError(res, err); - if (!stats) return sendNotFound(res); - if (stats.isFile()) return fs.unlink(file, handleResult); - if (stats.isDirectory()) return fs.rmdir(file, handleResult); - return sendNotFound(res); - function handleResult(err: NodeJS.ErrnoException) { - if (err && err.code !== "ENOENT") return sendInternalServerError(res, err); - if (err) return sendNotFound(res); - return sendNoContent(res); - } - } - catch (e) { - return sendInternalServerError(res, e); - } - }); -} - -function handleOptionsRequest(req: http.ServerRequest, res: http.ServerResponse) { - res.setHeader("X-Case-Sensitivity", useCaseSensitiveFileNames ? "CS" : "CI"); - return sendNoContent(res); -} - -function handleApiResolve(req: http.ServerRequest, res: http.ServerResponse) { - readContent(req, (err, content) => { - try { - if (err) return sendInternalServerError(res, err); - if (!content) return sendBadRequest(res); - const serverPath = toServerPath(content); - const clientPath = toClientPath(serverPath); - if (clientPath === undefined) return sendBadRequest(res); - return sendContent(res, /*statusCode*/ 200, clientPath, /*contentType*/ "text/plain;charset=utf-8"); - } - catch (e) { - return sendInternalServerError(res, e); - } - }); -} - -function handleApiEnumerateTestFiles(req: http.ServerRequest, res: http.ServerResponse) { - readContent(req, (err, content) => { - try { - if (err) return sendInternalServerError(res, err); - if (!content) return sendBadRequest(res); - const tests: (string | FileBasedTest)[] = enumerateTestFiles(content); - return sendJson(res, /*statusCode*/ 200, tests); - } - catch (e) { - return sendInternalServerError(res, e); - } - }); -} - -function enumerateTestFiles(runner: string) { - switch (runner) { - case "conformance": - case "compiler": - return listFiles(`tests/cases/${runner}`, /*serverDirname*/ undefined, /\.tsx?$/, { recursive: true }).map(parseCompilerTestConfigurations); - case "fourslash": - return listFiles(`tests/cases/fourslash`, /*serverDirname*/ undefined, /\.ts/i, { recursive: false }); - case "fourslash-shims": - return listFiles(`tests/cases/fourslash/shims`, /*serverDirname*/ undefined, /\.ts/i, { recursive: false }); - case "fourslash-shims-pp": - return listFiles(`tests/cases/fourslash/shims-pp`, /*serverDirname*/ undefined, /\.ts/i, { recursive: false }); - case "fourslash-server": - return listFiles(`tests/cases/fourslash/server`, /*serverDirname*/ undefined, /\.ts/i, { recursive: false }); - default: - throw new Error(`Runner '${runner}' not supported in browser tests.`); - } -} - -// Regex for parsing options in the format "@Alpha: Value of any sort" -const optionRegex = /^[\/]{2}\s*@(\w+)\s*:\s*([^\r\n]*)/gm; // multiple matches on multiple lines - -function extractCompilerSettings(content: string): Record { - const opts: Record = {}; - - let match: RegExpExecArray; - while ((match = optionRegex.exec(content)) !== null) { - opts[match[1]] = match[2].trim(); - } - - return opts; -} - -function splitVaryBySettingValue(text: string): string[] | undefined { - if (!text) return undefined; - const entries = text.split(/,/).map(s => s.trim().toLowerCase()).filter(s => s.length > 0); - return entries && entries.length > 1 ? entries : undefined; -} - -function computeFileBasedTestConfigurationVariations(configurations: FileBasedTestConfiguration[], variationState: FileBasedTestConfiguration, varyByEntries: [string, string[]][], offset: number) { - if (offset >= varyByEntries.length) { - // make a copy of the current variation state - configurations.push({ ...variationState }); - return; - } - - const [varyBy, entries] = varyByEntries[offset]; - for (const entry of entries) { - // set or overwrite the variation - variationState[varyBy] = entry; - computeFileBasedTestConfigurationVariations(configurations, variationState, varyByEntries, offset + 1); - } -} - -function getFileBasedTestConfigurations(settings: Record, varyBy: string[]): FileBasedTestConfiguration[] | undefined { - let varyByEntries: [string, string[]][] | undefined; - for (const varyByKey of varyBy) { - if (Object.prototype.hasOwnProperty.call(settings, varyByKey)) { - const entries = splitVaryBySettingValue(settings[varyByKey]); - if (entries) { - if (!varyByEntries) varyByEntries = []; - varyByEntries.push([varyByKey, entries]); - } - } - } - - if (!varyByEntries) return undefined; - - const configurations: FileBasedTestConfiguration[] = []; - computeFileBasedTestConfigurationVariations(configurations, {}, varyByEntries, 0); - return configurations; -} - -function parseCompilerTestConfigurations(file: string): FileBasedTest { - const content = fs.readFileSync(path.join(rootDir, file), "utf8"); - const settings = extractCompilerSettings(content); - const configurations = getFileBasedTestConfigurations(settings, ["module", "target"]); - return { file, configurations }; -} - -function handleApiListFiles(req: http.ServerRequest, res: http.ServerResponse) { - readContent(req, (err, content) => { - try { - if (err) return sendInternalServerError(res, err); - if (!content) return sendBadRequest(res); - const serverPath = toServerPath(content); - const files = listFiles(content, serverPath, /*spec*/ undefined, { recursive: true }); - return sendJson(res, /*statusCode*/ 200, files); - } - catch (e) { - return sendInternalServerError(res, e); - } - }); -} - -function listFiles(clientDirname: string, serverDirname: string = path.resolve(rootDir, clientDirname), spec?: RegExp, options: { recursive?: boolean } = {}): string[] { - const files: string[] = []; - visit(serverDirname, clientDirname, files); - return files; - - function visit(dirname: string, relative: string, results: string[]) { - const { files, directories } = getAccessibleFileSystemEntries(dirname); - for (const file of files) { - if (!spec || file.match(spec)) { - results.push(path.join(relative, file)); - } - } - for (const directory of directories) { - if (options.recursive) { - visit(path.join(dirname, directory), path.join(relative, directory), results); - } - } - } -} - -function handleApiDirectoryExists(req: http.ServerRequest, res: http.ServerResponse) { - readContent(req, (err, content) => { - try { - if (err) return sendInternalServerError(res, err); - if (!content) return sendBadRequest(res); - const serverPath = toServerPath(content); - fs.stat(serverPath, (err, stats) => { - try { - if (err && err.code !== "ENOENT") return sendInternalServerError(res, err); - return sendJson(res, /*statusCode*/ 200, !!stats && stats.isDirectory()); - } - catch (e) { - return sendInternalServerError(res, e); - } - }); - } - catch (e) { - return sendInternalServerError(res, e); - } - }); -} - -function handleApiGetAccessibleFileSystemEntries(req: http.ServerRequest, res: http.ServerResponse) { - readContent(req, (err, content) => { - try { - if (err) return sendInternalServerError(res, err); - if (!content) return sendBadRequest(res); - const serverPath = toServerPath(content); - return sendJson(res, /*statusCode*/ 200, getAccessibleFileSystemEntries(serverPath)); - } - catch (e) { - return sendInternalServerError(res, e); - } - }); -} - -function handlePostRequest(req: http.ServerRequest, res: http.ServerResponse) { - // API responses should not be cached - res.setHeader("Cache-Control", "no-cache"); - switch (new URL(req.url, baseUrl).pathname) { - case "/api/resolve": return handleApiResolve(req, res); - case "/api/listFiles": return handleApiListFiles(req, res); - case "/api/enumerateTestFiles": return handleApiEnumerateTestFiles(req, res); - case "/api/directoryExists": return handleApiDirectoryExists(req, res); - case "/api/getAccessibleFileSystemEntries": return handleApiGetAccessibleFileSystemEntries(req, res); - default: return sendMethodNotAllowed(res, ["HEAD", "GET", "PUT", "DELETE", "OPTIONS"]); - } -} - -function handleRequest(req: http.ServerRequest, res: http.ServerResponse) { - try { - switch (req.method) { - case "HEAD": - case "GET": return handleGetRequest(req, res); - case "PUT": return handlePutRequest(req, res); - case "POST": return handlePostRequest(req, res); - case "DELETE": return handleDeleteRequest(req, res); - case "OPTIONS": return handleOptionsRequest(req, res); - default: return sendMethodNotAllowed(res, ["HEAD", "GET", "PUT", "POST", "DELETE"]); - } - } - catch (e) { - return sendInternalServerError(res, e); - } -} - -function startServer() { - console.log(`Static file server running at\n => http://localhost:${port}/\nCTRL + C to shutdown`); - return http.createServer(handleRequest).listen(port); -} - -const REG_COLUMN_PADDING = 4; - -function queryRegistryValue(keyPath: string, callback: (error: Error | null, value: string) => void) { - const args = ["query", keyPath]; - child_process.execFile("reg", ["query", keyPath, "/ve"], { encoding: "utf8" }, (error, stdout) => { - if (error) return callback(error, null); - - const valueLine = stdout.replace(/^\r\n.+?\r\n|\r\n\r\n$/g, ""); - if (!valueLine) { - return callback(new Error("Unable to retrieve value."), null); - } - - const valueNameColumnOffset = REG_COLUMN_PADDING; - if (valueLine.lastIndexOf("(Default)", valueNameColumnOffset) !== valueNameColumnOffset) { - return callback(new Error("Unable to retrieve value."), null); - } - - const dataTypeColumnOffset = valueNameColumnOffset + "(Default)".length + REG_COLUMN_PADDING; - if (valueLine.lastIndexOf("REG_SZ", dataTypeColumnOffset) !== dataTypeColumnOffset) { - return callback(new Error("Unable to retrieve value."), null); - } - - const valueColumnOffset = dataTypeColumnOffset + "REG_SZ".length + REG_COLUMN_PADDING; - const value = valueLine.slice(valueColumnOffset); - return callback(null, value); - }); -} - -interface Browser { - description: string; - command: string; -} - -function createBrowserFromPath(path: string): Browser { - return { description: path, command: path }; -} - -function getChromePath(callback: (error: Error | null, browser: Browser | string | null) => void) { - switch (os.platform()) { - case "win32": - return queryRegistryValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chrome.exe", (error, value) => { - if (error) return callback(null, "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"); - return callback(null, createBrowserFromPath(value)); - }); - case "darwin": return callback(null, "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"); - case "linux": return callback(null, "/opt/google/chrome/chrome"); - default: return callback(new Error(`Chrome location is unknown for platform '${os.platform()}'`), null); - } -} - -function getEdgePath(callback: (error: Error | null, browser: Browser | null) => void) { - switch (os.platform()) { - case "win32": return callback(null, { description: "Microsoft Edge", command: "cmd /c start microsoft-edge:%1" }); - default: return callback(new Error(`Edge location is unknown for platform '${os.platform()}'`), null); - } -} - -function getBrowserPath(callback: (error: Error | null, browser: Browser | null) => void) { - switch (browser) { - case "chrome": return getChromePath(afterGetBrowserPath); - case "edge": return getEdgePath(afterGetBrowserPath); - default: return callback(new Error(`Browser location is unknown for '${browser}'`), null); - } - - function afterGetBrowserPath(error: Error | null, browser: Browser | string | null) { - if (error) return callback(error, null); - if (typeof browser === "object") return callback(null, browser); - return fs.stat(browser, (error, stats) => { - if (!error && stats.isFile()) { - return callback(null, createBrowserFromPath(browser)); - } - if (browser === "chrome") return callback(null, createBrowserFromPath("chrome")); - return callback(new Error(`Browser location is unknown for '${browser}'`), null); - }); - } -} - -function startClient(server: http.Server) { - let browserPath: string; - if (browser === "none") { - return; - } - - getBrowserPath((error, browser) => { - if (error) return console.error(error); - console.log(`Using browser: ${browser.description}`); - const queryString = grep ? `?grep=${grep}` : ""; - const args = [`http://localhost:${port}/tests/webTestResults.html${queryString}`]; - if (browser.command.indexOf("%") === -1) { - child_process.spawn(browser.command, args); - } - else { - const command = browser.command.replace(/%(\d+)/g, (_, offset) => args[+offset - 1]); - child_process.exec(command); - } - }); -} - -function printHelp() { - console.log("Runs an http server on port 8888, looking for tests folder in the current directory\n"); - console.log("Syntax: node webTestServer.js [browser] [tests] [--verbose]\n"); - console.log("Options:"); - console.log(" The browser to launch. One of 'edge', 'chrome', or 'none' (default 'edge' on Windows, otherwise `chrome`)."); - console.log(" A regular expression to pass to Mocha."); - console.log(" --verbose Enables verbose logging."); -} - -function parseCommandLine(args: string[]) { - const parsed = minimist(args, { boolean: ["help", "verbose"] }); - if (parsed.help) { - printHelp(); - return false; - } - - if (parsed.verbose) { - verbose = true; - } - - const [parsedBrowser = defaultBrowser, parsedGrep, ...unrecognized] = parsed._; - if (parsedBrowser !== "edge" && parsedBrowser !== "chrome" && parsedBrowser !== "none") { - console.log(`Unrecognized browser '${parsedBrowser}', expected 'edge', 'chrome', or 'none'.`); - return false; - } - - if (unrecognized.length > 0) { - console.log(`Unrecognized argument: ${unrecognized[0]}`); - return false; - } - - browser = parsedBrowser; - grep = parsedGrep; - return true; -} - -function log(msg: string) { - if (verbose) { - console.log(msg); - } -} - -function main() { - if (parseCommandLine(process.argv.slice(2))) { - startClient(startServer()); - } -} - -main(); -// tslint:enable:no-null-keyword \ No newline at end of file diff --git a/tests/webTestServer.tsconfig.json b/tests/webTestServer.tsconfig.json deleted file mode 100644 index ff9fbb54bb5..00000000000 --- a/tests/webTestServer.tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "target": "es2015", - "module": "commonjs", - "declaration": false, - "removeComments": true, - "noResolve": false, - "stripInternal": false, - "sourceMap": true - }, - "files": [ - "webTestServer.ts" - ] -} diff --git a/tests/webhost/favicon-32x32.png b/tests/webhost/favicon-32x32.png deleted file mode 100644 index efbce163f92..00000000000 Binary files a/tests/webhost/favicon-32x32.png and /dev/null differ diff --git a/tests/webhost/webhost.html b/tests/webhost/webhost.html deleted file mode 100644 index 8d67918732b..00000000000 --- a/tests/webhost/webhost.html +++ /dev/null @@ -1,87 +0,0 @@ - - - WebTSC - - - - - - - -
- -
-
-

Command line:

- -

Output:

- -
-
- -
-
-
- - \ No newline at end of file diff --git a/tests/webhost/webtsc.ts b/tests/webhost/webtsc.ts deleted file mode 100644 index 3c682df6274..00000000000 --- a/tests/webhost/webtsc.ts +++ /dev/null @@ -1,104 +0,0 @@ -/// - -namespace TypeScript.WebTsc { - - declare var RealActiveXObject: { new (s: string): any }; - - function getWScriptSystem() { - const fso = new RealActiveXObject("Scripting.FileSystemObject"); - - const fileStream = new ActiveXObject("ADODB.Stream"); - fileStream.Type = 2 /*text*/; - - const args: string[] = []; - for (let i = 0; i < WScript.Arguments.length; i++) { - args[i] = WScript.Arguments.Item(i); - } - return { - args: args, - newLine: "\r\n", - write(s: string): void { - WScript.StdOut.Write(s); - }, - writeErr(s: string): void { - WScript.StdErr.Write(s); - }, - readFile(fileName: string, encoding?: string): string { - if (!fso.FileExists(fileName)) { - return undefined; - } - fileStream.Open(); - try { - if (encoding) { - fileStream.Charset = encoding; - fileStream.LoadFromFile(fileName); - } - else { - // Load file and read the first two bytes into a string with no interpretation - fileStream.Charset = "x-ansi"; - fileStream.LoadFromFile(fileName); - const bom = fileStream.ReadText(2) || ""; - // Position must be at 0 before encoding can be changed - fileStream.Position = 0; - // [0xFF,0xFE] and [0xFE,0xFF] mean utf-16 (little or big endian), otherwise default to utf-8 - fileStream.Charset = bom.length >= 2 && (bom.charCodeAt(0) === 0xFF && bom.charCodeAt(1) === 0xFE || bom.charCodeAt(0) === 0xFE && bom.charCodeAt(1) === 0xFF) ? "unicode" : "utf-8"; - } - // ReadText method always strips byte order mark from resulting string - return fileStream.ReadText(); - } - catch (e) { - throw e; - } - finally { - fileStream.Close(); - } - }, - writeFile(fileName: string, data: string): boolean { - const f = fso.CreateTextFile(fileName, true); - f.Write(data); - f.Close(); - return true; - }, - resolvePath(path: string): string { - return fso.GetAbsolutePathName(path); - }, - fileExists(path: string): boolean { - return fso.FileExists(path); - }, - directoryExists(path: string) { - return fso.FolderExists(path); - }, - createDirectory(directoryName: string) { - if (!this.directoryExists(directoryName)) { - fso.CreateFolder(directoryName); - } - }, - getExecutingFilePath() { - return WScript.ScriptFullName; - }, - getCurrentDirectory() { - return ""; - }, - getMemoryUsage() { - return 0; - }, - exit(exitCode?: number): void { - WScript.Quit(exitCode); - }, - useCaseSensitiveFileNames: false - }; - } - - export function prepareCompiler(currentDir: string, stdOut: ITextWriter, stdErr: ITextWriter) { - const shell = new RealActiveXObject("WScript.Shell"); - shell.CurrentDirectory = currentDir; - WScript.ScriptFullName = currentDir + "\\tc.js"; - WScript.StdOut = stdOut; - WScript.StdErr = stdErr; - sys = getWScriptSystem(); - - return (commandLine: string) => { - ts.executeCommandLine(commandLine.split(" ")); - }; - } -} diff --git a/tests/webhost/webtsc.tsconfig.json b/tests/webhost/webtsc.tsconfig.json deleted file mode 100644 index a30b4ceef83..00000000000 --- a/tests/webhost/webtsc.tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "target": "es2015", - "module": "commonjs", - "declaration": false, - "removeComments": true, - "noResolve": false, - "stripInternal": false, - "sourceMap": true - }, - "files": [ - "webtsc.ts" - ] -} \ No newline at end of file diff --git a/tests/webhost/wscript.js b/tests/webhost/wscript.js deleted file mode 100644 index 8cacfd4eb7d..00000000000 --- a/tests/webhost/wscript.js +++ /dev/null @@ -1,22 +0,0 @@ -var RealActiveXObject = ActiveXObject - -var WScript; -(function (WScript) { - WScript.Arguments = []; - WScript.Echo = function (str) { }; - WScript.StdErr = { - Write: function() {} - } - WScript.StdOut = { - Write: function () { }, - WriteLine: function () { } - } - - WScript.Quit = function (exitCode) { } -})(WScript || (WScript = {})); - -var ActiveXObject = (function () { - function ActiveXObject(name) { - } - return ActiveXObject; -})();