mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into dev/aozgaa/JsDocExtendsSupport
This commit is contained in:
+7
-7
@@ -19,11 +19,6 @@ tests/baselines/local/projectOutput/*
|
||||
tests/baselines/reference/testresults.tap
|
||||
tests/services/baselines/prototyping/local/*
|
||||
tests/services/browser/typescriptServices.js
|
||||
scripts/authors.js
|
||||
scripts/configureNightly.js
|
||||
scripts/processDiagnosticMessages.d.ts
|
||||
scripts/processDiagnosticMessages.js
|
||||
scripts/importDefinitelyTypedTests/importDefinitelyTypedTests.js
|
||||
src/harness/*.js
|
||||
src/compiler/diagnosticInformationMap.generated.ts
|
||||
src/compiler/diagnosticMessages.generated.json
|
||||
@@ -43,7 +38,12 @@ scripts/run.bat
|
||||
scripts/word2md.js
|
||||
scripts/buildProtocol.js
|
||||
scripts/ior.js
|
||||
scripts/buildProtocol.js
|
||||
scripts/authors.js
|
||||
scripts/configureNightly.js
|
||||
scripts/processDiagnosticMessages.d.ts
|
||||
scripts/processDiagnosticMessages.js
|
||||
scripts/importDefinitelyTypedTests/importDefinitelyTypedTests.js
|
||||
scripts/generateLocalizedDiagnosticMessages.js
|
||||
scripts/*.js.map
|
||||
scripts/typings/
|
||||
coverage/
|
||||
@@ -59,4 +59,4 @@ internal/
|
||||
.idea
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
.parallelperf.json
|
||||
.parallelperf.*
|
||||
|
||||
+2
-1
@@ -5,6 +5,7 @@ internal
|
||||
issue_template.md
|
||||
jenkins.sh
|
||||
lib/README.md
|
||||
lib/enu
|
||||
netci.groovy
|
||||
pull_request_template.md
|
||||
scripts
|
||||
@@ -16,5 +17,5 @@ Jakefile.js
|
||||
.gitattributes
|
||||
.settings/
|
||||
.travis.yml
|
||||
.vscode/
|
||||
.vscode/
|
||||
test.config
|
||||
+15
-15
@@ -1,15 +1,15 @@
|
||||
/*! *****************************************************************************
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
this file except in compliance with the License. You may obtain a copy of the
|
||||
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
MERCHANTABLITY OR NON-INFRINGEMENT.
|
||||
|
||||
See the Apache Version 2.0 License for specific language governing permissions
|
||||
and limitations under the License.
|
||||
***************************************************************************** */
|
||||
|
||||
/*! *****************************************************************************
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
this file except in compliance with the License. You may obtain a copy of the
|
||||
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
MERCHANTABLITY OR NON-INFRINGEMENT.
|
||||
|
||||
See the Apache Version 2.0 License for specific language governing permissions
|
||||
and limitations under the License.
|
||||
***************************************************************************** */
|
||||
|
||||
|
||||
+55
-14
@@ -34,6 +34,14 @@ const gulp = helpMaker(originalGulp);
|
||||
|
||||
Error.stackTraceLimit = 1000;
|
||||
|
||||
/**
|
||||
* This regexp exists to capture our const enums and replace them with normal enums in our public API
|
||||
* - this is fine since we compile with preserveConstEnums, and ensures our consumers are not locked
|
||||
* to the TS version they compile with.
|
||||
*/
|
||||
const constEnumCaptureRegexp = /^(\s*)(export )?const enum (\S+) {(\s*)$/gm;
|
||||
const constEnumReplacement = "$1$2enum $3 {$4";
|
||||
|
||||
const cmdLineOptions = minimist(process.argv.slice(2), {
|
||||
boolean: ["debug", "inspect", "light", "colors", "lint", "soft"],
|
||||
string: ["browser", "tests", "host", "reporter", "stackTraceLimit", "timeout"],
|
||||
@@ -87,6 +95,7 @@ const harnessDirectory = "src/harness/";
|
||||
const libraryDirectory = "src/lib/";
|
||||
const scriptsDirectory = "scripts/";
|
||||
const docDirectory = "doc/";
|
||||
const lclDirectory = "src/loc/lcl";
|
||||
|
||||
const builtDirectory = "built/";
|
||||
const builtLocalDirectory = "built/local/";
|
||||
@@ -260,8 +269,8 @@ function getCompilerSettings(base: tsc.Settings, useBuiltCompiler?: boolean): ts
|
||||
}
|
||||
if (!useDebugMode) {
|
||||
if (copy.removeComments === undefined) copy.removeComments = true;
|
||||
copy.newLine = "lf";
|
||||
}
|
||||
copy.newLine = "lf";
|
||||
if (useBuiltCompiler === true) {
|
||||
copy.typescript = require("./built/local/typescript.js");
|
||||
}
|
||||
@@ -367,6 +376,36 @@ gulp.task(builtGeneratedDiagnosticMessagesJSON, [diagnosticInfoMapTs], (done) =>
|
||||
|
||||
gulp.task("generate-diagnostics", "Generates a diagnostic file in TypeScript based on an input JSON file", [diagnosticInfoMapTs]);
|
||||
|
||||
// Localize diagnostics script
|
||||
const generateLocalizedDiagnosticMessagesJs = path.join(scriptsDirectory, "generateLocalizedDiagnosticMessages.js");
|
||||
const generateLocalizedDiagnosticMessagesTs = path.join(scriptsDirectory, "generateLocalizedDiagnosticMessages.ts");
|
||||
|
||||
gulp.task(generateLocalizedDiagnosticMessagesJs, /*help*/ false, [], () => {
|
||||
const settings: tsc.Settings = getCompilerSettings({
|
||||
target: "es5",
|
||||
declaration: false,
|
||||
removeComments: true,
|
||||
noResolve: false,
|
||||
stripInternal: false,
|
||||
types: ["node", "xml2js"]
|
||||
}, /*useBuiltCompiler*/ false);
|
||||
return gulp.src(generateLocalizedDiagnosticMessagesTs)
|
||||
.pipe(newer(generateLocalizedDiagnosticMessagesJs))
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(tsc(settings))
|
||||
.pipe(sourcemaps.write("."))
|
||||
.pipe(gulp.dest(scriptsDirectory));
|
||||
});
|
||||
|
||||
// Localize diagnostics
|
||||
const generatedLCGFile = path.join(builtLocalDirectory, "enu", "diagnosticMessages.generated.json.lcg");
|
||||
gulp.task(generatedLCGFile, [generateLocalizedDiagnosticMessagesJs, diagnosticInfoMapTs], (done) => {
|
||||
if (fs.existsSync(builtLocalDirectory) && needsUpdate(generatedDiagnosticMessagesJSON, generatedLCGFile)) {
|
||||
exec(host, [generateLocalizedDiagnosticMessagesJs, lclDirectory, builtLocalDirectory, generatedDiagnosticMessagesJSON], done, done);
|
||||
}
|
||||
});
|
||||
|
||||
gulp.task("localize", [generatedLCGFile]);
|
||||
|
||||
const servicesFile = path.join(builtLocalDirectory, "typescriptServices.js");
|
||||
const standaloneDefinitionsFile = path.join(builtLocalDirectory, "typescriptServices.d.ts");
|
||||
@@ -401,7 +440,7 @@ gulp.task(servicesFile, /*help*/ false, ["lib", "generate-diagnostics"], () => {
|
||||
const completedDts = dts.pipe(prependCopyright(/*outputCopyright*/ true))
|
||||
.pipe(insert.transform((contents, file) => {
|
||||
file.path = standaloneDefinitionsFile;
|
||||
return contents.replace(/^(\s*)(export )?const enum (\S+) {(\s*)$/gm, "$1$2enum $3 {$4");
|
||||
return contents.replace(constEnumCaptureRegexp, constEnumReplacement);
|
||||
}));
|
||||
return merge2([
|
||||
completedJs,
|
||||
@@ -411,7 +450,7 @@ gulp.task(servicesFile, /*help*/ false, ["lib", "generate-diagnostics"], () => {
|
||||
completedDts.pipe(clone())
|
||||
.pipe(insert.transform((content, file) => {
|
||||
file.path = nodeDefinitionsFile;
|
||||
return content + "\r\nexport = ts;";
|
||||
return content + "\nexport = ts;";
|
||||
}))
|
||||
.pipe(gulp.dest("src/services")),
|
||||
completedDts.pipe(clone())
|
||||
@@ -466,7 +505,7 @@ const tsserverLibraryFile = path.join(builtLocalDirectory, "tsserverlibrary.js")
|
||||
const tsserverLibraryDefinitionFile = path.join(builtLocalDirectory, "tsserverlibrary.d.ts");
|
||||
|
||||
gulp.task(tsserverLibraryFile, /*help*/ false, [servicesFile, typesMapJson], (done) => {
|
||||
const serverLibraryProject = tsc.createProject("src/server/tsconfig.library.json", getCompilerSettings({}, /*useBuiltCompiler*/ true));
|
||||
const serverLibraryProject = tsc.createProject("src/server/tsconfig.library.json", getCompilerSettings({ removeComments: false }, /*useBuiltCompiler*/ true));
|
||||
const {js, dts}: { js: NodeJS.ReadableStream, dts: NodeJS.ReadableStream } = serverLibraryProject.src()
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(newer(tsserverLibraryFile))
|
||||
@@ -478,7 +517,7 @@ gulp.task(tsserverLibraryFile, /*help*/ false, [servicesFile, typesMapJson], (do
|
||||
.pipe(gulp.dest("src/server")),
|
||||
dts.pipe(prependCopyright(/*outputCopyright*/ true))
|
||||
.pipe(insert.transform((content) => {
|
||||
return content + "\r\nexport = ts;\r\nexport as namespace ts;";
|
||||
return content.replace(constEnumCaptureRegexp, constEnumReplacement) + "\nexport = ts;\nexport as namespace ts;";
|
||||
}))
|
||||
.pipe(gulp.dest("src/server"))
|
||||
]);
|
||||
@@ -494,7 +533,7 @@ gulp.task(typesMapJson, /*help*/ false, [], () => {
|
||||
});
|
||||
|
||||
gulp.task("lssl", "Builds language service server library", [tsserverLibraryFile]);
|
||||
gulp.task("local", "Builds the full compiler and services", [builtLocalCompiler, servicesFile, serverFile, builtGeneratedDiagnosticMessagesJSON, tsserverLibraryFile]);
|
||||
gulp.task("local", "Builds the full compiler and services", [builtLocalCompiler, servicesFile, serverFile, builtGeneratedDiagnosticMessagesJSON, tsserverLibraryFile, "localize"]);
|
||||
gulp.task("tsc", "Builds only the compiler", [builtLocalCompiler]);
|
||||
|
||||
// Generate Markdown spec
|
||||
@@ -536,15 +575,16 @@ gulp.task("dontUseDebugMode", /*help*/ false, [], (done) => { useDebugMode = fal
|
||||
|
||||
gulp.task("VerifyLKG", /*help*/ false, [], () => {
|
||||
const expectedFiles = [builtLocalCompiler, servicesFile, serverFile, nodePackageFile, nodeDefinitionsFile, standaloneDefinitionsFile, tsserverLibraryFile, tsserverLibraryDefinitionFile, typingsInstallerJs, cancellationTokenJs].concat(libraryTargets);
|
||||
const missingFiles = expectedFiles.filter(function(f) {
|
||||
return !fs.existsSync(f);
|
||||
});
|
||||
const missingFiles = expectedFiles.
|
||||
concat(fs.readdirSync(lclDirectory).map(function (d) { return path.join(builtLocalDirectory, d, "diagnosticMessages.generated.json"); })).
|
||||
concat(generatedLCGFile).
|
||||
filter(f => !fs.existsSync(f));
|
||||
if (missingFiles.length > 0) {
|
||||
throw new Error("Cannot replace the LKG unless all built targets are present in directory " + builtLocalDirectory +
|
||||
". The following files are missing:\n" + missingFiles.join("\n"));
|
||||
}
|
||||
// Copy all the targets into the LKG directory
|
||||
return gulp.src(expectedFiles).pipe(gulp.dest(LKGDirectory));
|
||||
return gulp.src([...expectedFiles, path.join(builtLocalDirectory, "**"), `!${path.join(builtLocalDirectory, "tslint")}`, `!${path.join(builtLocalDirectory, "*.*")}`]).pipe(gulp.dest(LKGDirectory));
|
||||
});
|
||||
|
||||
gulp.task("LKGInternal", /*help*/ false, ["lib", "local"]);
|
||||
@@ -556,7 +596,7 @@ gulp.task("LKG", "Makes a new LKG out of the built js files", ["clean", "dontUse
|
||||
|
||||
// Task to build the tests infrastructure using the built compiler
|
||||
const run = path.join(builtLocalDirectory, "run.js");
|
||||
gulp.task(run, /*help*/ false, [servicesFile], () => {
|
||||
gulp.task(run, /*help*/ false, [servicesFile, tsserverLibraryFile], () => {
|
||||
const testProject = tsc.createProject("src/harness/tsconfig.json", getCompilerSettings({}, /*useBuiltCompiler*/ true));
|
||||
return testProject.src()
|
||||
.pipe(newer(run))
|
||||
@@ -978,8 +1018,9 @@ gulp.task(instrumenterJsPath, /*help*/ false, [servicesFile], () => {
|
||||
.pipe(gulp.dest(builtLocalDirectory));
|
||||
});
|
||||
|
||||
gulp.task("tsc-instrumented", "Builds an instrumented tsc.js", ["local", loggedIOJsPath, instrumenterJsPath, servicesFile], (done) => {
|
||||
exec(host, [instrumenterJsPath, "record", "iocapture", builtLocalCompiler], done, done);
|
||||
gulp.task("tsc-instrumented", "Builds an instrumented tsc.js - run with --test=[testname]", ["local", loggedIOJsPath, instrumenterJsPath, servicesFile], (done) => {
|
||||
const test = cmdLineOptions["tests"] || "iocapture";
|
||||
exec(host, [instrumenterJsPath, "record", test, builtLocalCompiler], done, done);
|
||||
});
|
||||
|
||||
gulp.task("update-sublime", "Updates the sublime plugin's tsserver", ["local", serverFile], () => {
|
||||
@@ -1050,7 +1091,7 @@ gulp.task("lint", "Runs tslint on the compiler sources. Optional arguments are:
|
||||
const fileMatcher = cmdLineOptions["files"];
|
||||
const files = fileMatcher
|
||||
? `src/**/${fileMatcher}`
|
||||
: "Gulpfile.ts 'scripts/tslint/**/*.ts' 'src/**/*.ts' --exclude src/lib/es5.d.ts --exclude 'src/lib/*.generated.d.ts'";
|
||||
: "Gulpfile.ts 'scripts/generateLocalizedDiagnosticMessages.ts' 'scripts/tslint/**/*.ts' 'src/**/*.ts' --exclude src/lib/es5.d.ts --exclude 'src/lib/*.generated.d.ts'";
|
||||
const cmd = `node node_modules/tslint/bin/tslint ${files} --formatters-dir ./built/local/tslint/formatters --format autolinkableStylish`;
|
||||
console.log("Linting: " + cmd);
|
||||
child_process.execSync(cmd, { stdio: [0, 1, 2] });
|
||||
|
||||
+58
-17
@@ -17,6 +17,7 @@ var libraryDirectory = "src/lib/";
|
||||
var scriptsDirectory = "scripts/";
|
||||
var unittestsDirectory = "src/harness/unittests/";
|
||||
var docDirectory = "doc/";
|
||||
var lclDirectory = "src/loc/lcl";
|
||||
|
||||
var builtDirectory = "built/";
|
||||
var builtLocalDirectory = "built/local/";
|
||||
@@ -93,6 +94,7 @@ var typesMapOutputPath = path.join(builtLocalDirectory, 'typesMap.json');
|
||||
var harnessCoreSources = [
|
||||
"harness.ts",
|
||||
"virtualFileSystem.ts",
|
||||
"virtualFileSystemWithWatch.ts",
|
||||
"sourceMapRecorder.ts",
|
||||
"harnessLanguageService.ts",
|
||||
"fourslash.ts",
|
||||
@@ -125,20 +127,24 @@ var harnessSources = harnessCoreSources.concat([
|
||||
"transpile.ts",
|
||||
"reuseProgramStructure.ts",
|
||||
"textStorage.ts",
|
||||
"cachingInServerLSHost.ts",
|
||||
"moduleResolution.ts",
|
||||
"tsconfigParsing.ts",
|
||||
"builder.ts",
|
||||
"commandLineParsing.ts",
|
||||
"configurationExtension.ts",
|
||||
"convertCompilerOptionsFromJson.ts",
|
||||
"convertTypeAcquisitionFromJson.ts",
|
||||
"tsserverProjectSystem.ts",
|
||||
"tscWatchMode.ts",
|
||||
"compileOnSave.ts",
|
||||
"typingsInstaller.ts",
|
||||
"projectErrors.ts",
|
||||
"matchFiles.ts",
|
||||
"initializeTSConfig.ts",
|
||||
"extractMethods.ts",
|
||||
"extractConstants.ts",
|
||||
"extractFunctions.ts",
|
||||
"extractRanges.ts",
|
||||
"extractTestHelpers.ts",
|
||||
"printer.ts",
|
||||
"textChanges.ts",
|
||||
"telemetry.ts",
|
||||
@@ -147,6 +153,7 @@ var harnessSources = harnessCoreSources.concat([
|
||||
"programMissingFiles.ts",
|
||||
"symbolWalker.ts",
|
||||
"languageService.ts",
|
||||
"publicApi.ts",
|
||||
].map(function (f) {
|
||||
return path.join(unittestsDirectory, f);
|
||||
})).concat([
|
||||
@@ -154,7 +161,6 @@ var harnessSources = harnessCoreSources.concat([
|
||||
"utilities.ts",
|
||||
"scriptVersionCache.ts",
|
||||
"scriptInfo.ts",
|
||||
"lsHost.ts",
|
||||
"project.ts",
|
||||
"typingsCache.ts",
|
||||
"editorServices.ts",
|
||||
@@ -337,9 +343,7 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts
|
||||
options += " -sourcemap";
|
||||
}
|
||||
}
|
||||
else {
|
||||
options += " --newLine LF";
|
||||
}
|
||||
options += " --newLine LF";
|
||||
|
||||
if (opts.stripInternal) {
|
||||
options += " --stripInternal";
|
||||
@@ -424,7 +428,40 @@ compileFile(processDiagnosticMessagesJs,
|
||||
[processDiagnosticMessagesTs],
|
||||
[processDiagnosticMessagesTs],
|
||||
[],
|
||||
/*useBuiltCompiler*/ false);
|
||||
/*useBuiltCompiler*/ false);
|
||||
|
||||
// Localize diagnostics script
|
||||
var generateLocalizedDiagnosticMessagesJs = path.join(scriptsDirectory, "generateLocalizedDiagnosticMessages.js");
|
||||
var generateLocalizedDiagnosticMessagesTs = path.join(scriptsDirectory, "generateLocalizedDiagnosticMessages.ts");
|
||||
|
||||
file(generateLocalizedDiagnosticMessagesTs);
|
||||
|
||||
compileFile(generateLocalizedDiagnosticMessagesJs,
|
||||
[generateLocalizedDiagnosticMessagesTs],
|
||||
[generateLocalizedDiagnosticMessagesTs],
|
||||
[],
|
||||
/*useBuiltCompiler*/ false, { noOutFile: true, types: ["node", "xml2js"] });
|
||||
|
||||
// Localize diagnostics
|
||||
var generatedLCGFile = path.join(builtLocalDirectory, "enu", "diagnosticMessages.generated.json.lcg");
|
||||
file(generatedLCGFile, [generateLocalizedDiagnosticMessagesJs, diagnosticInfoMapTs, generatedDiagnosticMessagesJSON], function () {
|
||||
var cmd = host + " " + generateLocalizedDiagnosticMessagesJs + " " + lclDirectory + " " + builtLocalDirectory + " " + generatedDiagnosticMessagesJSON;
|
||||
console.log(cmd);
|
||||
var ex = jake.createExec([cmd]);
|
||||
// Add listeners for output and error
|
||||
ex.addListener("stdout", function (output) {
|
||||
process.stdout.write(output);
|
||||
});
|
||||
ex.addListener("stderr", function (error) {
|
||||
process.stderr.write(error);
|
||||
});
|
||||
ex.addListener("cmdEnd", function () {
|
||||
complete();
|
||||
});
|
||||
ex.run();
|
||||
}, { async: true });
|
||||
|
||||
task("localize", [generatedLCGFile]);
|
||||
|
||||
var buildProtocolTs = path.join(scriptsDirectory, "buildProtocol.ts");
|
||||
var buildProtocolJs = path.join(scriptsDirectory, "buildProtocol.js");
|
||||
@@ -571,7 +608,7 @@ compileFile(servicesFile, servicesSources, [builtLocalDirectory, copyright].conc
|
||||
|
||||
// Official node package definition file, pointed to by 'typings' in package.json
|
||||
// Created by appending 'export = ts;' at the end of the standalone file to turn it into an external module
|
||||
var nodeDefinitionsFileContents = definitionFileContents + "\r\nexport = ts;";
|
||||
var nodeDefinitionsFileContents = definitionFileContents + "\nexport = ts;";
|
||||
fs.writeFileSync(nodeDefinitionsFile, nodeDefinitionsFileContents);
|
||||
|
||||
// Node package definition file to be distributed without the package. Created by replacing
|
||||
@@ -611,15 +648,15 @@ compileFile(
|
||||
[builtLocalDirectory, copyright, builtLocalCompiler].concat(languageServiceLibrarySources).concat(libraryTargets),
|
||||
/*prefixes*/[copyright],
|
||||
/*useBuiltCompiler*/ true,
|
||||
{ noOutFile: false, generateDeclarations: true, stripInternal: true, preserveConstEnums: true },
|
||||
{ noOutFile: false, generateDeclarations: true, stripInternal: true, preserveConstEnums: true, keepComments: true },
|
||||
/*callback*/ function () {
|
||||
prependFile(copyright, tsserverLibraryDefinitionFile);
|
||||
|
||||
// Appending exports at the end of the server library
|
||||
var tsserverLibraryDefinitionFileContents =
|
||||
fs.readFileSync(tsserverLibraryDefinitionFile).toString() +
|
||||
"\r\nexport = ts;" +
|
||||
"\r\nexport as namespace ts;";
|
||||
"\nexport = ts;" +
|
||||
"\nexport as namespace ts;";
|
||||
tsserverLibraryDefinitionFileContents = removeConstModifierFromEnumDeclarations(tsserverLibraryDefinitionFileContents);
|
||||
|
||||
fs.writeFileSync(tsserverLibraryDefinitionFile, tsserverLibraryDefinitionFileContents);
|
||||
@@ -641,7 +678,7 @@ task("build-fold-end", [], function () {
|
||||
|
||||
// Local target to build the compiler and services
|
||||
desc("Builds the full compiler and services");
|
||||
task("local", ["build-fold-start", "generate-diagnostics", "lib", tscFile, servicesFile, nodeDefinitionsFile, serverFile, buildProtocolDts, builtGeneratedDiagnosticMessagesJSON, "lssl", "build-fold-end"]);
|
||||
task("local", ["build-fold-start", "generate-diagnostics", "lib", tscFile, servicesFile, nodeDefinitionsFile, serverFile, buildProtocolDts, builtGeneratedDiagnosticMessagesJSON, "lssl", "localize", "build-fold-end"]);
|
||||
|
||||
// Local target to build only tsc.js
|
||||
desc("Builds only the compiler");
|
||||
@@ -696,7 +733,10 @@ task("generate-spec", [specMd]);
|
||||
// Makes a new LKG. This target does not build anything, but errors if not all the outputs are present in the built/local directory
|
||||
desc("Makes a new LKG out of the built js files");
|
||||
task("LKG", ["clean", "release", "local"].concat(libraryTargets), function () {
|
||||
var expectedFiles = [tscFile, servicesFile, serverFile, nodePackageFile, nodeDefinitionsFile, standaloneDefinitionsFile, tsserverLibraryFile, tsserverLibraryDefinitionFile, cancellationTokenFile, typingsInstallerFile, buildProtocolDts, watchGuardFile].concat(libraryTargets);
|
||||
var expectedFiles = [tscFile, servicesFile, serverFile, nodePackageFile, nodeDefinitionsFile, standaloneDefinitionsFile, tsserverLibraryFile, tsserverLibraryDefinitionFile, cancellationTokenFile, typingsInstallerFile, buildProtocolDts, watchGuardFile].
|
||||
concat(libraryTargets).
|
||||
concat(fs.readdirSync(lclDirectory).map(function (d) { return path.join(builtLocalDirectory, d) })).
|
||||
concat(path.dirname(generatedLCGFile));
|
||||
var missingFiles = expectedFiles.filter(function (f) {
|
||||
return !fs.existsSync(f);
|
||||
});
|
||||
@@ -723,7 +763,7 @@ var run = path.join(builtLocalDirectory, "run.js");
|
||||
compileFile(
|
||||
/*outFile*/ run,
|
||||
/*source*/ harnessSources,
|
||||
/*prereqs*/[builtLocalDirectory, tscFile].concat(libraryTargets).concat(servicesSources).concat(harnessSources),
|
||||
/*prereqs*/[builtLocalDirectory, tscFile, tsserverLibraryFile].concat(libraryTargets).concat(servicesSources).concat(harnessSources),
|
||||
/*prefixes*/[],
|
||||
/*useBuiltCompiler:*/ true,
|
||||
/*opts*/ { types: ["node", "mocha", "chai"], lib: "es6" });
|
||||
@@ -1104,9 +1144,10 @@ var instrumenterPath = harnessDirectory + 'instrumenter.ts';
|
||||
var instrumenterJsPath = builtLocalDirectory + 'instrumenter.js';
|
||||
compileFile(instrumenterJsPath, [instrumenterPath], [tscFile, instrumenterPath].concat(libraryTargets), [], /*useBuiltCompiler*/ true, { lib: "es6", types: ["node"], noOutFile: true, outDir: builtLocalDirectory });
|
||||
|
||||
desc("Builds an instrumented tsc.js");
|
||||
desc("Builds an instrumented tsc.js - run with test=[testname]");
|
||||
task('tsc-instrumented', [loggedIOJsPath, instrumenterJsPath, tscFile], function () {
|
||||
var cmd = host + ' ' + instrumenterJsPath + ' record iocapture ' + builtLocalDirectory + compilerFilename;
|
||||
var test = process.env.test || process.env.tests || process.env.t || "iocapture";
|
||||
var cmd = host + ' ' + instrumenterJsPath + " record " + test + " " + builtLocalDirectory + compilerFilename;
|
||||
console.log(cmd);
|
||||
var ex = jake.createExec([cmd]);
|
||||
ex.addListener("cmdEnd", function () {
|
||||
@@ -1225,7 +1266,7 @@ task("lint", ["build-rules"], () => {
|
||||
const fileMatcher = process.env.f || process.env.file || process.env.files;
|
||||
const files = fileMatcher
|
||||
? `src/**/${fileMatcher}`
|
||||
: "Gulpfile.ts 'scripts/tslint/**/*.ts' 'src/**/*.ts' --exclude src/lib/es5.d.ts --exclude 'src/lib/*.generated.d.ts'";
|
||||
: "Gulpfile.ts 'scripts/generateLocalizedDiagnosticMessages.ts' 'scripts/tslint/**/*.ts' 'src/**/*.ts' --exclude src/lib/es5.d.ts --exclude 'src/lib/*.generated.d.ts'";
|
||||
const cmd = `node node_modules/tslint/bin/tslint ${files} --formatters-dir ./built/local/tslint/formatters --format autolinkableStylish`;
|
||||
console.log("Linting: " + cmd);
|
||||
jake.exec([cmd], { interactive: true }, () => {
|
||||
|
||||
Vendored
+235
-163
File diff suppressed because it is too large
Load Diff
Vendored
+171
-110
@@ -24,11 +24,11 @@ and limitations under the License.
|
||||
/////////////////////////////
|
||||
|
||||
interface Account {
|
||||
displayName?: string;
|
||||
id?: string;
|
||||
displayName: string;
|
||||
id: string;
|
||||
imageURL?: string;
|
||||
name?: string;
|
||||
rpDisplayName?: string;
|
||||
rpDisplayName: string;
|
||||
}
|
||||
|
||||
interface Algorithm {
|
||||
@@ -55,11 +55,11 @@ interface CacheQueryOptions {
|
||||
}
|
||||
|
||||
interface ClientData {
|
||||
challenge?: string;
|
||||
challenge: string;
|
||||
extensions?: WebAuthnExtensions;
|
||||
hashAlg?: string | Algorithm;
|
||||
origin?: string;
|
||||
rpId?: string;
|
||||
hashAlg: string | Algorithm;
|
||||
origin: string;
|
||||
rpId: string;
|
||||
tokenBinding?: string;
|
||||
}
|
||||
|
||||
@@ -107,9 +107,9 @@ interface CustomEventInit extends EventInit {
|
||||
}
|
||||
|
||||
interface DeviceAccelerationDict {
|
||||
x?: number;
|
||||
y?: number;
|
||||
z?: number;
|
||||
x?: number | null;
|
||||
y?: number | null;
|
||||
z?: number | null;
|
||||
}
|
||||
|
||||
interface DeviceLightEventInit extends EventInit {
|
||||
@@ -117,30 +117,30 @@ interface DeviceLightEventInit extends EventInit {
|
||||
}
|
||||
|
||||
interface DeviceMotionEventInit extends EventInit {
|
||||
acceleration?: DeviceAccelerationDict;
|
||||
accelerationIncludingGravity?: DeviceAccelerationDict;
|
||||
interval?: number;
|
||||
rotationRate?: DeviceRotationRateDict;
|
||||
acceleration?: DeviceAccelerationDict | null;
|
||||
accelerationIncludingGravity?: DeviceAccelerationDict | null;
|
||||
interval?: number | null;
|
||||
rotationRate?: DeviceRotationRateDict | null;
|
||||
}
|
||||
|
||||
interface DeviceOrientationEventInit extends EventInit {
|
||||
absolute?: boolean;
|
||||
alpha?: number;
|
||||
beta?: number;
|
||||
gamma?: number;
|
||||
alpha?: number | null;
|
||||
beta?: number | null;
|
||||
gamma?: number | null;
|
||||
}
|
||||
|
||||
interface DeviceRotationRateDict {
|
||||
alpha?: number;
|
||||
beta?: number;
|
||||
gamma?: number;
|
||||
alpha?: number | null;
|
||||
beta?: number | null;
|
||||
gamma?: number | null;
|
||||
}
|
||||
|
||||
interface DOMRectInit {
|
||||
height?: any;
|
||||
width?: any;
|
||||
x?: any;
|
||||
y?: any;
|
||||
height?: number;
|
||||
width?: number;
|
||||
x?: number;
|
||||
y?: number;
|
||||
}
|
||||
|
||||
interface DoubleRange {
|
||||
@@ -181,15 +181,15 @@ interface EventModifierInit extends UIEventInit {
|
||||
}
|
||||
|
||||
interface ExceptionInformation {
|
||||
domain?: string;
|
||||
domain?: string | null;
|
||||
}
|
||||
|
||||
interface FocusEventInit extends UIEventInit {
|
||||
relatedTarget?: EventTarget;
|
||||
relatedTarget?: EventTarget | null;
|
||||
}
|
||||
|
||||
interface FocusNavigationEventInit extends EventInit {
|
||||
navigationReason?: string;
|
||||
navigationReason?: string | null;
|
||||
originHeight?: number;
|
||||
originLeft?: number;
|
||||
originTop?: number;
|
||||
@@ -204,7 +204,7 @@ interface FocusNavigationOrigin {
|
||||
}
|
||||
|
||||
interface GamepadEventInit extends EventInit {
|
||||
gamepad?: Gamepad;
|
||||
gamepad?: Gamepad | null;
|
||||
}
|
||||
|
||||
interface GetNotificationOptions {
|
||||
@@ -212,8 +212,8 @@ interface GetNotificationOptions {
|
||||
}
|
||||
|
||||
interface HashChangeEventInit extends EventInit {
|
||||
newURL?: string;
|
||||
oldURL?: string;
|
||||
newURL?: string | null;
|
||||
oldURL?: string | null;
|
||||
}
|
||||
|
||||
interface IDBIndexParameters {
|
||||
@@ -223,19 +223,20 @@ interface IDBIndexParameters {
|
||||
|
||||
interface IDBObjectStoreParameters {
|
||||
autoIncrement?: boolean;
|
||||
keyPath?: IDBKeyPath;
|
||||
keyPath?: IDBKeyPath | null;
|
||||
}
|
||||
|
||||
interface IntersectionObserverEntryInit {
|
||||
boundingClientRect?: DOMRectInit;
|
||||
intersectionRect?: DOMRectInit;
|
||||
rootBounds?: DOMRectInit;
|
||||
target?: Element;
|
||||
time?: number;
|
||||
isIntersecting: boolean;
|
||||
boundingClientRect: DOMRectInit;
|
||||
intersectionRect: DOMRectInit;
|
||||
rootBounds: DOMRectInit;
|
||||
target: Element;
|
||||
time: number;
|
||||
}
|
||||
|
||||
interface IntersectionObserverInit {
|
||||
root?: Element;
|
||||
root?: Element | null;
|
||||
rootMargin?: string;
|
||||
threshold?: number | number[];
|
||||
}
|
||||
@@ -257,12 +258,12 @@ interface LongRange {
|
||||
}
|
||||
|
||||
interface MediaEncryptedEventInit extends EventInit {
|
||||
initData?: ArrayBuffer;
|
||||
initData?: ArrayBuffer | null;
|
||||
initDataType?: string;
|
||||
}
|
||||
|
||||
interface MediaKeyMessageEventInit extends EventInit {
|
||||
message?: ArrayBuffer;
|
||||
message?: ArrayBuffer | null;
|
||||
messageType?: MediaKeyMessageType;
|
||||
}
|
||||
|
||||
@@ -285,7 +286,7 @@ interface MediaStreamConstraints {
|
||||
}
|
||||
|
||||
interface MediaStreamErrorEventInit extends EventInit {
|
||||
error?: MediaStreamError;
|
||||
error?: MediaStreamError | null;
|
||||
}
|
||||
|
||||
interface MediaStreamEventInit extends EventInit {
|
||||
@@ -293,7 +294,7 @@ interface MediaStreamEventInit extends EventInit {
|
||||
}
|
||||
|
||||
interface MediaStreamTrackEventInit extends EventInit {
|
||||
track?: MediaStreamTrack;
|
||||
track?: MediaStreamTrack | null;
|
||||
}
|
||||
|
||||
interface MediaTrackCapabilities {
|
||||
@@ -370,7 +371,7 @@ interface MouseEventInit extends EventModifierInit {
|
||||
buttons?: number;
|
||||
clientX?: number;
|
||||
clientY?: number;
|
||||
relatedTarget?: EventTarget;
|
||||
relatedTarget?: EventTarget | null;
|
||||
screenX?: number;
|
||||
screenY?: number;
|
||||
}
|
||||
@@ -378,8 +379,8 @@ interface MouseEventInit extends EventModifierInit {
|
||||
interface MSAccountInfo {
|
||||
accountImageUri?: string;
|
||||
accountName?: string;
|
||||
rpDisplayName?: string;
|
||||
userDisplayName?: string;
|
||||
rpDisplayName: string;
|
||||
userDisplayName: string;
|
||||
userId?: string;
|
||||
}
|
||||
|
||||
@@ -462,7 +463,7 @@ interface MSCredentialParameters {
|
||||
|
||||
interface MSCredentialSpec {
|
||||
id?: string;
|
||||
type?: MSCredentialType;
|
||||
type: MSCredentialType;
|
||||
}
|
||||
|
||||
interface MSDelay {
|
||||
@@ -672,8 +673,8 @@ interface MsZoomToOptions {
|
||||
contentX?: number;
|
||||
contentY?: number;
|
||||
scaleFactor?: number;
|
||||
viewportX?: string;
|
||||
viewportY?: string;
|
||||
viewportX?: string | null;
|
||||
viewportY?: string | null;
|
||||
}
|
||||
|
||||
interface MutationObserverInit {
|
||||
@@ -699,9 +700,9 @@ interface ObjectURLOptions {
|
||||
}
|
||||
|
||||
interface PaymentCurrencyAmount {
|
||||
currency?: string;
|
||||
currency: string;
|
||||
currencySystem?: string;
|
||||
value?: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface PaymentDetails {
|
||||
@@ -715,19 +716,19 @@ interface PaymentDetails {
|
||||
interface PaymentDetailsModifier {
|
||||
additionalDisplayItems?: PaymentItem[];
|
||||
data?: any;
|
||||
supportedMethods?: string[];
|
||||
supportedMethods: string[];
|
||||
total?: PaymentItem;
|
||||
}
|
||||
|
||||
interface PaymentItem {
|
||||
amount?: PaymentCurrencyAmount;
|
||||
label?: string;
|
||||
amount: PaymentCurrencyAmount;
|
||||
label: string;
|
||||
pending?: boolean;
|
||||
}
|
||||
|
||||
interface PaymentMethodData {
|
||||
data?: any;
|
||||
supportedMethods?: string[];
|
||||
supportedMethods: string[];
|
||||
}
|
||||
|
||||
interface PaymentOptions {
|
||||
@@ -742,9 +743,9 @@ interface PaymentRequestUpdateEventInit extends EventInit {
|
||||
}
|
||||
|
||||
interface PaymentShippingOption {
|
||||
amount?: PaymentCurrencyAmount;
|
||||
id?: string;
|
||||
label?: string;
|
||||
amount: PaymentCurrencyAmount;
|
||||
id: string;
|
||||
label: string;
|
||||
selected?: boolean;
|
||||
}
|
||||
|
||||
@@ -792,7 +793,7 @@ interface RequestInit {
|
||||
body?: any;
|
||||
cache?: RequestCache;
|
||||
credentials?: RequestCredentials;
|
||||
headers?: any;
|
||||
headers?: Headers | string[][];
|
||||
integrity?: string;
|
||||
keepalive?: boolean;
|
||||
method?: string;
|
||||
@@ -804,7 +805,7 @@ interface RequestInit {
|
||||
}
|
||||
|
||||
interface ResponseInit {
|
||||
headers?: any;
|
||||
headers?: Headers | string[][];
|
||||
status?: number;
|
||||
statusText?: string;
|
||||
}
|
||||
@@ -889,15 +890,15 @@ interface RTCIceGatherOptions {
|
||||
}
|
||||
|
||||
interface RTCIceParameters {
|
||||
iceLite?: boolean;
|
||||
iceLite?: boolean | null;
|
||||
password?: string;
|
||||
usernameFragment?: string;
|
||||
}
|
||||
|
||||
interface RTCIceServer {
|
||||
credential?: string;
|
||||
credential?: string | null;
|
||||
urls?: any;
|
||||
username?: string;
|
||||
username?: string | null;
|
||||
}
|
||||
|
||||
interface RTCInboundRTPStreamStats extends RTCRTPStreamStats {
|
||||
@@ -1107,9 +1108,9 @@ interface RTCTransportStats extends RTCStats {
|
||||
}
|
||||
|
||||
interface ScopedCredentialDescriptor {
|
||||
id?: any;
|
||||
id: any;
|
||||
transports?: Transport[];
|
||||
type?: ScopedCredentialType;
|
||||
type: ScopedCredentialType;
|
||||
}
|
||||
|
||||
interface ScopedCredentialOptions {
|
||||
@@ -1120,29 +1121,29 @@ interface ScopedCredentialOptions {
|
||||
}
|
||||
|
||||
interface ScopedCredentialParameters {
|
||||
algorithm?: string | Algorithm;
|
||||
type?: ScopedCredentialType;
|
||||
algorithm: string | Algorithm;
|
||||
type: ScopedCredentialType;
|
||||
}
|
||||
|
||||
interface ServiceWorkerMessageEventInit extends EventInit {
|
||||
data?: any;
|
||||
lastEventId?: string;
|
||||
origin?: string;
|
||||
ports?: MessagePort[];
|
||||
source?: ServiceWorker | MessagePort;
|
||||
ports?: MessagePort[] | null;
|
||||
source?: ServiceWorker | MessagePort | null;
|
||||
}
|
||||
|
||||
interface SpeechSynthesisEventInit extends EventInit {
|
||||
charIndex?: number;
|
||||
elapsedTime?: number;
|
||||
name?: string;
|
||||
utterance?: SpeechSynthesisUtterance;
|
||||
utterance?: SpeechSynthesisUtterance | null;
|
||||
}
|
||||
|
||||
interface StoreExceptionsInformation extends ExceptionInformation {
|
||||
detailURI?: string;
|
||||
explanationString?: string;
|
||||
siteName?: string;
|
||||
detailURI?: string | null;
|
||||
explanationString?: string | null;
|
||||
siteName?: string | null;
|
||||
}
|
||||
|
||||
interface StoreSiteSpecificExceptionsInformation extends StoreExceptionsInformation {
|
||||
@@ -1150,7 +1151,7 @@ interface StoreSiteSpecificExceptionsInformation extends StoreExceptionsInformat
|
||||
}
|
||||
|
||||
interface TrackEventInit extends EventInit {
|
||||
track?: VideoTrack | AudioTrack | TextTrack;
|
||||
track?: VideoTrack | AudioTrack | TextTrack | null;
|
||||
}
|
||||
|
||||
interface TransitionEventInit extends EventInit {
|
||||
@@ -1160,7 +1161,7 @@ interface TransitionEventInit extends EventInit {
|
||||
|
||||
interface UIEventInit extends EventInit {
|
||||
detail?: number;
|
||||
view?: Window;
|
||||
view?: Window | null;
|
||||
}
|
||||
|
||||
interface WebAuthnExtensions {
|
||||
@@ -1540,9 +1541,9 @@ interface Cache {
|
||||
add(request: RequestInfo): Promise<void>;
|
||||
addAll(requests: RequestInfo[]): Promise<void>;
|
||||
delete(request: RequestInfo, options?: CacheQueryOptions): Promise<boolean>;
|
||||
keys(request?: RequestInfo, options?: CacheQueryOptions): any;
|
||||
keys(request?: RequestInfo, options?: CacheQueryOptions): Promise<Request[]>;
|
||||
match(request: RequestInfo, options?: CacheQueryOptions): Promise<Response>;
|
||||
matchAll(request?: RequestInfo, options?: CacheQueryOptions): any;
|
||||
matchAll(request?: RequestInfo, options?: CacheQueryOptions): Promise<Response[]>;
|
||||
put(request: RequestInfo, response: Response): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -1554,7 +1555,7 @@ declare var Cache: {
|
||||
interface CacheStorage {
|
||||
delete(cacheName: string): Promise<boolean>;
|
||||
has(cacheName: string): Promise<boolean>;
|
||||
keys(): any;
|
||||
keys(): Promise<string[]>;
|
||||
match(request: RequestInfo, options?: CacheQueryOptions): Promise<any>;
|
||||
open(cacheName: string): Promise<Cache>;
|
||||
}
|
||||
@@ -2659,7 +2660,7 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven
|
||||
*/
|
||||
readonly compatMode: string;
|
||||
cookie: string;
|
||||
readonly currentScript: HTMLScriptElement | SVGScriptElement;
|
||||
readonly currentScript: HTMLScriptElement | SVGScriptElement | null;
|
||||
readonly defaultView: Window;
|
||||
/**
|
||||
* Sets or gets a value that indicates whether the document can be edited.
|
||||
@@ -3398,7 +3399,7 @@ interface DOMException {
|
||||
|
||||
declare var DOMException: {
|
||||
prototype: DOMException;
|
||||
new(): DOMException;
|
||||
new(message?: string, name?: string): DOMException;
|
||||
readonly ABORT_ERR: number;
|
||||
readonly DATA_CLONE_ERR: number;
|
||||
readonly DOMSTRING_SIZE_ERR: number;
|
||||
@@ -3904,7 +3905,7 @@ interface Headers {
|
||||
|
||||
declare var Headers: {
|
||||
prototype: Headers;
|
||||
new(init?: any): Headers;
|
||||
new(init?: Headers | string[][] | object): Headers;
|
||||
};
|
||||
|
||||
interface History {
|
||||
@@ -4064,7 +4065,7 @@ interface HTMLAppletElement extends HTMLElement {
|
||||
* Sets or retrieves a character string that can be used to implement your own declare functionality for the object.
|
||||
*/
|
||||
declare: boolean;
|
||||
readonly form: HTMLFormElement;
|
||||
readonly form: HTMLFormElement | null;
|
||||
/**
|
||||
* Sets or retrieves the height of the object.
|
||||
*/
|
||||
@@ -4302,7 +4303,7 @@ interface HTMLButtonElement extends HTMLElement {
|
||||
/**
|
||||
* Retrieves a reference to the form that the object is embedded in.
|
||||
*/
|
||||
readonly form: HTMLFormElement;
|
||||
readonly form: HTMLFormElement | null;
|
||||
/**
|
||||
* Overrides the action attribute (where the data on a form is sent) on the parent form element.
|
||||
*/
|
||||
@@ -4735,7 +4736,7 @@ interface HTMLFieldSetElement extends HTMLElement {
|
||||
/**
|
||||
* Retrieves a reference to the form that the object is embedded in.
|
||||
*/
|
||||
readonly form: HTMLFormElement;
|
||||
readonly form: HTMLFormElement | null;
|
||||
name: string;
|
||||
/**
|
||||
* Returns the error message that would be displayed if the user submits the form, or an empty string if no error message. It also triggers the standard error message, such as "this is a required field". The result is that the user sees validation messages without actually submitting.
|
||||
@@ -5314,7 +5315,7 @@ interface HTMLInputElement extends HTMLElement {
|
||||
/**
|
||||
* Retrieves a reference to the form that the object is embedded in.
|
||||
*/
|
||||
readonly form: HTMLFormElement;
|
||||
readonly form: HTMLFormElement | null;
|
||||
/**
|
||||
* Overrides the action attribute (where the data on a form is sent) on the parent form element.
|
||||
*/
|
||||
@@ -5481,7 +5482,7 @@ interface HTMLLabelElement extends HTMLElement {
|
||||
/**
|
||||
* Retrieves a reference to the form that the object is embedded in.
|
||||
*/
|
||||
readonly form: HTMLFormElement;
|
||||
readonly form: HTMLFormElement | null;
|
||||
/**
|
||||
* Sets or retrieves the object to which the given label object is assigned.
|
||||
*/
|
||||
@@ -5503,7 +5504,7 @@ interface HTMLLegendElement extends HTMLElement {
|
||||
/**
|
||||
* Retrieves a reference to the form that the object is embedded in.
|
||||
*/
|
||||
readonly form: HTMLFormElement;
|
||||
readonly form: HTMLFormElement | null;
|
||||
addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLLegendElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
|
||||
}
|
||||
@@ -5937,7 +5938,7 @@ interface HTMLObjectElement extends HTMLElement, GetSVGDocument {
|
||||
/**
|
||||
* Retrieves a reference to the form that the object is embedded in.
|
||||
*/
|
||||
readonly form: HTMLFormElement;
|
||||
readonly form: HTMLFormElement | null;
|
||||
/**
|
||||
* Sets or retrieves the height of the object.
|
||||
*/
|
||||
@@ -6036,7 +6037,7 @@ interface HTMLOptGroupElement extends HTMLElement {
|
||||
/**
|
||||
* Retrieves a reference to the form that the object is embedded in.
|
||||
*/
|
||||
readonly form: HTMLFormElement;
|
||||
readonly form: HTMLFormElement | null;
|
||||
/**
|
||||
* Sets or retrieves the ordinal position of an option in a list box.
|
||||
*/
|
||||
@@ -6075,7 +6076,7 @@ interface HTMLOptionElement extends HTMLElement {
|
||||
/**
|
||||
* Retrieves a reference to the form that the object is embedded in.
|
||||
*/
|
||||
readonly form: HTMLFormElement;
|
||||
readonly form: HTMLFormElement | null;
|
||||
/**
|
||||
* Sets or retrieves the ordinal position of an option in a list box.
|
||||
*/
|
||||
@@ -6119,7 +6120,7 @@ declare var HTMLOptionsCollection: {
|
||||
|
||||
interface HTMLOutputElement extends HTMLElement {
|
||||
defaultValue: string;
|
||||
readonly form: HTMLFormElement;
|
||||
readonly form: HTMLFormElement | null;
|
||||
readonly htmlFor: DOMSettableTokenList;
|
||||
name: string;
|
||||
readonly type: string;
|
||||
@@ -6208,7 +6209,7 @@ interface HTMLProgressElement extends HTMLElement {
|
||||
/**
|
||||
* Retrieves a reference to the form that the object is embedded in.
|
||||
*/
|
||||
readonly form: HTMLFormElement;
|
||||
readonly form: HTMLFormElement | null;
|
||||
/**
|
||||
* Defines the maximum, or "done" value for a progress element.
|
||||
*/
|
||||
@@ -6294,7 +6295,7 @@ interface HTMLSelectElement extends HTMLElement {
|
||||
/**
|
||||
* Retrieves a reference to the form that the object is embedded in.
|
||||
*/
|
||||
readonly form: HTMLFormElement;
|
||||
readonly form: HTMLFormElement | null;
|
||||
/**
|
||||
* Sets or retrieves the number of objects in a collection.
|
||||
*/
|
||||
@@ -6765,7 +6766,7 @@ interface HTMLTextAreaElement extends HTMLElement {
|
||||
/**
|
||||
* Retrieves a reference to the form that the object is embedded in.
|
||||
*/
|
||||
readonly form: HTMLFormElement;
|
||||
readonly form: HTMLFormElement | null;
|
||||
/**
|
||||
* Sets or retrieves the maximum number of characters that the user can enter in a text control.
|
||||
*/
|
||||
@@ -7231,6 +7232,7 @@ interface IntersectionObserverEntry {
|
||||
readonly rootBounds: ClientRect;
|
||||
readonly target: Element;
|
||||
readonly time: number;
|
||||
readonly isIntersecting: boolean;
|
||||
}
|
||||
|
||||
declare var IntersectionObserverEntry: {
|
||||
@@ -7332,7 +7334,7 @@ interface MediaDevicesEventMap {
|
||||
|
||||
interface MediaDevices extends EventTarget {
|
||||
ondevicechange: (this: MediaDevices, ev: Event) => any;
|
||||
enumerateDevices(): any;
|
||||
enumerateDevices(): Promise<MediaDeviceInfo[]>;
|
||||
getSupportedConstraints(): MediaTrackSupportedConstraints;
|
||||
getUserMedia(constraints: MediaStreamConstraints): Promise<MediaStream>;
|
||||
addEventListener<K extends keyof MediaDevicesEventMap>(type: K, listener: (this: MediaDevices, ev: MediaDevicesEventMap[K]) => any, useCapture?: boolean): void;
|
||||
@@ -9078,6 +9080,7 @@ interface Response extends Object, Body {
|
||||
readonly statusText: string;
|
||||
readonly type: ResponseType;
|
||||
readonly url: string;
|
||||
readonly redirected: boolean;
|
||||
clone(): Response;
|
||||
}
|
||||
|
||||
@@ -9531,8 +9534,8 @@ interface ServiceWorkerContainer extends EventTarget {
|
||||
oncontrollerchange: (this: ServiceWorkerContainer, ev: Event) => any;
|
||||
onmessage: (this: ServiceWorkerContainer, ev: ServiceWorkerMessageEvent) => any;
|
||||
readonly ready: Promise<ServiceWorkerRegistration>;
|
||||
getRegistration(clientURL?: USVString): Promise<any>;
|
||||
getRegistrations(): any;
|
||||
getRegistration(): Promise<ServiceWorkerRegistration | undefined>;
|
||||
getRegistrations(): Promise<ServiceWorkerRegistration[]>;
|
||||
register(scriptURL: USVString, options?: RegistrationOptions): Promise<ServiceWorkerRegistration>;
|
||||
addEventListener<K extends keyof ServiceWorkerContainerEventMap>(type: K, listener: (this: ServiceWorkerContainer, ev: ServiceWorkerContainerEventMap[K]) => any, useCapture?: boolean): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
|
||||
@@ -9568,7 +9571,7 @@ interface ServiceWorkerRegistration extends EventTarget {
|
||||
readonly scope: USVString;
|
||||
readonly sync: SyncManager;
|
||||
readonly waiting: ServiceWorker | null;
|
||||
getNotifications(filter?: GetNotificationOptions): any;
|
||||
getNotifications(filter?: GetNotificationOptions): Promise<Notification[]>;
|
||||
showNotification(title: string, options?: NotificationOptions): Promise<void>;
|
||||
unregister(): Promise<boolean>;
|
||||
update(): Promise<void>;
|
||||
@@ -11593,7 +11596,7 @@ declare var SVGZoomEvent: {
|
||||
};
|
||||
|
||||
interface SyncManager {
|
||||
getTags(): any;
|
||||
getTags(): Promise<string[]>;
|
||||
register(tag: string): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -11901,6 +11904,7 @@ interface ValidityState {
|
||||
readonly typeMismatch: boolean;
|
||||
readonly valid: boolean;
|
||||
readonly valueMissing: boolean;
|
||||
readonly tooShort: boolean;
|
||||
}
|
||||
|
||||
declare var ValidityState: {
|
||||
@@ -13762,13 +13766,13 @@ interface NavigatorUserMedia {
|
||||
|
||||
interface NodeSelector {
|
||||
querySelector<K extends keyof ElementTagNameMap>(selectors: K): ElementTagNameMap[K] | null;
|
||||
querySelector(selectors: string): Element | null;
|
||||
querySelector<E extends Element = Element>(selectors: string): E | null;
|
||||
querySelectorAll<K extends keyof ElementListTagNameMap>(selectors: K): ElementListTagNameMap[K];
|
||||
querySelectorAll(selectors: string): NodeListOf<Element>;
|
||||
querySelectorAll<E extends Element = Element>(selectors: string): NodeListOf<E>;
|
||||
}
|
||||
|
||||
interface RandomSource {
|
||||
getRandomValues(array: ArrayBufferView): ArrayBufferView;
|
||||
getRandomValues<T extends Int8Array | Uint8ClampedArray | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array>(array: T): T;
|
||||
}
|
||||
|
||||
interface SVGAnimatedPoints {
|
||||
@@ -13843,17 +13847,37 @@ interface XMLHttpRequestEventTargetEventMap {
|
||||
}
|
||||
|
||||
interface XMLHttpRequestEventTarget {
|
||||
onabort: (this: XMLHttpRequestEventTarget, ev: Event) => any;
|
||||
onerror: (this: XMLHttpRequestEventTarget, ev: ErrorEvent) => any;
|
||||
onload: (this: XMLHttpRequestEventTarget, ev: Event) => any;
|
||||
onloadend: (this: XMLHttpRequestEventTarget, ev: ProgressEvent) => any;
|
||||
onloadstart: (this: XMLHttpRequestEventTarget, ev: Event) => any;
|
||||
onprogress: (this: XMLHttpRequestEventTarget, ev: ProgressEvent) => any;
|
||||
ontimeout: (this: XMLHttpRequestEventTarget, ev: ProgressEvent) => any;
|
||||
onabort: (this: XMLHttpRequest, ev: Event) => any;
|
||||
onerror: (this: XMLHttpRequest, ev: ErrorEvent) => any;
|
||||
onload: (this: XMLHttpRequest, ev: Event) => any;
|
||||
onloadend: (this: XMLHttpRequest, ev: ProgressEvent) => any;
|
||||
onloadstart: (this: XMLHttpRequest, ev: Event) => any;
|
||||
onprogress: (this: XMLHttpRequest, ev: ProgressEvent) => any;
|
||||
ontimeout: (this: XMLHttpRequest, ev: ProgressEvent) => any;
|
||||
addEventListener<K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestEventTarget, ev: XMLHttpRequestEventTargetEventMap[K]) => any, useCapture?: boolean): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
|
||||
}
|
||||
|
||||
interface BroadcastChannel extends EventTarget {
|
||||
readonly name: string;
|
||||
onmessage: (ev: MessageEvent) => any;
|
||||
onmessageerror: (ev: MessageEvent) => any;
|
||||
close(): void;
|
||||
postMessage(message: any): void;
|
||||
addEventListener<K extends keyof BroadcastChannelEventMap>(type: K, listener: (this: BroadcastChannel, ev: BroadcastChannelEventMap[K]) => any, useCapture?: boolean): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
|
||||
}
|
||||
|
||||
declare var BroadcastChannel: {
|
||||
prototype: BroadcastChannel;
|
||||
new(name: string): BroadcastChannel;
|
||||
};
|
||||
|
||||
interface BroadcastChannelEventMap {
|
||||
message: MessageEvent;
|
||||
messageerror: MessageEvent;
|
||||
}
|
||||
|
||||
interface ErrorEventInit {
|
||||
message?: string;
|
||||
filename?: string;
|
||||
@@ -13944,8 +13968,7 @@ interface BlobPropertyBag {
|
||||
endings?: string;
|
||||
}
|
||||
|
||||
interface FilePropertyBag {
|
||||
type?: string;
|
||||
interface FilePropertyBag extends BlobPropertyBag {
|
||||
lastModified?: number;
|
||||
}
|
||||
|
||||
@@ -14221,6 +14244,44 @@ interface TouchEventInit extends EventModifierInit {
|
||||
changedTouches?: Touch[];
|
||||
}
|
||||
|
||||
interface HTMLDialogElement extends HTMLElement {
|
||||
open: boolean;
|
||||
returnValue: string;
|
||||
close(returnValue?: string): void;
|
||||
show(): void;
|
||||
showModal(): void;
|
||||
}
|
||||
|
||||
declare var HTMLDialogElement: {
|
||||
prototype: HTMLDialogElement;
|
||||
new(): HTMLDialogElement;
|
||||
};
|
||||
|
||||
interface HTMLMainElement extends HTMLElement {
|
||||
}
|
||||
|
||||
declare var HTMLMainElement: {
|
||||
prototype: HTMLMainElement;
|
||||
new(): HTMLMainElement;
|
||||
};
|
||||
|
||||
interface HTMLDetailsElement extends HTMLElement {
|
||||
open: boolean;
|
||||
}
|
||||
|
||||
declare var HTMLDetailsElement: {
|
||||
prototype: HTMLDetailsElement;
|
||||
new(): HTMLDetailsElement;
|
||||
};
|
||||
|
||||
interface HTMLSummaryElement extends HTMLElement {
|
||||
}
|
||||
|
||||
declare var HTMLSummaryElement: {
|
||||
prototype: HTMLSummaryElement;
|
||||
new(): HTMLSummaryElement;
|
||||
};
|
||||
|
||||
declare type EventListenerOrEventListenerObject = EventListener | EventListenerObject;
|
||||
|
||||
interface DecodeErrorCallback {
|
||||
@@ -14710,7 +14771,7 @@ type GLsizeiptr = number;
|
||||
type GLubyte = number;
|
||||
type GLuint = number;
|
||||
type GLushort = number;
|
||||
type HeadersInit = any;
|
||||
type HeadersInit = Headers | string[][];
|
||||
type IDBKeyPath = string;
|
||||
type KeyFormat = string;
|
||||
type KeyType = string;
|
||||
|
||||
Vendored
+7
-24
@@ -30,9 +30,7 @@ interface Array<T> {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (this: void, value: T, index: number, obj: Array<T>) => boolean): T | undefined;
|
||||
find(predicate: (this: void, value: T, index: number, obj: Array<T>) => boolean, thisArg: undefined): T | undefined;
|
||||
find<Z>(predicate: (this: Z, value: T, index: number, obj: Array<T>) => boolean, thisArg: Z): T | undefined;
|
||||
find(predicate: (value: T, index: number, obj: T[]) => boolean, thisArg?: any): T | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -43,9 +41,7 @@ interface Array<T> {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (this: void, value: T, index: number, obj: Array<T>) => boolean): number;
|
||||
findIndex(predicate: (this: void, value: T, index: number, obj: Array<T>) => boolean, thisArg: undefined): number;
|
||||
findIndex<Z>(predicate: (this: Z, value: T, index: number, obj: Array<T>) => boolean, thisArg: Z): number;
|
||||
findIndex(predicate: (value: T, index: number, obj: T[]) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Returns the this object after filling the section identified by start and end with value
|
||||
@@ -76,22 +72,13 @@ interface ArrayConstructor {
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from<T, U>(arrayLike: ArrayLike<T>, mapfn: (this: void, v: T, k: number) => U): Array<U>;
|
||||
from<T, U>(arrayLike: ArrayLike<T>, mapfn: (this: void, v: T, k: number) => U, thisArg: undefined): Array<U>;
|
||||
from<Z, T, U>(arrayLike: ArrayLike<T>, mapfn: (this: Z, v: T, k: number) => U, thisArg: Z): Array<U>;
|
||||
|
||||
|
||||
/**
|
||||
* Creates an array from an array-like object.
|
||||
* @param arrayLike An array-like object to convert to an array.
|
||||
*/
|
||||
from<T>(arrayLike: ArrayLike<T>): Array<T>;
|
||||
from<T, U = T>(arrayLike: ArrayLike<T>, mapfn?: (v: T, k: number) => U, thisArg?: any): U[];
|
||||
|
||||
/**
|
||||
* Returns a new array from a set of elements.
|
||||
* @param items A set of elements to include in the new array object.
|
||||
*/
|
||||
of<T>(...items: T[]): Array<T>;
|
||||
of<T>(...items: T[]): T[];
|
||||
}
|
||||
|
||||
interface DateConstructor {
|
||||
@@ -360,7 +347,7 @@ interface ObjectConstructor {
|
||||
* @param o Object that contains the property.
|
||||
* @param p Name of the property.
|
||||
*/
|
||||
getOwnPropertyDescriptor(o: any, propertyKey: PropertyKey): PropertyDescriptor;
|
||||
getOwnPropertyDescriptor(o: any, propertyKey: PropertyKey): PropertyDescriptor | undefined;
|
||||
|
||||
/**
|
||||
* Adds a property to an object, or modifies attributes of an existing property.
|
||||
@@ -383,9 +370,7 @@ interface ReadonlyArray<T> {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (this: void, value: T, index: number, obj: ReadonlyArray<T>) => boolean): T | undefined;
|
||||
find(predicate: (this: void, value: T, index: number, obj: ReadonlyArray<T>) => boolean, thisArg: undefined): T | undefined;
|
||||
find<Z>(predicate: (this: Z, value: T, index: number, obj: ReadonlyArray<T>) => boolean, thisArg: Z): T | undefined;
|
||||
find(predicate: (value: T, index: number, obj: ReadonlyArray<T>) => boolean, thisArg?: any): T | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -396,9 +381,7 @@ interface ReadonlyArray<T> {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (this: void, value: T, index: number, obj: Array<T>) => boolean): number;
|
||||
findIndex(predicate: (this: void, value: T, index: number, obj: Array<T>) => boolean, thisArg: undefined): number;
|
||||
findIndex<Z>(predicate: (this: Z, value: T, index: number, obj: Array<T>) => boolean, thisArg: Z): number;
|
||||
findIndex(predicate: (value: T, index: number, obj: ReadonlyArray<T>) => boolean, thisArg?: any): number;
|
||||
}
|
||||
|
||||
interface RegExp {
|
||||
|
||||
Vendored
+10
-90
@@ -74,15 +74,7 @@ interface ArrayConstructor {
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from<T, U>(iterable: Iterable<T>, mapfn: (this: void, v: T, k: number) => U): Array<U>;
|
||||
from<T, U>(iterable: Iterable<T>, mapfn: (this: void, v: T, k: number) => U, thisArg: undefined): Array<U>;
|
||||
from<Z, T, U>(iterable: Iterable<T>, mapfn: (this: Z, v: T, k: number) => U, thisArg: Z): Array<U>;
|
||||
|
||||
/**
|
||||
* Creates an array from an iterable object.
|
||||
* @param iterable An iterable object to convert to an array.
|
||||
*/
|
||||
from<T>(iterable: Iterable<T>): Array<T>;
|
||||
from<T, U = T>(iterable: Iterable<T>, mapfn?: (v: T, k: number) => U, thisArg?: any): U[];
|
||||
}
|
||||
|
||||
interface ReadonlyArray<T> {
|
||||
@@ -237,10 +229,6 @@ interface String {
|
||||
[Symbol.iterator](): IterableIterator<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit integer values. The contents are initialized to 0. If the requested
|
||||
* number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int8Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
@@ -266,17 +254,9 @@ interface Int8ArrayConstructor {
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: void, v: number, k: number) => number): Int8Array;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: void, v: number, k: number) => number, thisArg: undefined): Int8Array;
|
||||
from<Z>(arrayLike: Iterable<number>, mapfn: (this: Z, v: number, k: number) => number, thisArg: Z): Int8Array;
|
||||
|
||||
from(arrayLike: Iterable<number>): Int8Array;
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Int8Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint8Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
@@ -302,17 +282,9 @@ interface Uint8ArrayConstructor {
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: void, v: number, k: number) => number): Uint8Array;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: void, v: number, k: number) => number, thisArg: undefined): Uint8Array;
|
||||
from<Z>(arrayLike: Iterable<number>, mapfn: (this: Z, v: number, k: number) => number, thisArg: Z): Uint8Array;
|
||||
|
||||
from(arrayLike: Iterable<number>): Uint8Array;
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Uint8Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit unsigned integer (clamped) values. The contents are initialized to 0.
|
||||
* If the requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint8ClampedArray {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
@@ -341,17 +313,9 @@ interface Uint8ClampedArrayConstructor {
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: void, v: number, k: number) => number): Uint8ClampedArray;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: void, v: number, k: number) => number, thisArg: undefined): Uint8ClampedArray;
|
||||
from<Z>(arrayLike: Iterable<number>, mapfn: (this: Z, v: number, k: number) => number, thisArg: Z): Uint8ClampedArray;
|
||||
|
||||
from(arrayLike: Iterable<number>): Uint8ClampedArray;
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Uint8ClampedArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 16-bit signed integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int16Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
@@ -379,17 +343,9 @@ interface Int16ArrayConstructor {
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: void, v: number, k: number) => number): Int16Array;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: void, v: number, k: number) => number, thisArg: undefined): Int16Array;
|
||||
from<Z>(arrayLike: Iterable<number>, mapfn: (this: Z, v: number, k: number) => number, thisArg: Z): Int16Array;
|
||||
|
||||
from(arrayLike: Iterable<number>): Int16Array;
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Int16Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 16-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint16Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
@@ -415,17 +371,9 @@ interface Uint16ArrayConstructor {
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: void, v: number, k: number) => number): Uint16Array;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: void, v: number, k: number) => number, thisArg: undefined): Uint16Array;
|
||||
from<Z>(arrayLike: Iterable<number>, mapfn: (this: Z, v: number, k: number) => number, thisArg: Z): Uint16Array;
|
||||
|
||||
from(arrayLike: Iterable<number>): Uint16Array;
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Uint16Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 32-bit signed integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int32Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
@@ -451,17 +399,9 @@ interface Int32ArrayConstructor {
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: void, v: number, k: number) => number): Int32Array;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: void, v: number, k: number) => number, thisArg: undefined): Int32Array;
|
||||
from<Z>(arrayLike: Iterable<number>, mapfn: (this: Z, v: number, k: number) => number, thisArg: Z): Int32Array;
|
||||
|
||||
from(arrayLike: Iterable<number>): Int32Array;
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Int32Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 32-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint32Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
@@ -487,17 +427,9 @@ interface Uint32ArrayConstructor {
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: void, v: number, k: number) => number): Uint32Array;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: void, v: number, k: number) => number, thisArg: undefined): Uint32Array;
|
||||
from<Z>(arrayLike: Iterable<number>, mapfn: (this: Z, v: number, k: number) => number, thisArg: Z): Uint32Array;
|
||||
|
||||
from(arrayLike: Iterable<number>): Uint32Array;
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Uint32Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 32-bit float values. The contents are initialized to 0. If the requested number
|
||||
* of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Float32Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
@@ -523,17 +455,9 @@ interface Float32ArrayConstructor {
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: void, v: number, k: number) => number): Float32Array;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: void, v: number, k: number) => number, thisArg: undefined): Float32Array;
|
||||
from<Z>(arrayLike: Iterable<number>, mapfn: (this: Z, v: number, k: number) => number, thisArg: Z): Float32Array;
|
||||
|
||||
from(arrayLike: Iterable<number>): Float32Array;
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Float32Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 64-bit float values. The contents are initialized to 0. If the requested
|
||||
* number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Float64Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
@@ -559,9 +483,5 @@ interface Float64ArrayConstructor {
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: void, v: number, k: number) => number): Float64Array;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: void, v: number, k: number) => number, thisArg: undefined): Float64Array;
|
||||
from<Z>(arrayLike: Iterable<number>, mapfn: (this: Z, v: number, k: number) => number, thisArg: Z): Float64Array;
|
||||
|
||||
from(arrayLike: Iterable<number>): Float64Array;
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Float64Array;
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -24,11 +24,11 @@ declare namespace Reflect {
|
||||
function defineProperty(target: object, propertyKey: PropertyKey, attributes: PropertyDescriptor): boolean;
|
||||
function deleteProperty(target: object, propertyKey: PropertyKey): boolean;
|
||||
function get(target: object, propertyKey: PropertyKey, receiver?: any): any;
|
||||
function getOwnPropertyDescriptor(target: object, propertyKey: PropertyKey): PropertyDescriptor;
|
||||
function getOwnPropertyDescriptor(target: object, propertyKey: PropertyKey): PropertyDescriptor | undefined;
|
||||
function getPrototypeOf(target: object): object;
|
||||
function has(target: object, propertyKey: PropertyKey): boolean;
|
||||
function isExtensible(target: object): boolean;
|
||||
function ownKeys(target: object): Array<PropertyKey>;
|
||||
function ownKeys(target: object): PropertyKey[];
|
||||
function preventExtensions(target: object): boolean;
|
||||
function set(target: object, propertyKey: PropertyKey, value: any, receiver?: any): boolean;
|
||||
function setPrototypeOf(target: object, proto: any): boolean;
|
||||
|
||||
Vendored
-42
@@ -260,12 +260,6 @@ interface String {
|
||||
split(splitter: { [Symbol.split](string: string, limit?: number): string[]; }, limit?: number): string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a raw buffer of binary data, which is used to store data for the
|
||||
* different typed arrays. ArrayBuffers cannot be read from or written to directly,
|
||||
* but can be passed to a typed array or DataView Object to interpret the raw
|
||||
* buffer as needed.
|
||||
*/
|
||||
interface ArrayBuffer {
|
||||
readonly [Symbol.toStringTag]: "ArrayBuffer";
|
||||
}
|
||||
@@ -274,74 +268,38 @@ interface DataView {
|
||||
readonly [Symbol.toStringTag]: "DataView";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit integer values. The contents are initialized to 0. If the requested
|
||||
* number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int8Array {
|
||||
readonly [Symbol.toStringTag]: "Int8Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint8Array {
|
||||
readonly [Symbol.toStringTag]: "UInt8Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit unsigned integer (clamped) values. The contents are initialized to 0.
|
||||
* If the requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint8ClampedArray {
|
||||
readonly [Symbol.toStringTag]: "Uint8ClampedArray";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 16-bit signed integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int16Array {
|
||||
readonly [Symbol.toStringTag]: "Int16Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 16-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint16Array {
|
||||
readonly [Symbol.toStringTag]: "Uint16Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 32-bit signed integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int32Array {
|
||||
readonly [Symbol.toStringTag]: "Int32Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 32-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint32Array {
|
||||
readonly [Symbol.toStringTag]: "Uint32Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 32-bit float values. The contents are initialized to 0. If the requested number
|
||||
* of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Float32Array {
|
||||
readonly [Symbol.toStringTag]: "Float32Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 64-bit float values. The contents are initialized to 0. If the requested
|
||||
* number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Float64Array {
|
||||
readonly [Symbol.toStringTag]: "Float64Array";
|
||||
}
|
||||
|
||||
Vendored
+208
-275
File diff suppressed because it is too large
Load Diff
Vendored
+208
-275
File diff suppressed because it is too large
Load Diff
Vendored
+6
@@ -42,4 +42,10 @@ interface ObjectConstructor {
|
||||
* @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
|
||||
*/
|
||||
entries(o: any): [string, any][];
|
||||
|
||||
/**
|
||||
* Returns an object containing all own property descriptors of an object
|
||||
* @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
|
||||
*/
|
||||
getOwnPropertyDescriptors<T>(o: T): {[P in keyof T]: TypedPropertyDescriptor<T[P]>} & { [x: string]: PropertyDescriptor };
|
||||
}
|
||||
|
||||
Vendored
+46
-46
@@ -147,7 +147,7 @@ interface ObjectConstructor {
|
||||
* @param o Object that contains the property.
|
||||
* @param p Name of the property.
|
||||
*/
|
||||
getOwnPropertyDescriptor(o: any, p: string): PropertyDescriptor;
|
||||
getOwnPropertyDescriptor(o: any, p: string): PropertyDescriptor | undefined;
|
||||
|
||||
/**
|
||||
* Returns the names of the own properties of an object. The own properties of an object are those that are defined directly
|
||||
@@ -1597,7 +1597,7 @@ interface Int8Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
|
||||
find(predicate: (value: number, index: number, obj: Int8Array) => boolean, thisArg?: any): number | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -1608,7 +1608,7 @@ interface Int8Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (value: number, index: number, obj: Int8Array) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
@@ -1655,7 +1655,7 @@ interface Int8Array {
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
||||
* If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
map(callbackfn: (this: void, value: number, index: number, array: Int8Array) => number, thisArg?: any): Int8Array;
|
||||
map(callbackfn: (value: number, index: number, array: Int8Array) => number, thisArg?: any): Int8Array;
|
||||
|
||||
/**
|
||||
* Calls the specified callback function for all the elements in an array. The return value of
|
||||
@@ -1764,8 +1764,8 @@ interface Int8Array {
|
||||
interface Int8ArrayConstructor {
|
||||
readonly prototype: Int8Array;
|
||||
new(length: number): Int8Array;
|
||||
new(array: ArrayLike<number>): Int8Array;
|
||||
new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): Int8Array;
|
||||
new(arrayOrArrayBuffer: ArrayLike<number> | ArrayBufferLike): Int8Array;
|
||||
new(buffer: ArrayBufferLike, byteOffset: number, length?: number): Int8Array;
|
||||
|
||||
/**
|
||||
* The size in bytes of each element in the array.
|
||||
@@ -1864,7 +1864,7 @@ interface Uint8Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
|
||||
find(predicate: (value: number, index: number, obj: Uint8Array) => boolean, thisArg?: any): number | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -1875,7 +1875,7 @@ interface Uint8Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (value: number, index: number, obj: Uint8Array) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
@@ -1922,7 +1922,7 @@ interface Uint8Array {
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
||||
* If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
map(callbackfn: (this: void, value: number, index: number, array: Uint8Array) => number, thisArg?: any): Uint8Array;
|
||||
map(callbackfn: (value: number, index: number, array: Uint8Array) => number, thisArg?: any): Uint8Array;
|
||||
|
||||
/**
|
||||
* Calls the specified callback function for all the elements in an array. The return value of
|
||||
@@ -2032,8 +2032,8 @@ interface Uint8Array {
|
||||
interface Uint8ArrayConstructor {
|
||||
readonly prototype: Uint8Array;
|
||||
new(length: number): Uint8Array;
|
||||
new(array: ArrayLike<number>): Uint8Array;
|
||||
new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): Uint8Array;
|
||||
new(arrayOrArrayBuffer: ArrayLike<number> | ArrayBufferLike): Uint8Array;
|
||||
new(buffer: ArrayBufferLike, byteOffset: number, length?: number): Uint8Array;
|
||||
|
||||
/**
|
||||
* The size in bytes of each element in the array.
|
||||
@@ -2131,7 +2131,7 @@ interface Uint8ClampedArray {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
|
||||
find(predicate: (value: number, index: number, obj: Uint8ClampedArray) => boolean, thisArg?: any): number | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -2142,7 +2142,7 @@ interface Uint8ClampedArray {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (value: number, index: number, obj: Uint8ClampedArray) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
@@ -2189,7 +2189,7 @@ interface Uint8ClampedArray {
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
||||
* If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
map(callbackfn: (this: void, value: number, index: number, array: Uint8ClampedArray) => number, thisArg?: any): Uint8ClampedArray;
|
||||
map(callbackfn: (value: number, index: number, array: Uint8ClampedArray) => number, thisArg?: any): Uint8ClampedArray;
|
||||
|
||||
/**
|
||||
* Calls the specified callback function for all the elements in an array. The return value of
|
||||
@@ -2299,8 +2299,8 @@ interface Uint8ClampedArray {
|
||||
interface Uint8ClampedArrayConstructor {
|
||||
readonly prototype: Uint8ClampedArray;
|
||||
new(length: number): Uint8ClampedArray;
|
||||
new(array: ArrayLike<number>): Uint8ClampedArray;
|
||||
new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): Uint8ClampedArray;
|
||||
new(arrayOrArrayBuffer: ArrayLike<number> | ArrayBufferLike): Uint8ClampedArray;
|
||||
new(buffer: ArrayBufferLike, byteOffset: number, length?: number): Uint8ClampedArray;
|
||||
|
||||
/**
|
||||
* The size in bytes of each element in the array.
|
||||
@@ -2386,7 +2386,7 @@ interface Int16Array {
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
||||
* If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
filter(callbackfn: (this: void, value: number, index: number, array: Int16Array) => any, thisArg?: any): Int16Array;
|
||||
filter(callbackfn: (value: number, index: number, array: Int16Array) => any, thisArg?: any): Int16Array;
|
||||
|
||||
/**
|
||||
* Returns the value of the first element in the array where predicate is true, and undefined
|
||||
@@ -2397,7 +2397,7 @@ interface Int16Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
|
||||
find(predicate: (value: number, index: number, obj: Int16Array) => boolean, thisArg?: any): number | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -2408,7 +2408,7 @@ interface Int16Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (value: number, index: number, obj: Int16Array) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
@@ -2454,7 +2454,7 @@ interface Int16Array {
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
||||
* If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
map(callbackfn: (this: void, value: number, index: number, array: Int16Array) => number, thisArg?: any): Int16Array;
|
||||
map(callbackfn: (value: number, index: number, array: Int16Array) => number, thisArg?: any): Int16Array;
|
||||
|
||||
/**
|
||||
* Calls the specified callback function for all the elements in an array. The return value of
|
||||
@@ -2564,8 +2564,8 @@ interface Int16Array {
|
||||
interface Int16ArrayConstructor {
|
||||
readonly prototype: Int16Array;
|
||||
new(length: number): Int16Array;
|
||||
new(array: ArrayLike<number>): Int16Array;
|
||||
new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): Int16Array;
|
||||
new(arrayOrArrayBuffer: ArrayLike<number> | ArrayBufferLike): Int16Array;
|
||||
new(buffer: ArrayBufferLike, byteOffset: number, length?: number): Int16Array;
|
||||
|
||||
/**
|
||||
* The size in bytes of each element in the array.
|
||||
@@ -2664,7 +2664,7 @@ interface Uint16Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
|
||||
find(predicate: (value: number, index: number, obj: Uint16Array) => boolean, thisArg?: any): number | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -2675,7 +2675,7 @@ interface Uint16Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (value: number, index: number, obj: Uint16Array) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
@@ -2722,7 +2722,7 @@ interface Uint16Array {
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
||||
* If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
map(callbackfn: (this: void, value: number, index: number, array: Uint16Array) => number, thisArg?: any): Uint16Array;
|
||||
map(callbackfn: (value: number, index: number, array: Uint16Array) => number, thisArg?: any): Uint16Array;
|
||||
|
||||
/**
|
||||
* Calls the specified callback function for all the elements in an array. The return value of
|
||||
@@ -2832,8 +2832,8 @@ interface Uint16Array {
|
||||
interface Uint16ArrayConstructor {
|
||||
readonly prototype: Uint16Array;
|
||||
new(length: number): Uint16Array;
|
||||
new(array: ArrayLike<number>): Uint16Array;
|
||||
new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): Uint16Array;
|
||||
new(arrayOrArrayBuffer: ArrayLike<number> | ArrayBufferLike): Uint16Array;
|
||||
new(buffer: ArrayBufferLike, byteOffset: number, length?: number): Uint16Array;
|
||||
|
||||
/**
|
||||
* The size in bytes of each element in the array.
|
||||
@@ -2931,7 +2931,7 @@ interface Int32Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
|
||||
find(predicate: (value: number, index: number, obj: Int32Array) => boolean, thisArg?: any): number | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -2942,7 +2942,7 @@ interface Int32Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (value: number, index: number, obj: Int32Array) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
@@ -3099,8 +3099,8 @@ interface Int32Array {
|
||||
interface Int32ArrayConstructor {
|
||||
readonly prototype: Int32Array;
|
||||
new(length: number): Int32Array;
|
||||
new(array: ArrayLike<number>): Int32Array;
|
||||
new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): Int32Array;
|
||||
new(arrayOrArrayBuffer: ArrayLike<number> | ArrayBufferLike): Int32Array;
|
||||
new(buffer: ArrayBufferLike, byteOffset: number, length?: number): Int32Array;
|
||||
|
||||
/**
|
||||
* The size in bytes of each element in the array.
|
||||
@@ -3198,7 +3198,7 @@ interface Uint32Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
|
||||
find(predicate: (value: number, index: number, obj: Uint32Array) => boolean, thisArg?: any): number | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -3209,7 +3209,7 @@ interface Uint32Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (value: number, index: number, obj: Uint32Array) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
@@ -3255,7 +3255,7 @@ interface Uint32Array {
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
||||
* If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
map(callbackfn: (this: void, value: number, index: number, array: Uint32Array) => number, thisArg?: any): Uint32Array;
|
||||
map(callbackfn: (value: number, index: number, array: Uint32Array) => number, thisArg?: any): Uint32Array;
|
||||
|
||||
/**
|
||||
* Calls the specified callback function for all the elements in an array. The return value of
|
||||
@@ -3365,8 +3365,8 @@ interface Uint32Array {
|
||||
interface Uint32ArrayConstructor {
|
||||
readonly prototype: Uint32Array;
|
||||
new(length: number): Uint32Array;
|
||||
new(array: ArrayLike<number>): Uint32Array;
|
||||
new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): Uint32Array;
|
||||
new(arrayOrArrayBuffer: ArrayLike<number> | ArrayBufferLike): Uint32Array;
|
||||
new(buffer: ArrayBufferLike, byteOffset: number, length?: number): Uint32Array;
|
||||
|
||||
/**
|
||||
* The size in bytes of each element in the array.
|
||||
@@ -3464,7 +3464,7 @@ interface Float32Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
|
||||
find(predicate: (value: number, index: number, obj: Float32Array) => boolean, thisArg?: any): number | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -3475,7 +3475,7 @@ interface Float32Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (value: number, index: number, obj: Float32Array) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
@@ -3522,7 +3522,7 @@ interface Float32Array {
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
||||
* If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
map(callbackfn: (this: void, value: number, index: number, array: Float32Array) => number, thisArg?: any): Float32Array;
|
||||
map(callbackfn: (value: number, index: number, array: Float32Array) => number, thisArg?: any): Float32Array;
|
||||
|
||||
/**
|
||||
* Calls the specified callback function for all the elements in an array. The return value of
|
||||
@@ -3632,8 +3632,8 @@ interface Float32Array {
|
||||
interface Float32ArrayConstructor {
|
||||
readonly prototype: Float32Array;
|
||||
new(length: number): Float32Array;
|
||||
new(array: ArrayLike<number>): Float32Array;
|
||||
new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): Float32Array;
|
||||
new(arrayOrArrayBuffer: ArrayLike<number> | ArrayBufferLike): Float32Array;
|
||||
new(buffer: ArrayBufferLike, byteOffset: number, length?: number): Float32Array;
|
||||
|
||||
/**
|
||||
* The size in bytes of each element in the array.
|
||||
@@ -3732,7 +3732,7 @@ interface Float64Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
|
||||
find(predicate: (value: number, index: number, obj: Float64Array) => boolean, thisArg?: any): number | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -3743,7 +3743,7 @@ interface Float64Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (value: number, index: number, obj: Float64Array) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
@@ -3790,7 +3790,7 @@ interface Float64Array {
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
||||
* If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
map(callbackfn: (this: void, value: number, index: number, array: Float64Array) => number, thisArg?: any): Float64Array;
|
||||
map(callbackfn: (value: number, index: number, array: Float64Array) => number, thisArg?: any): Float64Array;
|
||||
|
||||
/**
|
||||
* Calls the specified callback function for all the elements in an array. The return value of
|
||||
@@ -3900,8 +3900,8 @@ interface Float64Array {
|
||||
interface Float64ArrayConstructor {
|
||||
readonly prototype: Float64Array;
|
||||
new(length: number): Float64Array;
|
||||
new(array: ArrayLike<number>): Float64Array;
|
||||
new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): Float64Array;
|
||||
new(arrayOrArrayBuffer: ArrayLike<number> | ArrayBufferLike): Float64Array;
|
||||
new(buffer: ArrayBufferLike, byteOffset: number, length?: number): Float64Array;
|
||||
|
||||
/**
|
||||
* The size in bytes of each element in the array.
|
||||
|
||||
Vendored
+254
-321
File diff suppressed because it is too large
Load Diff
Vendored
+208
-275
File diff suppressed because it is too large
Load Diff
Vendored
+18
-7
@@ -221,10 +221,18 @@ declare var WScript: {
|
||||
Sleep(intTime: number): void;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents an Automation SAFEARRAY
|
||||
*/
|
||||
declare class SafeArray<T = any> {
|
||||
private constructor();
|
||||
private SafeArray_typekey: SafeArray<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows enumerating over a COM collection, which may not have indexed item access.
|
||||
*/
|
||||
interface Enumerator<T> {
|
||||
interface Enumerator<T = any> {
|
||||
/**
|
||||
* Returns true if the current item is the last one in the collection, or the collection is empty,
|
||||
* or the current item is undefined.
|
||||
@@ -250,8 +258,9 @@ interface Enumerator<T> {
|
||||
}
|
||||
|
||||
interface EnumeratorConstructor {
|
||||
new <T>(collection: any): Enumerator<T>;
|
||||
new (collection: any): Enumerator<any>;
|
||||
new <T = any>(safearray: SafeArray<T>): Enumerator<T>;
|
||||
new <T = any>(collection: { Item(index: any): T }): Enumerator<T>;
|
||||
new <T = any>(collection: any): Enumerator<T>;
|
||||
}
|
||||
|
||||
declare var Enumerator: EnumeratorConstructor;
|
||||
@@ -259,7 +268,7 @@ declare var Enumerator: EnumeratorConstructor;
|
||||
/**
|
||||
* Enables reading from a COM safe array, which might have an alternate lower bound, or multiple dimensions.
|
||||
*/
|
||||
interface VBArray<T> {
|
||||
interface VBArray<T = any> {
|
||||
/**
|
||||
* Returns the number of dimensions (1-based).
|
||||
*/
|
||||
@@ -291,8 +300,7 @@ interface VBArray<T> {
|
||||
}
|
||||
|
||||
interface VBArrayConstructor {
|
||||
new <T>(safeArray: any): VBArray<T>;
|
||||
new (safeArray: any): VBArray<any>;
|
||||
new <T = any>(safeArray: SafeArray<T>): VBArray<T>;
|
||||
}
|
||||
|
||||
declare var VBArray: VBArrayConstructor;
|
||||
@@ -300,7 +308,10 @@ declare var VBArray: VBArrayConstructor;
|
||||
/**
|
||||
* Automation date (VT_DATE)
|
||||
*/
|
||||
interface VarDate { }
|
||||
declare class VarDate {
|
||||
private constructor();
|
||||
private VarDate_typekey: VarDate;
|
||||
}
|
||||
|
||||
interface DateConstructor {
|
||||
new (vd: VarDate): Date;
|
||||
|
||||
Vendored
+46
-26
@@ -57,7 +57,7 @@ interface IDBIndexParameters {
|
||||
|
||||
interface IDBObjectStoreParameters {
|
||||
autoIncrement?: boolean;
|
||||
keyPath?: IDBKeyPath;
|
||||
keyPath?: IDBKeyPath | null;
|
||||
}
|
||||
|
||||
interface KeyAlgorithm {
|
||||
@@ -94,7 +94,7 @@ interface RequestInit {
|
||||
body?: any;
|
||||
cache?: RequestCache;
|
||||
credentials?: RequestCredentials;
|
||||
headers?: any;
|
||||
headers?: Headers | string[][];
|
||||
integrity?: string;
|
||||
keepalive?: boolean;
|
||||
method?: string;
|
||||
@@ -106,7 +106,7 @@ interface RequestInit {
|
||||
}
|
||||
|
||||
interface ResponseInit {
|
||||
headers?: any;
|
||||
headers?: Headers | string[][];
|
||||
status?: number;
|
||||
statusText?: string;
|
||||
}
|
||||
@@ -123,18 +123,18 @@ interface ExtendableMessageEventInit extends ExtendableEventInit {
|
||||
data?: any;
|
||||
origin?: string;
|
||||
lastEventId?: string;
|
||||
source?: Client | ServiceWorker | MessagePort;
|
||||
ports?: MessagePort[];
|
||||
source?: Client | ServiceWorker | MessagePort | null;
|
||||
ports?: MessagePort[] | null;
|
||||
}
|
||||
|
||||
interface FetchEventInit extends ExtendableEventInit {
|
||||
request?: Request;
|
||||
clientId?: string;
|
||||
request: Request;
|
||||
clientId?: string | null;
|
||||
isReload?: boolean;
|
||||
}
|
||||
|
||||
interface NotificationEventInit extends ExtendableEventInit {
|
||||
notification?: Notification;
|
||||
notification: Notification;
|
||||
action?: string;
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ interface PushEventInit extends ExtendableEventInit {
|
||||
}
|
||||
|
||||
interface SyncEventInit extends ExtendableEventInit {
|
||||
tag?: string;
|
||||
tag: string;
|
||||
lastChance?: boolean;
|
||||
}
|
||||
|
||||
@@ -195,9 +195,9 @@ interface Cache {
|
||||
add(request: RequestInfo): Promise<void>;
|
||||
addAll(requests: RequestInfo[]): Promise<void>;
|
||||
delete(request: RequestInfo, options?: CacheQueryOptions): Promise<boolean>;
|
||||
keys(request?: RequestInfo, options?: CacheQueryOptions): any;
|
||||
keys(request?: RequestInfo, options?: CacheQueryOptions): Promise<Request[]>;
|
||||
match(request: RequestInfo, options?: CacheQueryOptions): Promise<Response>;
|
||||
matchAll(request?: RequestInfo, options?: CacheQueryOptions): any;
|
||||
matchAll(request?: RequestInfo, options?: CacheQueryOptions): Promise<Response[]>;
|
||||
put(request: RequestInfo, response: Response): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ declare var Cache: {
|
||||
interface CacheStorage {
|
||||
delete(cacheName: string): Promise<boolean>;
|
||||
has(cacheName: string): Promise<boolean>;
|
||||
keys(): any;
|
||||
keys(): Promise<string[]>;
|
||||
match(request: RequestInfo, options?: CacheQueryOptions): Promise<any>;
|
||||
open(cacheName: string): Promise<Cache>;
|
||||
}
|
||||
@@ -334,7 +334,7 @@ interface DOMException {
|
||||
|
||||
declare var DOMException: {
|
||||
prototype: DOMException;
|
||||
new(): DOMException;
|
||||
new(message?: string, name?: string): DOMException;
|
||||
readonly ABORT_ERR: number;
|
||||
readonly DATA_CLONE_ERR: number;
|
||||
readonly DOMSTRING_SIZE_ERR: number;
|
||||
@@ -490,7 +490,7 @@ interface Headers {
|
||||
|
||||
declare var Headers: {
|
||||
prototype: Headers;
|
||||
new(init?: any): Headers;
|
||||
new(init?: Headers | string[][] | object): Headers;
|
||||
};
|
||||
|
||||
interface IDBCursor {
|
||||
@@ -980,6 +980,7 @@ interface Response extends Object, Body {
|
||||
readonly statusText: string;
|
||||
readonly type: ResponseType;
|
||||
readonly url: string;
|
||||
readonly redirected: boolean;
|
||||
clone(): Response;
|
||||
}
|
||||
|
||||
@@ -1020,7 +1021,7 @@ interface ServiceWorkerRegistration extends EventTarget {
|
||||
readonly scope: USVString;
|
||||
readonly sync: SyncManager;
|
||||
readonly waiting: ServiceWorker | null;
|
||||
getNotifications(filter?: GetNotificationOptions): any;
|
||||
getNotifications(filter?: GetNotificationOptions): Promise<Notification[]>;
|
||||
showNotification(title: string, options?: NotificationOptions): Promise<void>;
|
||||
unregister(): Promise<boolean>;
|
||||
update(): Promise<void>;
|
||||
@@ -1034,7 +1035,7 @@ declare var ServiceWorkerRegistration: {
|
||||
};
|
||||
|
||||
interface SyncManager {
|
||||
getTags(): any;
|
||||
getTags(): Promise<string[]>;
|
||||
register(tag: string): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -1268,13 +1269,13 @@ interface XMLHttpRequestEventTargetEventMap {
|
||||
}
|
||||
|
||||
interface XMLHttpRequestEventTarget {
|
||||
onabort: (this: XMLHttpRequestEventTarget, ev: Event) => any;
|
||||
onerror: (this: XMLHttpRequestEventTarget, ev: ErrorEvent) => any;
|
||||
onload: (this: XMLHttpRequestEventTarget, ev: Event) => any;
|
||||
onloadend: (this: XMLHttpRequestEventTarget, ev: ProgressEvent) => any;
|
||||
onloadstart: (this: XMLHttpRequestEventTarget, ev: Event) => any;
|
||||
onprogress: (this: XMLHttpRequestEventTarget, ev: ProgressEvent) => any;
|
||||
ontimeout: (this: XMLHttpRequestEventTarget, ev: ProgressEvent) => any;
|
||||
onabort: (this: XMLHttpRequest, ev: Event) => any;
|
||||
onerror: (this: XMLHttpRequest, ev: ErrorEvent) => any;
|
||||
onload: (this: XMLHttpRequest, ev: Event) => any;
|
||||
onloadend: (this: XMLHttpRequest, ev: ProgressEvent) => any;
|
||||
onloadstart: (this: XMLHttpRequest, ev: Event) => any;
|
||||
onprogress: (this: XMLHttpRequest, ev: ProgressEvent) => any;
|
||||
ontimeout: (this: XMLHttpRequest, ev: ProgressEvent) => any;
|
||||
addEventListener<K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestEventTarget, ev: XMLHttpRequestEventTargetEventMap[K]) => any, useCapture?: boolean): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
|
||||
}
|
||||
@@ -1294,7 +1295,7 @@ declare var Client: {
|
||||
interface Clients {
|
||||
claim(): Promise<void>;
|
||||
get(id: string): Promise<any>;
|
||||
matchAll(options?: ClientQueryOptions): any;
|
||||
matchAll(options?: ClientQueryOptions): Promise<Client[]>;
|
||||
openWindow(url: USVString): Promise<WindowClient>;
|
||||
}
|
||||
|
||||
@@ -1519,6 +1520,26 @@ interface WorkerUtils extends Object, WindowBase64 {
|
||||
setTimeout(handler: any, timeout?: any, ...args: any[]): number;
|
||||
}
|
||||
|
||||
interface BroadcastChannel extends EventTarget {
|
||||
readonly name: string;
|
||||
onmessage: (ev: MessageEvent) => any;
|
||||
onmessageerror: (ev: MessageEvent) => any;
|
||||
close(): void;
|
||||
postMessage(message: any): void;
|
||||
addEventListener<K extends keyof BroadcastChannelEventMap>(type: K, listener: (this: BroadcastChannel, ev: BroadcastChannelEventMap[K]) => any, useCapture?: boolean): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
|
||||
}
|
||||
|
||||
declare var BroadcastChannel: {
|
||||
prototype: BroadcastChannel;
|
||||
new(name: string): BroadcastChannel;
|
||||
};
|
||||
|
||||
interface BroadcastChannelEventMap {
|
||||
message: MessageEvent;
|
||||
messageerror: MessageEvent;
|
||||
}
|
||||
|
||||
interface ErrorEventInit {
|
||||
message?: string;
|
||||
filename?: string;
|
||||
@@ -1582,8 +1603,7 @@ interface BlobPropertyBag {
|
||||
endings?: string;
|
||||
}
|
||||
|
||||
interface FilePropertyBag {
|
||||
type?: string;
|
||||
interface FilePropertyBag extends BlobPropertyBag {
|
||||
lastModified?: number;
|
||||
}
|
||||
|
||||
|
||||
+1632
-1290
File diff suppressed because it is too large
Load Diff
+2750
-2043
File diff suppressed because it is too large
Load Diff
Vendored
+120
-79
@@ -435,6 +435,9 @@ declare namespace ts {
|
||||
modifiers?: ModifiersArray;
|
||||
parent?: Node;
|
||||
}
|
||||
interface JSDocContainer {
|
||||
}
|
||||
type HasJSDoc = ParameterDeclaration | CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignature | PropertySignature | ArrowFunction | ParenthesizedExpression | SpreadAssignment | ShorthandPropertyAssignment | PropertyAssignment | FunctionExpression | LabeledStatement | ExpressionStatement | VariableStatement | FunctionDeclaration | ConstructorDeclaration | MethodDeclaration | PropertyDeclaration | AccessorDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumMember | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | EndOfFileToken;
|
||||
interface NodeArray<T extends Node> extends ReadonlyArray<T>, TextRange {
|
||||
hasTrailingComma?: boolean;
|
||||
}
|
||||
@@ -447,7 +450,7 @@ declare namespace ts {
|
||||
type EqualsToken = Token<SyntaxKind.EqualsToken>;
|
||||
type AsteriskToken = Token<SyntaxKind.AsteriskToken>;
|
||||
type EqualsGreaterThanToken = Token<SyntaxKind.EqualsGreaterThanToken>;
|
||||
type EndOfFileToken = Token<SyntaxKind.EndOfFileToken>;
|
||||
type EndOfFileToken = Token<SyntaxKind.EndOfFileToken> & JSDocContainer;
|
||||
type AtToken = Token<SyntaxKind.AtToken>;
|
||||
type ReadonlyToken = Token<SyntaxKind.ReadonlyKeyword>;
|
||||
type AwaitKeywordToken = Token<SyntaxKind.AwaitKeyword>;
|
||||
@@ -485,6 +488,7 @@ declare namespace ts {
|
||||
}
|
||||
interface Decorator extends Node {
|
||||
kind: SyntaxKind.Decorator;
|
||||
parent?: NamedDeclaration;
|
||||
expression: LeftHandSideExpression;
|
||||
}
|
||||
interface TypeParameterDeclaration extends NamedDeclaration {
|
||||
@@ -495,16 +499,18 @@ declare namespace ts {
|
||||
default?: TypeNode;
|
||||
expression?: Expression;
|
||||
}
|
||||
interface SignatureDeclaration extends NamedDeclaration {
|
||||
interface SignatureDeclarationBase extends NamedDeclaration, JSDocContainer {
|
||||
kind: SignatureDeclaration["kind"];
|
||||
name?: PropertyName;
|
||||
typeParameters?: NodeArray<TypeParameterDeclaration>;
|
||||
parameters: NodeArray<ParameterDeclaration>;
|
||||
type?: TypeNode;
|
||||
type: TypeNode | undefined;
|
||||
}
|
||||
interface CallSignatureDeclaration extends SignatureDeclaration, TypeElement {
|
||||
type SignatureDeclaration = CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignature | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | AccessorDeclaration | FunctionExpression | ArrowFunction;
|
||||
interface CallSignatureDeclaration extends SignatureDeclarationBase, TypeElement {
|
||||
kind: SyntaxKind.CallSignature;
|
||||
}
|
||||
interface ConstructSignatureDeclaration extends SignatureDeclaration, TypeElement {
|
||||
interface ConstructSignatureDeclaration extends SignatureDeclarationBase, TypeElement {
|
||||
kind: SyntaxKind.ConstructSignature;
|
||||
}
|
||||
type BindingName = Identifier | BindingPattern;
|
||||
@@ -520,7 +526,7 @@ declare namespace ts {
|
||||
parent?: VariableStatement | ForStatement | ForOfStatement | ForInStatement;
|
||||
declarations: NodeArray<VariableDeclaration>;
|
||||
}
|
||||
interface ParameterDeclaration extends NamedDeclaration {
|
||||
interface ParameterDeclaration extends NamedDeclaration, JSDocContainer {
|
||||
kind: SyntaxKind.Parameter;
|
||||
parent?: SignatureDeclaration;
|
||||
dotDotDotToken?: DotDotDotToken;
|
||||
@@ -537,14 +543,14 @@ declare namespace ts {
|
||||
name: BindingName;
|
||||
initializer?: Expression;
|
||||
}
|
||||
interface PropertySignature extends TypeElement {
|
||||
interface PropertySignature extends TypeElement, JSDocContainer {
|
||||
kind: SyntaxKind.PropertySignature;
|
||||
name: PropertyName;
|
||||
questionToken?: QuestionToken;
|
||||
type?: TypeNode;
|
||||
initializer?: Expression;
|
||||
}
|
||||
interface PropertyDeclaration extends ClassElement {
|
||||
interface PropertyDeclaration extends ClassElement, JSDocContainer {
|
||||
kind: SyntaxKind.PropertyDeclaration;
|
||||
questionToken?: QuestionToken;
|
||||
name: PropertyName;
|
||||
@@ -556,27 +562,30 @@ declare namespace ts {
|
||||
name?: PropertyName;
|
||||
}
|
||||
type ObjectLiteralElementLike = PropertyAssignment | ShorthandPropertyAssignment | SpreadAssignment | MethodDeclaration | AccessorDeclaration;
|
||||
interface PropertyAssignment extends ObjectLiteralElement {
|
||||
interface PropertyAssignment extends ObjectLiteralElement, JSDocContainer {
|
||||
parent: ObjectLiteralExpression;
|
||||
kind: SyntaxKind.PropertyAssignment;
|
||||
name: PropertyName;
|
||||
questionToken?: QuestionToken;
|
||||
initializer: Expression;
|
||||
}
|
||||
interface ShorthandPropertyAssignment extends ObjectLiteralElement {
|
||||
interface ShorthandPropertyAssignment extends ObjectLiteralElement, JSDocContainer {
|
||||
parent: ObjectLiteralExpression;
|
||||
kind: SyntaxKind.ShorthandPropertyAssignment;
|
||||
name: Identifier;
|
||||
questionToken?: QuestionToken;
|
||||
equalsToken?: Token<SyntaxKind.EqualsToken>;
|
||||
objectAssignmentInitializer?: Expression;
|
||||
}
|
||||
interface SpreadAssignment extends ObjectLiteralElement {
|
||||
interface SpreadAssignment extends ObjectLiteralElement, JSDocContainer {
|
||||
parent: ObjectLiteralExpression;
|
||||
kind: SyntaxKind.SpreadAssignment;
|
||||
expression: Expression;
|
||||
}
|
||||
interface VariableLikeDeclaration extends NamedDeclaration {
|
||||
propertyName?: PropertyName;
|
||||
dotDotDotToken?: DotDotDotToken;
|
||||
name?: DeclarationName;
|
||||
name: DeclarationName;
|
||||
questionToken?: QuestionToken;
|
||||
type?: TypeNode;
|
||||
initializer?: Expression;
|
||||
@@ -596,7 +605,7 @@ declare namespace ts {
|
||||
}
|
||||
type BindingPattern = ObjectBindingPattern | ArrayBindingPattern;
|
||||
type ArrayBindingElement = BindingElement | OmittedExpression;
|
||||
interface FunctionLikeDeclarationBase extends SignatureDeclaration {
|
||||
interface FunctionLikeDeclarationBase extends SignatureDeclarationBase {
|
||||
_functionLikeDeclarationBrand: any;
|
||||
asteriskToken?: AsteriskToken;
|
||||
questionToken?: QuestionToken;
|
||||
@@ -609,16 +618,16 @@ declare namespace ts {
|
||||
name?: Identifier;
|
||||
body?: FunctionBody;
|
||||
}
|
||||
interface MethodSignature extends SignatureDeclaration, TypeElement {
|
||||
interface MethodSignature extends SignatureDeclarationBase, TypeElement {
|
||||
kind: SyntaxKind.MethodSignature;
|
||||
name: PropertyName;
|
||||
}
|
||||
interface MethodDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement {
|
||||
interface MethodDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
|
||||
kind: SyntaxKind.MethodDeclaration;
|
||||
name: PropertyName;
|
||||
body?: FunctionBody;
|
||||
}
|
||||
interface ConstructorDeclaration extends FunctionLikeDeclarationBase, ClassElement {
|
||||
interface ConstructorDeclaration extends FunctionLikeDeclarationBase, ClassElement, JSDocContainer {
|
||||
kind: SyntaxKind.Constructor;
|
||||
parent?: ClassDeclaration | ClassExpression;
|
||||
body?: FunctionBody;
|
||||
@@ -627,20 +636,20 @@ declare namespace ts {
|
||||
kind: SyntaxKind.SemicolonClassElement;
|
||||
parent?: ClassDeclaration | ClassExpression;
|
||||
}
|
||||
interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement {
|
||||
interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
|
||||
kind: SyntaxKind.GetAccessor;
|
||||
parent?: ClassDeclaration | ClassExpression | ObjectLiteralExpression;
|
||||
name: PropertyName;
|
||||
body: FunctionBody;
|
||||
}
|
||||
interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement {
|
||||
interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
|
||||
kind: SyntaxKind.SetAccessor;
|
||||
parent?: ClassDeclaration | ClassExpression | ObjectLiteralExpression;
|
||||
name: PropertyName;
|
||||
body: FunctionBody;
|
||||
}
|
||||
type AccessorDeclaration = GetAccessorDeclaration | SetAccessorDeclaration;
|
||||
interface IndexSignatureDeclaration extends SignatureDeclaration, ClassElement, TypeElement {
|
||||
interface IndexSignatureDeclaration extends SignatureDeclarationBase, ClassElement, TypeElement {
|
||||
kind: SyntaxKind.IndexSignature;
|
||||
parent?: ClassDeclaration | ClassExpression | InterfaceDeclaration | TypeLiteralNode;
|
||||
}
|
||||
@@ -654,10 +663,10 @@ declare namespace ts {
|
||||
kind: SyntaxKind.ThisType;
|
||||
}
|
||||
type FunctionOrConstructorTypeNode = FunctionTypeNode | ConstructorTypeNode;
|
||||
interface FunctionTypeNode extends TypeNode, SignatureDeclaration {
|
||||
interface FunctionTypeNode extends TypeNode, SignatureDeclarationBase {
|
||||
kind: SyntaxKind.FunctionType;
|
||||
}
|
||||
interface ConstructorTypeNode extends TypeNode, SignatureDeclaration {
|
||||
interface ConstructorTypeNode extends TypeNode, SignatureDeclarationBase {
|
||||
kind: SyntaxKind.ConstructorType;
|
||||
}
|
||||
type TypeReferenceType = TypeReferenceNode | ExpressionWithTypeArguments;
|
||||
@@ -668,6 +677,7 @@ declare namespace ts {
|
||||
}
|
||||
interface TypePredicateNode extends TypeNode {
|
||||
kind: SyntaxKind.TypePredicate;
|
||||
parent?: SignatureDeclaration;
|
||||
parameterName: Identifier | ThisTypeNode;
|
||||
type: TypeNode;
|
||||
}
|
||||
@@ -712,7 +722,6 @@ declare namespace ts {
|
||||
}
|
||||
interface MappedTypeNode extends TypeNode, Declaration {
|
||||
kind: SyntaxKind.MappedType;
|
||||
parent?: TypeAliasDeclaration;
|
||||
readonlyToken?: ReadonlyToken;
|
||||
typeParameter: TypeParameterDeclaration;
|
||||
questionToken?: QuestionToken;
|
||||
@@ -720,7 +729,7 @@ declare namespace ts {
|
||||
}
|
||||
interface LiteralTypeNode extends TypeNode {
|
||||
kind: SyntaxKind.LiteralType;
|
||||
literal: Expression;
|
||||
literal: BooleanLiteral | LiteralExpression | PrefixUnaryExpression;
|
||||
}
|
||||
interface StringLiteral extends LiteralExpression {
|
||||
kind: SyntaxKind.StringLiteral;
|
||||
@@ -854,12 +863,12 @@ declare namespace ts {
|
||||
}
|
||||
type FunctionBody = Block;
|
||||
type ConciseBody = FunctionBody | Expression;
|
||||
interface FunctionExpression extends PrimaryExpression, FunctionLikeDeclarationBase {
|
||||
interface FunctionExpression extends PrimaryExpression, FunctionLikeDeclarationBase, JSDocContainer {
|
||||
kind: SyntaxKind.FunctionExpression;
|
||||
name?: Identifier;
|
||||
body: FunctionBody;
|
||||
}
|
||||
interface ArrowFunction extends Expression, FunctionLikeDeclarationBase {
|
||||
interface ArrowFunction extends Expression, FunctionLikeDeclarationBase, JSDocContainer {
|
||||
kind: SyntaxKind.ArrowFunction;
|
||||
equalsGreaterThanToken: EqualsGreaterThanToken;
|
||||
body: ConciseBody;
|
||||
@@ -905,7 +914,7 @@ declare namespace ts {
|
||||
expression: Expression;
|
||||
literal: TemplateMiddle | TemplateTail;
|
||||
}
|
||||
interface ParenthesizedExpression extends PrimaryExpression {
|
||||
interface ParenthesizedExpression extends PrimaryExpression, JSDocContainer {
|
||||
kind: SyntaxKind.ParenthesizedExpression;
|
||||
expression: Expression;
|
||||
}
|
||||
@@ -915,6 +924,7 @@ declare namespace ts {
|
||||
}
|
||||
interface SpreadElement extends Expression {
|
||||
kind: SyntaxKind.SpreadElement;
|
||||
parent?: ArrayLiteralExpression | CallExpression | NewExpression;
|
||||
expression: Expression;
|
||||
}
|
||||
interface ObjectLiteralExpressionBase<T extends ObjectLiteralElement> extends PrimaryExpression, Declaration {
|
||||
@@ -1072,11 +1082,11 @@ declare namespace ts {
|
||||
kind: SyntaxKind.Block;
|
||||
statements: NodeArray<Statement>;
|
||||
}
|
||||
interface VariableStatement extends Statement {
|
||||
interface VariableStatement extends Statement, JSDocContainer {
|
||||
kind: SyntaxKind.VariableStatement;
|
||||
declarationList: VariableDeclarationList;
|
||||
}
|
||||
interface ExpressionStatement extends Statement {
|
||||
interface ExpressionStatement extends Statement, JSDocContainer {
|
||||
kind: SyntaxKind.ExpressionStatement;
|
||||
expression: Expression;
|
||||
}
|
||||
@@ -1157,7 +1167,7 @@ declare namespace ts {
|
||||
statements: NodeArray<Statement>;
|
||||
}
|
||||
type CaseOrDefaultClause = CaseClause | DefaultClause;
|
||||
interface LabeledStatement extends Statement {
|
||||
interface LabeledStatement extends Statement, JSDocContainer {
|
||||
kind: SyntaxKind.LabeledStatement;
|
||||
label: Identifier;
|
||||
statement: Statement;
|
||||
@@ -1179,19 +1189,21 @@ declare namespace ts {
|
||||
block: Block;
|
||||
}
|
||||
type DeclarationWithTypeParameters = SignatureDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | JSDocTemplateTag;
|
||||
interface ClassLikeDeclaration extends NamedDeclaration {
|
||||
interface ClassLikeDeclarationBase extends NamedDeclaration, JSDocContainer {
|
||||
kind: SyntaxKind.ClassDeclaration | SyntaxKind.ClassExpression;
|
||||
name?: Identifier;
|
||||
typeParameters?: NodeArray<TypeParameterDeclaration>;
|
||||
heritageClauses?: NodeArray<HeritageClause>;
|
||||
members: NodeArray<ClassElement>;
|
||||
}
|
||||
interface ClassDeclaration extends ClassLikeDeclaration, DeclarationStatement {
|
||||
interface ClassDeclaration extends ClassLikeDeclarationBase, DeclarationStatement {
|
||||
kind: SyntaxKind.ClassDeclaration;
|
||||
name?: Identifier;
|
||||
}
|
||||
interface ClassExpression extends ClassLikeDeclaration, PrimaryExpression {
|
||||
interface ClassExpression extends ClassLikeDeclarationBase, PrimaryExpression {
|
||||
kind: SyntaxKind.ClassExpression;
|
||||
}
|
||||
type ClassLikeDeclaration = ClassDeclaration | ClassExpression;
|
||||
interface ClassElement extends NamedDeclaration {
|
||||
_classElementBrand: any;
|
||||
name?: PropertyName;
|
||||
@@ -1201,7 +1213,7 @@ declare namespace ts {
|
||||
name?: PropertyName;
|
||||
questionToken?: QuestionToken;
|
||||
}
|
||||
interface InterfaceDeclaration extends DeclarationStatement {
|
||||
interface InterfaceDeclaration extends DeclarationStatement, JSDocContainer {
|
||||
kind: SyntaxKind.InterfaceDeclaration;
|
||||
name: Identifier;
|
||||
typeParameters?: NodeArray<TypeParameterDeclaration>;
|
||||
@@ -1214,26 +1226,26 @@ declare namespace ts {
|
||||
token: SyntaxKind.ExtendsKeyword | SyntaxKind.ImplementsKeyword;
|
||||
types: NodeArray<ExpressionWithTypeArguments>;
|
||||
}
|
||||
interface TypeAliasDeclaration extends DeclarationStatement {
|
||||
interface TypeAliasDeclaration extends DeclarationStatement, JSDocContainer {
|
||||
kind: SyntaxKind.TypeAliasDeclaration;
|
||||
name: Identifier;
|
||||
typeParameters?: NodeArray<TypeParameterDeclaration>;
|
||||
type: TypeNode;
|
||||
}
|
||||
interface EnumMember extends NamedDeclaration {
|
||||
interface EnumMember extends NamedDeclaration, JSDocContainer {
|
||||
kind: SyntaxKind.EnumMember;
|
||||
parent?: EnumDeclaration;
|
||||
name: PropertyName;
|
||||
initializer?: Expression;
|
||||
}
|
||||
interface EnumDeclaration extends DeclarationStatement {
|
||||
interface EnumDeclaration extends DeclarationStatement, JSDocContainer {
|
||||
kind: SyntaxKind.EnumDeclaration;
|
||||
name: Identifier;
|
||||
members: NodeArray<EnumMember>;
|
||||
}
|
||||
type ModuleName = Identifier | StringLiteral;
|
||||
type ModuleBody = NamespaceBody | JSDocNamespaceBody;
|
||||
interface ModuleDeclaration extends DeclarationStatement {
|
||||
interface ModuleDeclaration extends DeclarationStatement, JSDocContainer {
|
||||
kind: SyntaxKind.ModuleDeclaration;
|
||||
parent?: ModuleBody | SourceFile;
|
||||
name: ModuleName;
|
||||
@@ -1255,7 +1267,7 @@ declare namespace ts {
|
||||
statements: NodeArray<Statement>;
|
||||
}
|
||||
type ModuleReference = EntityName | ExternalModuleReference;
|
||||
interface ImportEqualsDeclaration extends DeclarationStatement {
|
||||
interface ImportEqualsDeclaration extends DeclarationStatement, JSDocContainer {
|
||||
kind: SyntaxKind.ImportEqualsDeclaration;
|
||||
parent?: SourceFile | ModuleBlock;
|
||||
name: Identifier;
|
||||
@@ -1365,7 +1377,7 @@ declare namespace ts {
|
||||
kind: SyntaxKind.JSDocOptionalType;
|
||||
type: TypeNode;
|
||||
}
|
||||
interface JSDocFunctionType extends JSDocType, SignatureDeclaration {
|
||||
interface JSDocFunctionType extends JSDocType, SignatureDeclarationBase {
|
||||
kind: SyntaxKind.JSDocFunctionType;
|
||||
}
|
||||
interface JSDocVariadicType extends JSDocType {
|
||||
@@ -1375,6 +1387,7 @@ declare namespace ts {
|
||||
type JSDocTypeReferencingNode = JSDocVariadicType | JSDocOptionalType | JSDocNullableType | JSDocNonNullableType;
|
||||
interface JSDoc extends Node {
|
||||
kind: SyntaxKind.JSDocComment;
|
||||
parent?: HasJSDoc;
|
||||
tags: NodeArray<JSDocTag> | undefined;
|
||||
comment: string | undefined;
|
||||
}
|
||||
@@ -1429,7 +1442,6 @@ declare namespace ts {
|
||||
interface JSDocTypeLiteral extends JSDocType {
|
||||
kind: SyntaxKind.JSDocTypeLiteral;
|
||||
jsDocPropertyTags?: ReadonlyArray<JSDocPropertyLikeTag>;
|
||||
jsDocTypeTag?: JSDocTypeTag;
|
||||
isArrayType?: boolean;
|
||||
}
|
||||
const enum FlowFlags {
|
||||
@@ -1503,10 +1515,10 @@ declare namespace ts {
|
||||
endOfFileToken: Token<SyntaxKind.EndOfFileToken>;
|
||||
fileName: string;
|
||||
text: string;
|
||||
amdDependencies: AmdDependency[];
|
||||
amdDependencies: ReadonlyArray<AmdDependency>;
|
||||
moduleName: string;
|
||||
referencedFiles: FileReference[];
|
||||
typeReferenceDirectives: FileReference[];
|
||||
referencedFiles: ReadonlyArray<FileReference>;
|
||||
typeReferenceDirectives: ReadonlyArray<FileReference>;
|
||||
languageVariant: LanguageVariant;
|
||||
isDeclarationFile: boolean;
|
||||
hasNoDefaultLib: boolean;
|
||||
@@ -1514,7 +1526,7 @@ declare namespace ts {
|
||||
}
|
||||
interface Bundle extends Node {
|
||||
kind: SyntaxKind.Bundle;
|
||||
sourceFiles: SourceFile[];
|
||||
sourceFiles: ReadonlyArray<SourceFile>;
|
||||
}
|
||||
interface JsonSourceFile extends SourceFile {
|
||||
jsonObject?: ObjectLiteralExpression;
|
||||
@@ -1533,7 +1545,7 @@ declare namespace ts {
|
||||
readFile(path: string): string | undefined;
|
||||
}
|
||||
interface WriteFileCallback {
|
||||
(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void, sourceFiles?: ReadonlyArray<SourceFile>): void;
|
||||
(fileName: string, data: string, writeByteOrderMark: boolean, onError: ((message: string) => void) | undefined, sourceFiles: ReadonlyArray<SourceFile>): void;
|
||||
}
|
||||
class OperationCanceledException {
|
||||
}
|
||||
@@ -1542,15 +1554,16 @@ declare namespace ts {
|
||||
throwIfCancellationRequested(): void;
|
||||
}
|
||||
interface Program extends ScriptReferenceHost {
|
||||
getRootFileNames(): string[];
|
||||
getSourceFiles(): SourceFile[];
|
||||
getRootFileNames(): ReadonlyArray<string>;
|
||||
getSourceFiles(): ReadonlyArray<SourceFile>;
|
||||
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult;
|
||||
getOptionsDiagnostics(cancellationToken?: CancellationToken): Diagnostic[];
|
||||
getGlobalDiagnostics(cancellationToken?: CancellationToken): Diagnostic[];
|
||||
getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
|
||||
getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
|
||||
getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
|
||||
getOptionsDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
|
||||
getGlobalDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
|
||||
getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
|
||||
getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
|
||||
getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
|
||||
getTypeChecker(): TypeChecker;
|
||||
isSourceFileFromExternalLibrary(file: SourceFile): boolean;
|
||||
}
|
||||
interface CustomTransformers {
|
||||
before?: TransformerFactory<SourceFile>[];
|
||||
@@ -1583,7 +1596,7 @@ declare namespace ts {
|
||||
}
|
||||
interface EmitResult {
|
||||
emitSkipped: boolean;
|
||||
diagnostics: Diagnostic[];
|
||||
diagnostics: ReadonlyArray<Diagnostic>;
|
||||
emittedFiles: string[];
|
||||
}
|
||||
interface TypeChecker {
|
||||
@@ -1857,6 +1870,7 @@ declare namespace ts {
|
||||
IndexedAccess = 524288,
|
||||
NonPrimitive = 16777216,
|
||||
Literal = 224,
|
||||
Unit = 6368,
|
||||
StringOrNumberLiteral = 96,
|
||||
PossiblyFalsy = 7406,
|
||||
StringLike = 262178,
|
||||
@@ -2032,7 +2046,7 @@ declare namespace ts {
|
||||
interface PluginImport {
|
||||
name: string;
|
||||
}
|
||||
type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike<string[]> | PluginImport[];
|
||||
type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike<string[]> | PluginImport[] | null | undefined;
|
||||
interface CompilerOptions {
|
||||
allowJs?: boolean;
|
||||
allowSyntheticDefaultImports?: boolean;
|
||||
@@ -2199,6 +2213,7 @@ declare namespace ts {
|
||||
}
|
||||
interface PackageId {
|
||||
name: string;
|
||||
subModuleName: string;
|
||||
version: string;
|
||||
}
|
||||
const enum Extension {
|
||||
@@ -2214,14 +2229,15 @@ declare namespace ts {
|
||||
interface ResolvedTypeReferenceDirective {
|
||||
primary: boolean;
|
||||
resolvedFileName?: string;
|
||||
packageId?: PackageId;
|
||||
}
|
||||
interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
|
||||
resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective;
|
||||
failedLookupLocations: string[];
|
||||
}
|
||||
interface CompilerHost extends ModuleResolutionHost {
|
||||
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile;
|
||||
getSourceFileByPath?(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile;
|
||||
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile | undefined;
|
||||
getSourceFileByPath?(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile | undefined;
|
||||
getCancellationToken?(): CancellationToken;
|
||||
getDefaultLibFileName(options: CompilerOptions): string;
|
||||
getDefaultLibLocation?(): string;
|
||||
@@ -2283,7 +2299,8 @@ declare namespace ts {
|
||||
SourceFile = 0,
|
||||
Expression = 1,
|
||||
IdentifierName = 2,
|
||||
Unspecified = 3,
|
||||
MappedTypeParameter = 3,
|
||||
Unspecified = 4,
|
||||
}
|
||||
interface TransformationContext {
|
||||
getCompilerOptions(): CompilerOptions;
|
||||
@@ -2343,6 +2360,9 @@ declare namespace ts {
|
||||
const versionMajorMinor = "2.6";
|
||||
const version: string;
|
||||
}
|
||||
declare namespace ts {
|
||||
function isExternalModuleNameRelative(moduleName: string): boolean;
|
||||
}
|
||||
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): any;
|
||||
declare function clearTimeout(handle: any): void;
|
||||
declare namespace ts {
|
||||
@@ -2433,7 +2453,18 @@ declare namespace ts {
|
||||
function getParseTreeNode<T extends Node>(node: Node, nodeTest?: (node: Node) => node is T): T;
|
||||
function unescapeLeadingUnderscores(identifier: __String): string;
|
||||
function unescapeIdentifier(id: string): string;
|
||||
function getNameOfDeclaration(declaration: Declaration): DeclarationName | undefined;
|
||||
function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | undefined;
|
||||
function getNameOfDeclaration(declaration: Declaration | Expression): DeclarationName | undefined;
|
||||
function getJSDocParameterTags(param: ParameterDeclaration): ReadonlyArray<JSDocParameterTag> | undefined;
|
||||
function hasJSDocParameterTags(node: FunctionLikeDeclaration | SignatureDeclaration): boolean;
|
||||
function getJSDocAugmentsTag(node: Node): JSDocAugmentsTag | undefined;
|
||||
function getJSDocClassTag(node: Node): JSDocClassTag | undefined;
|
||||
function getJSDocReturnTag(node: Node): JSDocReturnTag | undefined;
|
||||
function getJSDocTemplateTag(node: Node): JSDocTemplateTag | undefined;
|
||||
function getJSDocTypeTag(node: Node): JSDocTypeTag | undefined;
|
||||
function getJSDocType(node: Node): TypeNode | undefined;
|
||||
function getJSDocReturnType(node: Node): TypeNode | undefined;
|
||||
function getJSDocTags(node: Node): ReadonlyArray<JSDocTag> | undefined;
|
||||
}
|
||||
declare namespace ts {
|
||||
function isNumericLiteral(node: Node): node is NumericLiteral;
|
||||
@@ -2805,8 +2836,8 @@ declare namespace ts {
|
||||
function updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode;
|
||||
function createMappedTypeNode(readonlyToken: ReadonlyToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | undefined, type: TypeNode | undefined): MappedTypeNode;
|
||||
function updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | undefined, type: TypeNode | undefined): MappedTypeNode;
|
||||
function createLiteralTypeNode(literal: Expression): LiteralTypeNode;
|
||||
function updateLiteralTypeNode(node: LiteralTypeNode, literal: Expression): LiteralTypeNode;
|
||||
function createLiteralTypeNode(literal: LiteralTypeNode["literal"]): LiteralTypeNode;
|
||||
function updateLiteralTypeNode(node: LiteralTypeNode, literal: LiteralTypeNode["literal"]): LiteralTypeNode;
|
||||
function createObjectBindingPattern(elements: ReadonlyArray<BindingElement>): ObjectBindingPattern;
|
||||
function updateObjectBindingPattern(node: ObjectBindingPattern, elements: ReadonlyArray<BindingElement>): ObjectBindingPattern;
|
||||
function createArrayBindingPattern(elements: ReadonlyArray<ArrayBindingElement>): ArrayBindingPattern;
|
||||
@@ -2835,6 +2866,7 @@ declare namespace ts {
|
||||
function updateFunctionExpression(node: FunctionExpression, modifiers: ReadonlyArray<Modifier> | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration>, type: TypeNode | undefined, body: Block): FunctionExpression;
|
||||
function createArrowFunction(modifiers: ReadonlyArray<Modifier> | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration>, type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken | undefined, body: ConciseBody): ArrowFunction;
|
||||
function updateArrowFunction(node: ArrowFunction, modifiers: ReadonlyArray<Modifier> | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration>, type: TypeNode | undefined, body: ConciseBody): ArrowFunction;
|
||||
function updateArrowFunction(node: ArrowFunction, modifiers: ReadonlyArray<Modifier> | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration>, type: TypeNode | undefined, equalsGreaterThanToken: Token<SyntaxKind.EqualsGreaterThanToken>, body: ConciseBody): ArrowFunction;
|
||||
function createDelete(expression: Expression): DeleteExpression;
|
||||
function updateDelete(node: DeleteExpression, expression: Expression): DeleteExpression;
|
||||
function createTypeOf(expression: Expression): TypeOfExpression;
|
||||
@@ -2852,8 +2884,13 @@ declare namespace ts {
|
||||
function createConditional(condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression;
|
||||
function createConditional(condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression): ConditionalExpression;
|
||||
function updateConditional(node: ConditionalExpression, condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression;
|
||||
function updateConditional(node: ConditionalExpression, condition: Expression, questionToken: Token<SyntaxKind.QuestionToken>, whenTrue: Expression, colonToken: Token<SyntaxKind.ColonToken>, whenFalse: Expression): ConditionalExpression;
|
||||
function createTemplateExpression(head: TemplateHead, templateSpans: ReadonlyArray<TemplateSpan>): TemplateExpression;
|
||||
function updateTemplateExpression(node: TemplateExpression, head: TemplateHead, templateSpans: ReadonlyArray<TemplateSpan>): TemplateExpression;
|
||||
function createTemplateHead(text: string): TemplateHead;
|
||||
function createTemplateMiddle(text: string): TemplateMiddle;
|
||||
function createTemplateTail(text: string): TemplateTail;
|
||||
function createNoSubstitutionTemplateLiteral(text: string): NoSubstitutionTemplateLiteral;
|
||||
function createYield(expression?: Expression): YieldExpression;
|
||||
function createYield(asteriskToken: AsteriskToken, expression: Expression): YieldExpression;
|
||||
function updateYield(node: YieldExpression, asteriskToken: AsteriskToken | undefined, expression: Expression): YieldExpression;
|
||||
@@ -2992,10 +3029,12 @@ declare namespace ts {
|
||||
function updatePartiallyEmittedExpression(node: PartiallyEmittedExpression, expression: Expression): PartiallyEmittedExpression;
|
||||
function createCommaList(elements: ReadonlyArray<Expression>): CommaListExpression;
|
||||
function updateCommaList(node: CommaListExpression, elements: ReadonlyArray<Expression>): CommaListExpression;
|
||||
function createBundle(sourceFiles: SourceFile[]): Bundle;
|
||||
function updateBundle(node: Bundle, sourceFiles: SourceFile[]): Bundle;
|
||||
function createBundle(sourceFiles: ReadonlyArray<SourceFile>): Bundle;
|
||||
function updateBundle(node: Bundle, sourceFiles: ReadonlyArray<SourceFile>): Bundle;
|
||||
function createImmediatelyInvokedFunctionExpression(statements: Statement[]): CallExpression;
|
||||
function createImmediatelyInvokedFunctionExpression(statements: Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression;
|
||||
function createImmediatelyInvokedArrowFunction(statements: Statement[]): CallExpression;
|
||||
function createImmediatelyInvokedArrowFunction(statements: Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression;
|
||||
function createComma(left: Expression, right: Expression): Expression;
|
||||
function createLessThan(left: Expression, right: Expression): Expression;
|
||||
function createAssignment(left: ObjectLiteralExpression | ArrayLiteralExpression, right: Expression): DestructuringAssignment;
|
||||
@@ -3062,10 +3101,10 @@ declare namespace ts {
|
||||
getCanonicalFileName(fileName: string): string;
|
||||
getNewLine(): string;
|
||||
}
|
||||
function formatDiagnostics(diagnostics: Diagnostic[], host: FormatDiagnosticsHost): string;
|
||||
function formatDiagnosticsWithColorAndContext(diagnostics: Diagnostic[], host: FormatDiagnosticsHost): string;
|
||||
function formatDiagnostics(diagnostics: ReadonlyArray<Diagnostic>, host: FormatDiagnosticsHost): string;
|
||||
function formatDiagnosticsWithColorAndContext(diagnostics: ReadonlyArray<Diagnostic>, host: FormatDiagnosticsHost): string;
|
||||
function flattenDiagnosticMessageText(messageText: string | DiagnosticMessageChain, newLine: string): string;
|
||||
function createProgram(rootNames: string[], options: CompilerOptions, host?: CompilerHost, oldProgram?: Program): Program;
|
||||
function createProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program): Program;
|
||||
}
|
||||
declare namespace ts {
|
||||
interface Node {
|
||||
@@ -3121,7 +3160,7 @@ declare namespace ts {
|
||||
interface SourceFile {
|
||||
getLineAndCharacterOfPosition(pos: number): LineAndCharacter;
|
||||
getLineEndOfPosition(pos: number): number;
|
||||
getLineStarts(): number[];
|
||||
getLineStarts(): ReadonlyArray<number>;
|
||||
getPositionOfLineAndCharacter(line: number, character: number): number;
|
||||
update(newText: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
}
|
||||
@@ -3273,15 +3312,15 @@ declare namespace ts {
|
||||
inlineable?: boolean;
|
||||
actions: RefactorActionInfo[];
|
||||
}
|
||||
type RefactorActionInfo = {
|
||||
interface RefactorActionInfo {
|
||||
name: string;
|
||||
description: string;
|
||||
};
|
||||
type RefactorEditInfo = {
|
||||
}
|
||||
interface RefactorEditInfo {
|
||||
edits: FileTextChanges[];
|
||||
renameFilename?: string;
|
||||
renameLocation?: number;
|
||||
};
|
||||
renameFilename: string | undefined;
|
||||
renameLocation: number | undefined;
|
||||
}
|
||||
interface TextInsertion {
|
||||
newText: string;
|
||||
caretOffset: number;
|
||||
@@ -4041,10 +4080,10 @@ declare namespace ts.server.protocol {
|
||||
inlineable?: boolean;
|
||||
actions: RefactorActionInfo[];
|
||||
}
|
||||
type RefactorActionInfo = {
|
||||
interface RefactorActionInfo {
|
||||
name: string;
|
||||
description: string;
|
||||
};
|
||||
}
|
||||
interface GetEditsForRefactorRequest extends Request {
|
||||
command: CommandTypes.GetEditsForRefactor;
|
||||
arguments: GetEditsForRefactorRequestArgs;
|
||||
@@ -4052,15 +4091,16 @@ declare namespace ts.server.protocol {
|
||||
type GetEditsForRefactorRequestArgs = FileLocationOrRangeRequestArgs & {
|
||||
refactor: string;
|
||||
action: string;
|
||||
formatOptions?: FormatCodeSettings;
|
||||
};
|
||||
interface GetEditsForRefactorResponse extends Response {
|
||||
body?: RefactorEditInfo;
|
||||
}
|
||||
type RefactorEditInfo = {
|
||||
interface RefactorEditInfo {
|
||||
edits: FileCodeEdits[];
|
||||
renameLocation?: Location;
|
||||
renameFilename?: string;
|
||||
};
|
||||
}
|
||||
interface CodeFixRequest extends Request {
|
||||
command: CommandTypes.GetCodeFixes;
|
||||
arguments: CodeFixRequestArgs;
|
||||
@@ -4943,13 +4983,14 @@ declare namespace ts.server {
|
||||
readonly fileName: NormalizedPath;
|
||||
readonly scriptKind: ScriptKind;
|
||||
hasMixedContent: boolean;
|
||||
isDynamic: boolean;
|
||||
readonly containingProjects: Project[];
|
||||
private formatCodeSettings;
|
||||
readonly path: Path;
|
||||
private fileWatcher;
|
||||
private textStorage;
|
||||
private isOpen;
|
||||
constructor(host: ServerHost, fileName: NormalizedPath, scriptKind: ScriptKind, hasMixedContent?: boolean);
|
||||
constructor(host: ServerHost, fileName: NormalizedPath, scriptKind: ScriptKind, hasMixedContent?: boolean, isDynamic?: boolean);
|
||||
isScriptOpen(): boolean;
|
||||
open(newText: string): void;
|
||||
close(): void;
|
||||
@@ -5295,7 +5336,7 @@ declare namespace ts.server {
|
||||
interface SafeList {
|
||||
[name: string]: {
|
||||
match: RegExp;
|
||||
exclude?: Array<Array<string | number>>;
|
||||
exclude?: (string | number)[][];
|
||||
types?: string[];
|
||||
};
|
||||
}
|
||||
@@ -5412,7 +5453,7 @@ declare namespace ts.server {
|
||||
getOrCreateScriptInfo(uncheckedFileName: string, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind): ScriptInfo;
|
||||
getScriptInfo(uncheckedFileName: string): ScriptInfo;
|
||||
watchClosedScriptInfo(info: ScriptInfo): void;
|
||||
getOrCreateScriptInfoForNormalizedPath(fileName: NormalizedPath, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean): ScriptInfo;
|
||||
getOrCreateScriptInfoForNormalizedPath(fileName: NormalizedPath, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, isDynamic?: boolean): ScriptInfo;
|
||||
getScriptInfoForNormalizedPath(fileName: NormalizedPath): ScriptInfo;
|
||||
getScriptInfoForPath(fileName: Path): ScriptInfo;
|
||||
setHostConfiguration(args: protocol.ConfigureRequestArguments): void;
|
||||
|
||||
+2679
-2028
File diff suppressed because it is too large
Load Diff
Vendored
+158
-73
@@ -446,6 +446,9 @@ declare namespace ts {
|
||||
modifiers?: ModifiersArray;
|
||||
parent?: Node;
|
||||
}
|
||||
interface JSDocContainer {
|
||||
}
|
||||
type HasJSDoc = ParameterDeclaration | CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignature | PropertySignature | ArrowFunction | ParenthesizedExpression | SpreadAssignment | ShorthandPropertyAssignment | PropertyAssignment | FunctionExpression | LabeledStatement | ExpressionStatement | VariableStatement | FunctionDeclaration | ConstructorDeclaration | MethodDeclaration | PropertyDeclaration | AccessorDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumMember | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | EndOfFileToken;
|
||||
interface NodeArray<T extends Node> extends ReadonlyArray<T>, TextRange {
|
||||
hasTrailingComma?: boolean;
|
||||
}
|
||||
@@ -458,7 +461,7 @@ declare namespace ts {
|
||||
type EqualsToken = Token<SyntaxKind.EqualsToken>;
|
||||
type AsteriskToken = Token<SyntaxKind.AsteriskToken>;
|
||||
type EqualsGreaterThanToken = Token<SyntaxKind.EqualsGreaterThanToken>;
|
||||
type EndOfFileToken = Token<SyntaxKind.EndOfFileToken>;
|
||||
type EndOfFileToken = Token<SyntaxKind.EndOfFileToken> & JSDocContainer;
|
||||
type AtToken = Token<SyntaxKind.AtToken>;
|
||||
type ReadonlyToken = Token<SyntaxKind.ReadonlyKeyword>;
|
||||
type AwaitKeywordToken = Token<SyntaxKind.AwaitKeyword>;
|
||||
@@ -500,6 +503,7 @@ declare namespace ts {
|
||||
}
|
||||
interface Decorator extends Node {
|
||||
kind: SyntaxKind.Decorator;
|
||||
parent?: NamedDeclaration;
|
||||
expression: LeftHandSideExpression;
|
||||
}
|
||||
interface TypeParameterDeclaration extends NamedDeclaration {
|
||||
@@ -510,16 +514,18 @@ declare namespace ts {
|
||||
default?: TypeNode;
|
||||
expression?: Expression;
|
||||
}
|
||||
interface SignatureDeclaration extends NamedDeclaration {
|
||||
interface SignatureDeclarationBase extends NamedDeclaration, JSDocContainer {
|
||||
kind: SignatureDeclaration["kind"];
|
||||
name?: PropertyName;
|
||||
typeParameters?: NodeArray<TypeParameterDeclaration>;
|
||||
parameters: NodeArray<ParameterDeclaration>;
|
||||
type?: TypeNode;
|
||||
type: TypeNode | undefined;
|
||||
}
|
||||
interface CallSignatureDeclaration extends SignatureDeclaration, TypeElement {
|
||||
type SignatureDeclaration = CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignature | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | AccessorDeclaration | FunctionExpression | ArrowFunction;
|
||||
interface CallSignatureDeclaration extends SignatureDeclarationBase, TypeElement {
|
||||
kind: SyntaxKind.CallSignature;
|
||||
}
|
||||
interface ConstructSignatureDeclaration extends SignatureDeclaration, TypeElement {
|
||||
interface ConstructSignatureDeclaration extends SignatureDeclarationBase, TypeElement {
|
||||
kind: SyntaxKind.ConstructSignature;
|
||||
}
|
||||
type BindingName = Identifier | BindingPattern;
|
||||
@@ -535,7 +541,7 @@ declare namespace ts {
|
||||
parent?: VariableStatement | ForStatement | ForOfStatement | ForInStatement;
|
||||
declarations: NodeArray<VariableDeclaration>;
|
||||
}
|
||||
interface ParameterDeclaration extends NamedDeclaration {
|
||||
interface ParameterDeclaration extends NamedDeclaration, JSDocContainer {
|
||||
kind: SyntaxKind.Parameter;
|
||||
parent?: SignatureDeclaration;
|
||||
dotDotDotToken?: DotDotDotToken;
|
||||
@@ -552,14 +558,14 @@ declare namespace ts {
|
||||
name: BindingName;
|
||||
initializer?: Expression;
|
||||
}
|
||||
interface PropertySignature extends TypeElement {
|
||||
interface PropertySignature extends TypeElement, JSDocContainer {
|
||||
kind: SyntaxKind.PropertySignature;
|
||||
name: PropertyName;
|
||||
questionToken?: QuestionToken;
|
||||
type?: TypeNode;
|
||||
initializer?: Expression;
|
||||
}
|
||||
interface PropertyDeclaration extends ClassElement {
|
||||
interface PropertyDeclaration extends ClassElement, JSDocContainer {
|
||||
kind: SyntaxKind.PropertyDeclaration;
|
||||
questionToken?: QuestionToken;
|
||||
name: PropertyName;
|
||||
@@ -571,27 +577,30 @@ declare namespace ts {
|
||||
name?: PropertyName;
|
||||
}
|
||||
type ObjectLiteralElementLike = PropertyAssignment | ShorthandPropertyAssignment | SpreadAssignment | MethodDeclaration | AccessorDeclaration;
|
||||
interface PropertyAssignment extends ObjectLiteralElement {
|
||||
interface PropertyAssignment extends ObjectLiteralElement, JSDocContainer {
|
||||
parent: ObjectLiteralExpression;
|
||||
kind: SyntaxKind.PropertyAssignment;
|
||||
name: PropertyName;
|
||||
questionToken?: QuestionToken;
|
||||
initializer: Expression;
|
||||
}
|
||||
interface ShorthandPropertyAssignment extends ObjectLiteralElement {
|
||||
interface ShorthandPropertyAssignment extends ObjectLiteralElement, JSDocContainer {
|
||||
parent: ObjectLiteralExpression;
|
||||
kind: SyntaxKind.ShorthandPropertyAssignment;
|
||||
name: Identifier;
|
||||
questionToken?: QuestionToken;
|
||||
equalsToken?: Token<SyntaxKind.EqualsToken>;
|
||||
objectAssignmentInitializer?: Expression;
|
||||
}
|
||||
interface SpreadAssignment extends ObjectLiteralElement {
|
||||
interface SpreadAssignment extends ObjectLiteralElement, JSDocContainer {
|
||||
parent: ObjectLiteralExpression;
|
||||
kind: SyntaxKind.SpreadAssignment;
|
||||
expression: Expression;
|
||||
}
|
||||
interface VariableLikeDeclaration extends NamedDeclaration {
|
||||
propertyName?: PropertyName;
|
||||
dotDotDotToken?: DotDotDotToken;
|
||||
name?: DeclarationName;
|
||||
name: DeclarationName;
|
||||
questionToken?: QuestionToken;
|
||||
type?: TypeNode;
|
||||
initializer?: Expression;
|
||||
@@ -619,7 +628,7 @@ declare namespace ts {
|
||||
* - MethodDeclaration
|
||||
* - AccessorDeclaration
|
||||
*/
|
||||
interface FunctionLikeDeclarationBase extends SignatureDeclaration {
|
||||
interface FunctionLikeDeclarationBase extends SignatureDeclarationBase {
|
||||
_functionLikeDeclarationBrand: any;
|
||||
asteriskToken?: AsteriskToken;
|
||||
questionToken?: QuestionToken;
|
||||
@@ -632,16 +641,16 @@ declare namespace ts {
|
||||
name?: Identifier;
|
||||
body?: FunctionBody;
|
||||
}
|
||||
interface MethodSignature extends SignatureDeclaration, TypeElement {
|
||||
interface MethodSignature extends SignatureDeclarationBase, TypeElement {
|
||||
kind: SyntaxKind.MethodSignature;
|
||||
name: PropertyName;
|
||||
}
|
||||
interface MethodDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement {
|
||||
interface MethodDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
|
||||
kind: SyntaxKind.MethodDeclaration;
|
||||
name: PropertyName;
|
||||
body?: FunctionBody;
|
||||
}
|
||||
interface ConstructorDeclaration extends FunctionLikeDeclarationBase, ClassElement {
|
||||
interface ConstructorDeclaration extends FunctionLikeDeclarationBase, ClassElement, JSDocContainer {
|
||||
kind: SyntaxKind.Constructor;
|
||||
parent?: ClassDeclaration | ClassExpression;
|
||||
body?: FunctionBody;
|
||||
@@ -651,20 +660,20 @@ declare namespace ts {
|
||||
kind: SyntaxKind.SemicolonClassElement;
|
||||
parent?: ClassDeclaration | ClassExpression;
|
||||
}
|
||||
interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement {
|
||||
interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
|
||||
kind: SyntaxKind.GetAccessor;
|
||||
parent?: ClassDeclaration | ClassExpression | ObjectLiteralExpression;
|
||||
name: PropertyName;
|
||||
body: FunctionBody;
|
||||
}
|
||||
interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement {
|
||||
interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
|
||||
kind: SyntaxKind.SetAccessor;
|
||||
parent?: ClassDeclaration | ClassExpression | ObjectLiteralExpression;
|
||||
name: PropertyName;
|
||||
body: FunctionBody;
|
||||
}
|
||||
type AccessorDeclaration = GetAccessorDeclaration | SetAccessorDeclaration;
|
||||
interface IndexSignatureDeclaration extends SignatureDeclaration, ClassElement, TypeElement {
|
||||
interface IndexSignatureDeclaration extends SignatureDeclarationBase, ClassElement, TypeElement {
|
||||
kind: SyntaxKind.IndexSignature;
|
||||
parent?: ClassDeclaration | ClassExpression | InterfaceDeclaration | TypeLiteralNode;
|
||||
}
|
||||
@@ -678,10 +687,10 @@ declare namespace ts {
|
||||
kind: SyntaxKind.ThisType;
|
||||
}
|
||||
type FunctionOrConstructorTypeNode = FunctionTypeNode | ConstructorTypeNode;
|
||||
interface FunctionTypeNode extends TypeNode, SignatureDeclaration {
|
||||
interface FunctionTypeNode extends TypeNode, SignatureDeclarationBase {
|
||||
kind: SyntaxKind.FunctionType;
|
||||
}
|
||||
interface ConstructorTypeNode extends TypeNode, SignatureDeclaration {
|
||||
interface ConstructorTypeNode extends TypeNode, SignatureDeclarationBase {
|
||||
kind: SyntaxKind.ConstructorType;
|
||||
}
|
||||
type TypeReferenceType = TypeReferenceNode | ExpressionWithTypeArguments;
|
||||
@@ -692,6 +701,7 @@ declare namespace ts {
|
||||
}
|
||||
interface TypePredicateNode extends TypeNode {
|
||||
kind: SyntaxKind.TypePredicate;
|
||||
parent?: SignatureDeclaration;
|
||||
parameterName: Identifier | ThisTypeNode;
|
||||
type: TypeNode;
|
||||
}
|
||||
@@ -736,7 +746,6 @@ declare namespace ts {
|
||||
}
|
||||
interface MappedTypeNode extends TypeNode, Declaration {
|
||||
kind: SyntaxKind.MappedType;
|
||||
parent?: TypeAliasDeclaration;
|
||||
readonlyToken?: ReadonlyToken;
|
||||
typeParameter: TypeParameterDeclaration;
|
||||
questionToken?: QuestionToken;
|
||||
@@ -744,7 +753,7 @@ declare namespace ts {
|
||||
}
|
||||
interface LiteralTypeNode extends TypeNode {
|
||||
kind: SyntaxKind.LiteralType;
|
||||
literal: Expression;
|
||||
literal: BooleanLiteral | LiteralExpression | PrefixUnaryExpression;
|
||||
}
|
||||
interface StringLiteral extends LiteralExpression {
|
||||
kind: SyntaxKind.StringLiteral;
|
||||
@@ -879,12 +888,12 @@ declare namespace ts {
|
||||
}
|
||||
type FunctionBody = Block;
|
||||
type ConciseBody = FunctionBody | Expression;
|
||||
interface FunctionExpression extends PrimaryExpression, FunctionLikeDeclarationBase {
|
||||
interface FunctionExpression extends PrimaryExpression, FunctionLikeDeclarationBase, JSDocContainer {
|
||||
kind: SyntaxKind.FunctionExpression;
|
||||
name?: Identifier;
|
||||
body: FunctionBody;
|
||||
}
|
||||
interface ArrowFunction extends Expression, FunctionLikeDeclarationBase {
|
||||
interface ArrowFunction extends Expression, FunctionLikeDeclarationBase, JSDocContainer {
|
||||
kind: SyntaxKind.ArrowFunction;
|
||||
equalsGreaterThanToken: EqualsGreaterThanToken;
|
||||
body: ConciseBody;
|
||||
@@ -930,7 +939,7 @@ declare namespace ts {
|
||||
expression: Expression;
|
||||
literal: TemplateMiddle | TemplateTail;
|
||||
}
|
||||
interface ParenthesizedExpression extends PrimaryExpression {
|
||||
interface ParenthesizedExpression extends PrimaryExpression, JSDocContainer {
|
||||
kind: SyntaxKind.ParenthesizedExpression;
|
||||
expression: Expression;
|
||||
}
|
||||
@@ -940,6 +949,7 @@ declare namespace ts {
|
||||
}
|
||||
interface SpreadElement extends Expression {
|
||||
kind: SyntaxKind.SpreadElement;
|
||||
parent?: ArrayLiteralExpression | CallExpression | NewExpression;
|
||||
expression: Expression;
|
||||
}
|
||||
/**
|
||||
@@ -1107,11 +1117,11 @@ declare namespace ts {
|
||||
kind: SyntaxKind.Block;
|
||||
statements: NodeArray<Statement>;
|
||||
}
|
||||
interface VariableStatement extends Statement {
|
||||
interface VariableStatement extends Statement, JSDocContainer {
|
||||
kind: SyntaxKind.VariableStatement;
|
||||
declarationList: VariableDeclarationList;
|
||||
}
|
||||
interface ExpressionStatement extends Statement {
|
||||
interface ExpressionStatement extends Statement, JSDocContainer {
|
||||
kind: SyntaxKind.ExpressionStatement;
|
||||
expression: Expression;
|
||||
}
|
||||
@@ -1192,7 +1202,7 @@ declare namespace ts {
|
||||
statements: NodeArray<Statement>;
|
||||
}
|
||||
type CaseOrDefaultClause = CaseClause | DefaultClause;
|
||||
interface LabeledStatement extends Statement {
|
||||
interface LabeledStatement extends Statement, JSDocContainer {
|
||||
kind: SyntaxKind.LabeledStatement;
|
||||
label: Identifier;
|
||||
statement: Statement;
|
||||
@@ -1214,19 +1224,21 @@ declare namespace ts {
|
||||
block: Block;
|
||||
}
|
||||
type DeclarationWithTypeParameters = SignatureDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | JSDocTemplateTag;
|
||||
interface ClassLikeDeclaration extends NamedDeclaration {
|
||||
interface ClassLikeDeclarationBase extends NamedDeclaration, JSDocContainer {
|
||||
kind: SyntaxKind.ClassDeclaration | SyntaxKind.ClassExpression;
|
||||
name?: Identifier;
|
||||
typeParameters?: NodeArray<TypeParameterDeclaration>;
|
||||
heritageClauses?: NodeArray<HeritageClause>;
|
||||
members: NodeArray<ClassElement>;
|
||||
}
|
||||
interface ClassDeclaration extends ClassLikeDeclaration, DeclarationStatement {
|
||||
interface ClassDeclaration extends ClassLikeDeclarationBase, DeclarationStatement {
|
||||
kind: SyntaxKind.ClassDeclaration;
|
||||
name?: Identifier;
|
||||
}
|
||||
interface ClassExpression extends ClassLikeDeclaration, PrimaryExpression {
|
||||
interface ClassExpression extends ClassLikeDeclarationBase, PrimaryExpression {
|
||||
kind: SyntaxKind.ClassExpression;
|
||||
}
|
||||
type ClassLikeDeclaration = ClassDeclaration | ClassExpression;
|
||||
interface ClassElement extends NamedDeclaration {
|
||||
_classElementBrand: any;
|
||||
name?: PropertyName;
|
||||
@@ -1236,7 +1248,7 @@ declare namespace ts {
|
||||
name?: PropertyName;
|
||||
questionToken?: QuestionToken;
|
||||
}
|
||||
interface InterfaceDeclaration extends DeclarationStatement {
|
||||
interface InterfaceDeclaration extends DeclarationStatement, JSDocContainer {
|
||||
kind: SyntaxKind.InterfaceDeclaration;
|
||||
name: Identifier;
|
||||
typeParameters?: NodeArray<TypeParameterDeclaration>;
|
||||
@@ -1249,26 +1261,26 @@ declare namespace ts {
|
||||
token: SyntaxKind.ExtendsKeyword | SyntaxKind.ImplementsKeyword;
|
||||
types: NodeArray<ExpressionWithTypeArguments>;
|
||||
}
|
||||
interface TypeAliasDeclaration extends DeclarationStatement {
|
||||
interface TypeAliasDeclaration extends DeclarationStatement, JSDocContainer {
|
||||
kind: SyntaxKind.TypeAliasDeclaration;
|
||||
name: Identifier;
|
||||
typeParameters?: NodeArray<TypeParameterDeclaration>;
|
||||
type: TypeNode;
|
||||
}
|
||||
interface EnumMember extends NamedDeclaration {
|
||||
interface EnumMember extends NamedDeclaration, JSDocContainer {
|
||||
kind: SyntaxKind.EnumMember;
|
||||
parent?: EnumDeclaration;
|
||||
name: PropertyName;
|
||||
initializer?: Expression;
|
||||
}
|
||||
interface EnumDeclaration extends DeclarationStatement {
|
||||
interface EnumDeclaration extends DeclarationStatement, JSDocContainer {
|
||||
kind: SyntaxKind.EnumDeclaration;
|
||||
name: Identifier;
|
||||
members: NodeArray<EnumMember>;
|
||||
}
|
||||
type ModuleName = Identifier | StringLiteral;
|
||||
type ModuleBody = NamespaceBody | JSDocNamespaceBody;
|
||||
interface ModuleDeclaration extends DeclarationStatement {
|
||||
interface ModuleDeclaration extends DeclarationStatement, JSDocContainer {
|
||||
kind: SyntaxKind.ModuleDeclaration;
|
||||
parent?: ModuleBody | SourceFile;
|
||||
name: ModuleName;
|
||||
@@ -1295,7 +1307,7 @@ declare namespace ts {
|
||||
* - import x = require("mod");
|
||||
* - import x = M.x;
|
||||
*/
|
||||
interface ImportEqualsDeclaration extends DeclarationStatement {
|
||||
interface ImportEqualsDeclaration extends DeclarationStatement, JSDocContainer {
|
||||
kind: SyntaxKind.ImportEqualsDeclaration;
|
||||
parent?: SourceFile | ModuleBlock;
|
||||
name: Identifier;
|
||||
@@ -1407,7 +1419,7 @@ declare namespace ts {
|
||||
kind: SyntaxKind.JSDocOptionalType;
|
||||
type: TypeNode;
|
||||
}
|
||||
interface JSDocFunctionType extends JSDocType, SignatureDeclaration {
|
||||
interface JSDocFunctionType extends JSDocType, SignatureDeclarationBase {
|
||||
kind: SyntaxKind.JSDocFunctionType;
|
||||
}
|
||||
interface JSDocVariadicType extends JSDocType {
|
||||
@@ -1417,6 +1429,7 @@ declare namespace ts {
|
||||
type JSDocTypeReferencingNode = JSDocVariadicType | JSDocOptionalType | JSDocNullableType | JSDocNonNullableType;
|
||||
interface JSDoc extends Node {
|
||||
kind: SyntaxKind.JSDocComment;
|
||||
parent?: HasJSDoc;
|
||||
tags: NodeArray<JSDocTag> | undefined;
|
||||
comment: string | undefined;
|
||||
}
|
||||
@@ -1472,7 +1485,6 @@ declare namespace ts {
|
||||
interface JSDocTypeLiteral extends JSDocType {
|
||||
kind: SyntaxKind.JSDocTypeLiteral;
|
||||
jsDocPropertyTags?: ReadonlyArray<JSDocPropertyLikeTag>;
|
||||
jsDocTypeTag?: JSDocTypeTag;
|
||||
/** If true, then this type literal represents an *array* of its type. */
|
||||
isArrayType?: boolean;
|
||||
}
|
||||
@@ -1547,10 +1559,10 @@ declare namespace ts {
|
||||
endOfFileToken: Token<SyntaxKind.EndOfFileToken>;
|
||||
fileName: string;
|
||||
text: string;
|
||||
amdDependencies: AmdDependency[];
|
||||
amdDependencies: ReadonlyArray<AmdDependency>;
|
||||
moduleName: string;
|
||||
referencedFiles: FileReference[];
|
||||
typeReferenceDirectives: FileReference[];
|
||||
referencedFiles: ReadonlyArray<FileReference>;
|
||||
typeReferenceDirectives: ReadonlyArray<FileReference>;
|
||||
languageVariant: LanguageVariant;
|
||||
isDeclarationFile: boolean;
|
||||
/**
|
||||
@@ -1566,7 +1578,7 @@ declare namespace ts {
|
||||
}
|
||||
interface Bundle extends Node {
|
||||
kind: SyntaxKind.Bundle;
|
||||
sourceFiles: SourceFile[];
|
||||
sourceFiles: ReadonlyArray<SourceFile>;
|
||||
}
|
||||
interface JsonSourceFile extends SourceFile {
|
||||
jsonObject?: ObjectLiteralExpression;
|
||||
@@ -1589,7 +1601,7 @@ declare namespace ts {
|
||||
readFile(path: string): string | undefined;
|
||||
}
|
||||
interface WriteFileCallback {
|
||||
(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void, sourceFiles?: ReadonlyArray<SourceFile>): void;
|
||||
(fileName: string, data: string, writeByteOrderMark: boolean, onError: ((message: string) => void) | undefined, sourceFiles: ReadonlyArray<SourceFile>): void;
|
||||
}
|
||||
class OperationCanceledException {
|
||||
}
|
||||
@@ -1602,11 +1614,11 @@ declare namespace ts {
|
||||
/**
|
||||
* Get a list of root file names that were passed to a 'createProgram'
|
||||
*/
|
||||
getRootFileNames(): string[];
|
||||
getRootFileNames(): ReadonlyArray<string>;
|
||||
/**
|
||||
* Get a list of files in the program
|
||||
*/
|
||||
getSourceFiles(): SourceFile[];
|
||||
getSourceFiles(): ReadonlyArray<SourceFile>;
|
||||
/**
|
||||
* Emits the JavaScript and declaration files. If targetSourceFile is not specified, then
|
||||
* the JavaScript and declaration files will be produced for all the files in this program.
|
||||
@@ -1618,15 +1630,16 @@ declare namespace ts {
|
||||
* will be invoked when writing the JavaScript and declaration files.
|
||||
*/
|
||||
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult;
|
||||
getOptionsDiagnostics(cancellationToken?: CancellationToken): Diagnostic[];
|
||||
getGlobalDiagnostics(cancellationToken?: CancellationToken): Diagnostic[];
|
||||
getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
|
||||
getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
|
||||
getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
|
||||
getOptionsDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
|
||||
getGlobalDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
|
||||
getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
|
||||
getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
|
||||
getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
|
||||
/**
|
||||
* Gets a type checker that can be used to semantically analyze source fils in the program.
|
||||
* Gets a type checker that can be used to semantically analyze source files in the program.
|
||||
*/
|
||||
getTypeChecker(): TypeChecker;
|
||||
isSourceFileFromExternalLibrary(file: SourceFile): boolean;
|
||||
}
|
||||
interface CustomTransformers {
|
||||
/** Custom transformers to evaluate before built-in transformations. */
|
||||
@@ -1669,7 +1682,7 @@ declare namespace ts {
|
||||
interface EmitResult {
|
||||
emitSkipped: boolean;
|
||||
/** Contains declaration emit diagnostics */
|
||||
diagnostics: Diagnostic[];
|
||||
diagnostics: ReadonlyArray<Diagnostic>;
|
||||
emittedFiles: string[];
|
||||
}
|
||||
interface TypeChecker {
|
||||
@@ -1970,6 +1983,7 @@ declare namespace ts {
|
||||
IndexedAccess = 524288,
|
||||
NonPrimitive = 16777216,
|
||||
Literal = 224,
|
||||
Unit = 6368,
|
||||
StringOrNumberLiteral = 96,
|
||||
PossiblyFalsy = 7406,
|
||||
StringLike = 262178,
|
||||
@@ -2172,7 +2186,7 @@ declare namespace ts {
|
||||
interface PluginImport {
|
||||
name: string;
|
||||
}
|
||||
type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike<string[]> | PluginImport[];
|
||||
type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike<string[]> | PluginImport[] | null | undefined;
|
||||
interface CompilerOptions {
|
||||
allowJs?: boolean;
|
||||
allowSyntheticDefaultImports?: boolean;
|
||||
@@ -2372,6 +2386,11 @@ declare namespace ts {
|
||||
* If accessing a non-index file, this should include its name e.g. "foo/bar".
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Name of a submodule within this package.
|
||||
* May be "".
|
||||
*/
|
||||
subModuleName: string;
|
||||
/** Version of the package, e.g. "1.2.3" */
|
||||
version: string;
|
||||
}
|
||||
@@ -2388,14 +2407,15 @@ declare namespace ts {
|
||||
interface ResolvedTypeReferenceDirective {
|
||||
primary: boolean;
|
||||
resolvedFileName?: string;
|
||||
packageId?: PackageId;
|
||||
}
|
||||
interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
|
||||
resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective;
|
||||
failedLookupLocations: string[];
|
||||
}
|
||||
interface CompilerHost extends ModuleResolutionHost {
|
||||
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile;
|
||||
getSourceFileByPath?(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile;
|
||||
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile | undefined;
|
||||
getSourceFileByPath?(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile | undefined;
|
||||
getCancellationToken?(): CancellationToken;
|
||||
getDefaultLibFileName(options: CompilerOptions): string;
|
||||
getDefaultLibLocation?(): string;
|
||||
@@ -2460,7 +2480,8 @@ declare namespace ts {
|
||||
SourceFile = 0,
|
||||
Expression = 1,
|
||||
IdentifierName = 2,
|
||||
Unspecified = 3,
|
||||
MappedTypeParameter = 3,
|
||||
Unspecified = 4,
|
||||
}
|
||||
interface TransformationContext {
|
||||
/** Gets the compiler options supplied to the transformer. */
|
||||
@@ -2639,6 +2660,9 @@ declare namespace ts {
|
||||
/** The version of the TypeScript compiler release */
|
||||
const version: string;
|
||||
}
|
||||
declare namespace ts {
|
||||
function isExternalModuleNameRelative(moduleName: string): boolean;
|
||||
}
|
||||
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): any;
|
||||
declare function clearTimeout(handle: any): void;
|
||||
declare namespace ts {
|
||||
@@ -2834,7 +2858,60 @@ declare namespace ts {
|
||||
* @returns The unescaped identifier text.
|
||||
*/
|
||||
function unescapeIdentifier(id: string): string;
|
||||
function getNameOfDeclaration(declaration: Declaration): DeclarationName | undefined;
|
||||
function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | undefined;
|
||||
function getNameOfDeclaration(declaration: Declaration | Expression): DeclarationName | undefined;
|
||||
/**
|
||||
* Gets the JSDoc parameter tags for the node if present.
|
||||
*
|
||||
* @remarks Returns any JSDoc param tag that matches the provided
|
||||
* parameter, whether a param tag on a containing function
|
||||
* expression, or a param tag on a variable declaration whose
|
||||
* initializer is the containing function. The tags closest to the
|
||||
* node are returned first, so in the previous example, the param
|
||||
* tag on the containing function expression would be first.
|
||||
*
|
||||
* Does not return tags for binding patterns, because JSDoc matches
|
||||
* parameters by name and binding patterns do not have a name.
|
||||
*/
|
||||
function getJSDocParameterTags(param: ParameterDeclaration): ReadonlyArray<JSDocParameterTag> | undefined;
|
||||
/**
|
||||
* Return true if the node has JSDoc parameter tags.
|
||||
*
|
||||
* @remarks Includes parameter tags that are not directly on the node,
|
||||
* for example on a variable declaration whose initializer is a function expression.
|
||||
*/
|
||||
function hasJSDocParameterTags(node: FunctionLikeDeclaration | SignatureDeclaration): boolean;
|
||||
/** Gets the JSDoc augments tag for the node if present */
|
||||
function getJSDocAugmentsTag(node: Node): JSDocAugmentsTag | undefined;
|
||||
/** Gets the JSDoc class tag for the node if present */
|
||||
function getJSDocClassTag(node: Node): JSDocClassTag | undefined;
|
||||
/** Gets the JSDoc return tag for the node if present */
|
||||
function getJSDocReturnTag(node: Node): JSDocReturnTag | undefined;
|
||||
/** Gets the JSDoc template tag for the node if present */
|
||||
function getJSDocTemplateTag(node: Node): JSDocTemplateTag | undefined;
|
||||
/** Gets the JSDoc type tag for the node if present and valid */
|
||||
function getJSDocTypeTag(node: Node): JSDocTypeTag | undefined;
|
||||
/**
|
||||
* Gets the type node for the node if provided via JSDoc.
|
||||
*
|
||||
* @remarks The search includes any JSDoc param tag that relates
|
||||
* to the provided parameter, for example a type tag on the
|
||||
* parameter itself, or a param tag on a containing function
|
||||
* expression, or a param tag on a variable declaration whose
|
||||
* initializer is the containing function. The tags closest to the
|
||||
* node are examined first, so in the previous example, the type
|
||||
* tag directly on the node would be returned.
|
||||
*/
|
||||
function getJSDocType(node: Node): TypeNode | undefined;
|
||||
/**
|
||||
* Gets the return type node for the node if provided via JSDoc's return tag.
|
||||
*
|
||||
* @remarks `getJSDocReturnTag` just gets the whole JSDoc tag. This function
|
||||
* gets the type from inside the braces.
|
||||
*/
|
||||
function getJSDocReturnType(node: Node): TypeNode | undefined;
|
||||
/** Get all JSDoc tags related to a node, including those on parent nodes. */
|
||||
function getJSDocTags(node: Node): ReadonlyArray<JSDocTag> | undefined;
|
||||
}
|
||||
declare namespace ts {
|
||||
function isNumericLiteral(node: Node): node is NumericLiteral;
|
||||
@@ -3184,8 +3261,8 @@ declare namespace ts {
|
||||
function updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode;
|
||||
function createMappedTypeNode(readonlyToken: ReadonlyToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | undefined, type: TypeNode | undefined): MappedTypeNode;
|
||||
function updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | undefined, type: TypeNode | undefined): MappedTypeNode;
|
||||
function createLiteralTypeNode(literal: Expression): LiteralTypeNode;
|
||||
function updateLiteralTypeNode(node: LiteralTypeNode, literal: Expression): LiteralTypeNode;
|
||||
function createLiteralTypeNode(literal: LiteralTypeNode["literal"]): LiteralTypeNode;
|
||||
function updateLiteralTypeNode(node: LiteralTypeNode, literal: LiteralTypeNode["literal"]): LiteralTypeNode;
|
||||
function createObjectBindingPattern(elements: ReadonlyArray<BindingElement>): ObjectBindingPattern;
|
||||
function updateObjectBindingPattern(node: ObjectBindingPattern, elements: ReadonlyArray<BindingElement>): ObjectBindingPattern;
|
||||
function createArrayBindingPattern(elements: ReadonlyArray<ArrayBindingElement>): ArrayBindingPattern;
|
||||
@@ -3214,6 +3291,7 @@ declare namespace ts {
|
||||
function updateFunctionExpression(node: FunctionExpression, modifiers: ReadonlyArray<Modifier> | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration>, type: TypeNode | undefined, body: Block): FunctionExpression;
|
||||
function createArrowFunction(modifiers: ReadonlyArray<Modifier> | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration>, type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken | undefined, body: ConciseBody): ArrowFunction;
|
||||
function updateArrowFunction(node: ArrowFunction, modifiers: ReadonlyArray<Modifier> | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration>, type: TypeNode | undefined, body: ConciseBody): ArrowFunction;
|
||||
function updateArrowFunction(node: ArrowFunction, modifiers: ReadonlyArray<Modifier> | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration>, type: TypeNode | undefined, equalsGreaterThanToken: Token<SyntaxKind.EqualsGreaterThanToken>, body: ConciseBody): ArrowFunction;
|
||||
function createDelete(expression: Expression): DeleteExpression;
|
||||
function updateDelete(node: DeleteExpression, expression: Expression): DeleteExpression;
|
||||
function createTypeOf(expression: Expression): TypeOfExpression;
|
||||
@@ -3231,8 +3309,13 @@ declare namespace ts {
|
||||
function createConditional(condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression;
|
||||
function createConditional(condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression): ConditionalExpression;
|
||||
function updateConditional(node: ConditionalExpression, condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression;
|
||||
function updateConditional(node: ConditionalExpression, condition: Expression, questionToken: Token<SyntaxKind.QuestionToken>, whenTrue: Expression, colonToken: Token<SyntaxKind.ColonToken>, whenFalse: Expression): ConditionalExpression;
|
||||
function createTemplateExpression(head: TemplateHead, templateSpans: ReadonlyArray<TemplateSpan>): TemplateExpression;
|
||||
function updateTemplateExpression(node: TemplateExpression, head: TemplateHead, templateSpans: ReadonlyArray<TemplateSpan>): TemplateExpression;
|
||||
function createTemplateHead(text: string): TemplateHead;
|
||||
function createTemplateMiddle(text: string): TemplateMiddle;
|
||||
function createTemplateTail(text: string): TemplateTail;
|
||||
function createNoSubstitutionTemplateLiteral(text: string): NoSubstitutionTemplateLiteral;
|
||||
function createYield(expression?: Expression): YieldExpression;
|
||||
function createYield(asteriskToken: AsteriskToken, expression: Expression): YieldExpression;
|
||||
function updateYield(node: YieldExpression, asteriskToken: AsteriskToken | undefined, expression: Expression): YieldExpression;
|
||||
@@ -3388,10 +3471,12 @@ declare namespace ts {
|
||||
function updatePartiallyEmittedExpression(node: PartiallyEmittedExpression, expression: Expression): PartiallyEmittedExpression;
|
||||
function createCommaList(elements: ReadonlyArray<Expression>): CommaListExpression;
|
||||
function updateCommaList(node: CommaListExpression, elements: ReadonlyArray<Expression>): CommaListExpression;
|
||||
function createBundle(sourceFiles: SourceFile[]): Bundle;
|
||||
function updateBundle(node: Bundle, sourceFiles: SourceFile[]): Bundle;
|
||||
function createBundle(sourceFiles: ReadonlyArray<SourceFile>): Bundle;
|
||||
function updateBundle(node: Bundle, sourceFiles: ReadonlyArray<SourceFile>): Bundle;
|
||||
function createImmediatelyInvokedFunctionExpression(statements: Statement[]): CallExpression;
|
||||
function createImmediatelyInvokedFunctionExpression(statements: Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression;
|
||||
function createImmediatelyInvokedArrowFunction(statements: Statement[]): CallExpression;
|
||||
function createImmediatelyInvokedArrowFunction(statements: Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression;
|
||||
function createComma(left: Expression, right: Expression): Expression;
|
||||
function createLessThan(left: Expression, right: Expression): Expression;
|
||||
function createAssignment(left: ObjectLiteralExpression | ArrayLiteralExpression, right: Expression): DestructuringAssignment;
|
||||
@@ -3575,8 +3660,8 @@ declare namespace ts {
|
||||
getCanonicalFileName(fileName: string): string;
|
||||
getNewLine(): string;
|
||||
}
|
||||
function formatDiagnostics(diagnostics: Diagnostic[], host: FormatDiagnosticsHost): string;
|
||||
function formatDiagnosticsWithColorAndContext(diagnostics: Diagnostic[], host: FormatDiagnosticsHost): string;
|
||||
function formatDiagnostics(diagnostics: ReadonlyArray<Diagnostic>, host: FormatDiagnosticsHost): string;
|
||||
function formatDiagnosticsWithColorAndContext(diagnostics: ReadonlyArray<Diagnostic>, host: FormatDiagnosticsHost): string;
|
||||
function flattenDiagnosticMessageText(messageText: string | DiagnosticMessageChain, newLine: string): string;
|
||||
/**
|
||||
* Create a new 'Program' instance. A Program is an immutable collection of 'SourceFile's and a 'CompilerOptions'
|
||||
@@ -3591,7 +3676,7 @@ declare namespace ts {
|
||||
* @param oldProgram - Reuses an old program structure.
|
||||
* @returns A 'Program' object.
|
||||
*/
|
||||
function createProgram(rootNames: string[], options: CompilerOptions, host?: CompilerHost, oldProgram?: Program): Program;
|
||||
function createProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program): Program;
|
||||
}
|
||||
declare namespace ts {
|
||||
function parseCommandLine(commandLine: ReadonlyArray<string>, readFile?: (path: string) => string | undefined): ParsedCommandLine;
|
||||
@@ -3700,7 +3785,7 @@ declare namespace ts {
|
||||
interface SourceFile {
|
||||
getLineAndCharacterOfPosition(pos: number): LineAndCharacter;
|
||||
getLineEndOfPosition(pos: number): number;
|
||||
getLineStarts(): number[];
|
||||
getLineStarts(): ReadonlyArray<number>;
|
||||
getPositionOfLineAndCharacter(line: number, character: number): number;
|
||||
update(newText: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
}
|
||||
@@ -3917,7 +4002,7 @@ declare namespace ts {
|
||||
* Represents a single refactoring action - for example, the "Extract Method..." refactor might
|
||||
* offer several actions, each corresponding to a surround class or closure to extract into.
|
||||
*/
|
||||
type RefactorActionInfo = {
|
||||
interface RefactorActionInfo {
|
||||
/**
|
||||
* The programmatic name of the refactoring action
|
||||
*/
|
||||
@@ -3928,16 +4013,16 @@ declare namespace ts {
|
||||
* so this description should make sense by itself if the parent is inlineable=true
|
||||
*/
|
||||
description: string;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* A set of edits to make in response to a refactor action, plus an optional
|
||||
* location where renaming should be invoked from
|
||||
*/
|
||||
type RefactorEditInfo = {
|
||||
interface RefactorEditInfo {
|
||||
edits: FileTextChanges[];
|
||||
renameFilename?: string;
|
||||
renameLocation?: number;
|
||||
};
|
||||
renameFilename: string | undefined;
|
||||
renameLocation: number | undefined;
|
||||
}
|
||||
interface TextInsertion {
|
||||
newText: string;
|
||||
/** The position in newText the caret should point to after the insertion. */
|
||||
|
||||
+2896
-2113
File diff suppressed because it is too large
Load Diff
Vendored
+158
-73
@@ -446,6 +446,9 @@ declare namespace ts {
|
||||
modifiers?: ModifiersArray;
|
||||
parent?: Node;
|
||||
}
|
||||
interface JSDocContainer {
|
||||
}
|
||||
type HasJSDoc = ParameterDeclaration | CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignature | PropertySignature | ArrowFunction | ParenthesizedExpression | SpreadAssignment | ShorthandPropertyAssignment | PropertyAssignment | FunctionExpression | LabeledStatement | ExpressionStatement | VariableStatement | FunctionDeclaration | ConstructorDeclaration | MethodDeclaration | PropertyDeclaration | AccessorDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumMember | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | EndOfFileToken;
|
||||
interface NodeArray<T extends Node> extends ReadonlyArray<T>, TextRange {
|
||||
hasTrailingComma?: boolean;
|
||||
}
|
||||
@@ -458,7 +461,7 @@ declare namespace ts {
|
||||
type EqualsToken = Token<SyntaxKind.EqualsToken>;
|
||||
type AsteriskToken = Token<SyntaxKind.AsteriskToken>;
|
||||
type EqualsGreaterThanToken = Token<SyntaxKind.EqualsGreaterThanToken>;
|
||||
type EndOfFileToken = Token<SyntaxKind.EndOfFileToken>;
|
||||
type EndOfFileToken = Token<SyntaxKind.EndOfFileToken> & JSDocContainer;
|
||||
type AtToken = Token<SyntaxKind.AtToken>;
|
||||
type ReadonlyToken = Token<SyntaxKind.ReadonlyKeyword>;
|
||||
type AwaitKeywordToken = Token<SyntaxKind.AwaitKeyword>;
|
||||
@@ -500,6 +503,7 @@ declare namespace ts {
|
||||
}
|
||||
interface Decorator extends Node {
|
||||
kind: SyntaxKind.Decorator;
|
||||
parent?: NamedDeclaration;
|
||||
expression: LeftHandSideExpression;
|
||||
}
|
||||
interface TypeParameterDeclaration extends NamedDeclaration {
|
||||
@@ -510,16 +514,18 @@ declare namespace ts {
|
||||
default?: TypeNode;
|
||||
expression?: Expression;
|
||||
}
|
||||
interface SignatureDeclaration extends NamedDeclaration {
|
||||
interface SignatureDeclarationBase extends NamedDeclaration, JSDocContainer {
|
||||
kind: SignatureDeclaration["kind"];
|
||||
name?: PropertyName;
|
||||
typeParameters?: NodeArray<TypeParameterDeclaration>;
|
||||
parameters: NodeArray<ParameterDeclaration>;
|
||||
type?: TypeNode;
|
||||
type: TypeNode | undefined;
|
||||
}
|
||||
interface CallSignatureDeclaration extends SignatureDeclaration, TypeElement {
|
||||
type SignatureDeclaration = CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignature | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | AccessorDeclaration | FunctionExpression | ArrowFunction;
|
||||
interface CallSignatureDeclaration extends SignatureDeclarationBase, TypeElement {
|
||||
kind: SyntaxKind.CallSignature;
|
||||
}
|
||||
interface ConstructSignatureDeclaration extends SignatureDeclaration, TypeElement {
|
||||
interface ConstructSignatureDeclaration extends SignatureDeclarationBase, TypeElement {
|
||||
kind: SyntaxKind.ConstructSignature;
|
||||
}
|
||||
type BindingName = Identifier | BindingPattern;
|
||||
@@ -535,7 +541,7 @@ declare namespace ts {
|
||||
parent?: VariableStatement | ForStatement | ForOfStatement | ForInStatement;
|
||||
declarations: NodeArray<VariableDeclaration>;
|
||||
}
|
||||
interface ParameterDeclaration extends NamedDeclaration {
|
||||
interface ParameterDeclaration extends NamedDeclaration, JSDocContainer {
|
||||
kind: SyntaxKind.Parameter;
|
||||
parent?: SignatureDeclaration;
|
||||
dotDotDotToken?: DotDotDotToken;
|
||||
@@ -552,14 +558,14 @@ declare namespace ts {
|
||||
name: BindingName;
|
||||
initializer?: Expression;
|
||||
}
|
||||
interface PropertySignature extends TypeElement {
|
||||
interface PropertySignature extends TypeElement, JSDocContainer {
|
||||
kind: SyntaxKind.PropertySignature;
|
||||
name: PropertyName;
|
||||
questionToken?: QuestionToken;
|
||||
type?: TypeNode;
|
||||
initializer?: Expression;
|
||||
}
|
||||
interface PropertyDeclaration extends ClassElement {
|
||||
interface PropertyDeclaration extends ClassElement, JSDocContainer {
|
||||
kind: SyntaxKind.PropertyDeclaration;
|
||||
questionToken?: QuestionToken;
|
||||
name: PropertyName;
|
||||
@@ -571,27 +577,30 @@ declare namespace ts {
|
||||
name?: PropertyName;
|
||||
}
|
||||
type ObjectLiteralElementLike = PropertyAssignment | ShorthandPropertyAssignment | SpreadAssignment | MethodDeclaration | AccessorDeclaration;
|
||||
interface PropertyAssignment extends ObjectLiteralElement {
|
||||
interface PropertyAssignment extends ObjectLiteralElement, JSDocContainer {
|
||||
parent: ObjectLiteralExpression;
|
||||
kind: SyntaxKind.PropertyAssignment;
|
||||
name: PropertyName;
|
||||
questionToken?: QuestionToken;
|
||||
initializer: Expression;
|
||||
}
|
||||
interface ShorthandPropertyAssignment extends ObjectLiteralElement {
|
||||
interface ShorthandPropertyAssignment extends ObjectLiteralElement, JSDocContainer {
|
||||
parent: ObjectLiteralExpression;
|
||||
kind: SyntaxKind.ShorthandPropertyAssignment;
|
||||
name: Identifier;
|
||||
questionToken?: QuestionToken;
|
||||
equalsToken?: Token<SyntaxKind.EqualsToken>;
|
||||
objectAssignmentInitializer?: Expression;
|
||||
}
|
||||
interface SpreadAssignment extends ObjectLiteralElement {
|
||||
interface SpreadAssignment extends ObjectLiteralElement, JSDocContainer {
|
||||
parent: ObjectLiteralExpression;
|
||||
kind: SyntaxKind.SpreadAssignment;
|
||||
expression: Expression;
|
||||
}
|
||||
interface VariableLikeDeclaration extends NamedDeclaration {
|
||||
propertyName?: PropertyName;
|
||||
dotDotDotToken?: DotDotDotToken;
|
||||
name?: DeclarationName;
|
||||
name: DeclarationName;
|
||||
questionToken?: QuestionToken;
|
||||
type?: TypeNode;
|
||||
initializer?: Expression;
|
||||
@@ -619,7 +628,7 @@ declare namespace ts {
|
||||
* - MethodDeclaration
|
||||
* - AccessorDeclaration
|
||||
*/
|
||||
interface FunctionLikeDeclarationBase extends SignatureDeclaration {
|
||||
interface FunctionLikeDeclarationBase extends SignatureDeclarationBase {
|
||||
_functionLikeDeclarationBrand: any;
|
||||
asteriskToken?: AsteriskToken;
|
||||
questionToken?: QuestionToken;
|
||||
@@ -632,16 +641,16 @@ declare namespace ts {
|
||||
name?: Identifier;
|
||||
body?: FunctionBody;
|
||||
}
|
||||
interface MethodSignature extends SignatureDeclaration, TypeElement {
|
||||
interface MethodSignature extends SignatureDeclarationBase, TypeElement {
|
||||
kind: SyntaxKind.MethodSignature;
|
||||
name: PropertyName;
|
||||
}
|
||||
interface MethodDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement {
|
||||
interface MethodDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
|
||||
kind: SyntaxKind.MethodDeclaration;
|
||||
name: PropertyName;
|
||||
body?: FunctionBody;
|
||||
}
|
||||
interface ConstructorDeclaration extends FunctionLikeDeclarationBase, ClassElement {
|
||||
interface ConstructorDeclaration extends FunctionLikeDeclarationBase, ClassElement, JSDocContainer {
|
||||
kind: SyntaxKind.Constructor;
|
||||
parent?: ClassDeclaration | ClassExpression;
|
||||
body?: FunctionBody;
|
||||
@@ -651,20 +660,20 @@ declare namespace ts {
|
||||
kind: SyntaxKind.SemicolonClassElement;
|
||||
parent?: ClassDeclaration | ClassExpression;
|
||||
}
|
||||
interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement {
|
||||
interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
|
||||
kind: SyntaxKind.GetAccessor;
|
||||
parent?: ClassDeclaration | ClassExpression | ObjectLiteralExpression;
|
||||
name: PropertyName;
|
||||
body: FunctionBody;
|
||||
}
|
||||
interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement {
|
||||
interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
|
||||
kind: SyntaxKind.SetAccessor;
|
||||
parent?: ClassDeclaration | ClassExpression | ObjectLiteralExpression;
|
||||
name: PropertyName;
|
||||
body: FunctionBody;
|
||||
}
|
||||
type AccessorDeclaration = GetAccessorDeclaration | SetAccessorDeclaration;
|
||||
interface IndexSignatureDeclaration extends SignatureDeclaration, ClassElement, TypeElement {
|
||||
interface IndexSignatureDeclaration extends SignatureDeclarationBase, ClassElement, TypeElement {
|
||||
kind: SyntaxKind.IndexSignature;
|
||||
parent?: ClassDeclaration | ClassExpression | InterfaceDeclaration | TypeLiteralNode;
|
||||
}
|
||||
@@ -678,10 +687,10 @@ declare namespace ts {
|
||||
kind: SyntaxKind.ThisType;
|
||||
}
|
||||
type FunctionOrConstructorTypeNode = FunctionTypeNode | ConstructorTypeNode;
|
||||
interface FunctionTypeNode extends TypeNode, SignatureDeclaration {
|
||||
interface FunctionTypeNode extends TypeNode, SignatureDeclarationBase {
|
||||
kind: SyntaxKind.FunctionType;
|
||||
}
|
||||
interface ConstructorTypeNode extends TypeNode, SignatureDeclaration {
|
||||
interface ConstructorTypeNode extends TypeNode, SignatureDeclarationBase {
|
||||
kind: SyntaxKind.ConstructorType;
|
||||
}
|
||||
type TypeReferenceType = TypeReferenceNode | ExpressionWithTypeArguments;
|
||||
@@ -692,6 +701,7 @@ declare namespace ts {
|
||||
}
|
||||
interface TypePredicateNode extends TypeNode {
|
||||
kind: SyntaxKind.TypePredicate;
|
||||
parent?: SignatureDeclaration;
|
||||
parameterName: Identifier | ThisTypeNode;
|
||||
type: TypeNode;
|
||||
}
|
||||
@@ -736,7 +746,6 @@ declare namespace ts {
|
||||
}
|
||||
interface MappedTypeNode extends TypeNode, Declaration {
|
||||
kind: SyntaxKind.MappedType;
|
||||
parent?: TypeAliasDeclaration;
|
||||
readonlyToken?: ReadonlyToken;
|
||||
typeParameter: TypeParameterDeclaration;
|
||||
questionToken?: QuestionToken;
|
||||
@@ -744,7 +753,7 @@ declare namespace ts {
|
||||
}
|
||||
interface LiteralTypeNode extends TypeNode {
|
||||
kind: SyntaxKind.LiteralType;
|
||||
literal: Expression;
|
||||
literal: BooleanLiteral | LiteralExpression | PrefixUnaryExpression;
|
||||
}
|
||||
interface StringLiteral extends LiteralExpression {
|
||||
kind: SyntaxKind.StringLiteral;
|
||||
@@ -879,12 +888,12 @@ declare namespace ts {
|
||||
}
|
||||
type FunctionBody = Block;
|
||||
type ConciseBody = FunctionBody | Expression;
|
||||
interface FunctionExpression extends PrimaryExpression, FunctionLikeDeclarationBase {
|
||||
interface FunctionExpression extends PrimaryExpression, FunctionLikeDeclarationBase, JSDocContainer {
|
||||
kind: SyntaxKind.FunctionExpression;
|
||||
name?: Identifier;
|
||||
body: FunctionBody;
|
||||
}
|
||||
interface ArrowFunction extends Expression, FunctionLikeDeclarationBase {
|
||||
interface ArrowFunction extends Expression, FunctionLikeDeclarationBase, JSDocContainer {
|
||||
kind: SyntaxKind.ArrowFunction;
|
||||
equalsGreaterThanToken: EqualsGreaterThanToken;
|
||||
body: ConciseBody;
|
||||
@@ -930,7 +939,7 @@ declare namespace ts {
|
||||
expression: Expression;
|
||||
literal: TemplateMiddle | TemplateTail;
|
||||
}
|
||||
interface ParenthesizedExpression extends PrimaryExpression {
|
||||
interface ParenthesizedExpression extends PrimaryExpression, JSDocContainer {
|
||||
kind: SyntaxKind.ParenthesizedExpression;
|
||||
expression: Expression;
|
||||
}
|
||||
@@ -940,6 +949,7 @@ declare namespace ts {
|
||||
}
|
||||
interface SpreadElement extends Expression {
|
||||
kind: SyntaxKind.SpreadElement;
|
||||
parent?: ArrayLiteralExpression | CallExpression | NewExpression;
|
||||
expression: Expression;
|
||||
}
|
||||
/**
|
||||
@@ -1107,11 +1117,11 @@ declare namespace ts {
|
||||
kind: SyntaxKind.Block;
|
||||
statements: NodeArray<Statement>;
|
||||
}
|
||||
interface VariableStatement extends Statement {
|
||||
interface VariableStatement extends Statement, JSDocContainer {
|
||||
kind: SyntaxKind.VariableStatement;
|
||||
declarationList: VariableDeclarationList;
|
||||
}
|
||||
interface ExpressionStatement extends Statement {
|
||||
interface ExpressionStatement extends Statement, JSDocContainer {
|
||||
kind: SyntaxKind.ExpressionStatement;
|
||||
expression: Expression;
|
||||
}
|
||||
@@ -1192,7 +1202,7 @@ declare namespace ts {
|
||||
statements: NodeArray<Statement>;
|
||||
}
|
||||
type CaseOrDefaultClause = CaseClause | DefaultClause;
|
||||
interface LabeledStatement extends Statement {
|
||||
interface LabeledStatement extends Statement, JSDocContainer {
|
||||
kind: SyntaxKind.LabeledStatement;
|
||||
label: Identifier;
|
||||
statement: Statement;
|
||||
@@ -1214,19 +1224,21 @@ declare namespace ts {
|
||||
block: Block;
|
||||
}
|
||||
type DeclarationWithTypeParameters = SignatureDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | JSDocTemplateTag;
|
||||
interface ClassLikeDeclaration extends NamedDeclaration {
|
||||
interface ClassLikeDeclarationBase extends NamedDeclaration, JSDocContainer {
|
||||
kind: SyntaxKind.ClassDeclaration | SyntaxKind.ClassExpression;
|
||||
name?: Identifier;
|
||||
typeParameters?: NodeArray<TypeParameterDeclaration>;
|
||||
heritageClauses?: NodeArray<HeritageClause>;
|
||||
members: NodeArray<ClassElement>;
|
||||
}
|
||||
interface ClassDeclaration extends ClassLikeDeclaration, DeclarationStatement {
|
||||
interface ClassDeclaration extends ClassLikeDeclarationBase, DeclarationStatement {
|
||||
kind: SyntaxKind.ClassDeclaration;
|
||||
name?: Identifier;
|
||||
}
|
||||
interface ClassExpression extends ClassLikeDeclaration, PrimaryExpression {
|
||||
interface ClassExpression extends ClassLikeDeclarationBase, PrimaryExpression {
|
||||
kind: SyntaxKind.ClassExpression;
|
||||
}
|
||||
type ClassLikeDeclaration = ClassDeclaration | ClassExpression;
|
||||
interface ClassElement extends NamedDeclaration {
|
||||
_classElementBrand: any;
|
||||
name?: PropertyName;
|
||||
@@ -1236,7 +1248,7 @@ declare namespace ts {
|
||||
name?: PropertyName;
|
||||
questionToken?: QuestionToken;
|
||||
}
|
||||
interface InterfaceDeclaration extends DeclarationStatement {
|
||||
interface InterfaceDeclaration extends DeclarationStatement, JSDocContainer {
|
||||
kind: SyntaxKind.InterfaceDeclaration;
|
||||
name: Identifier;
|
||||
typeParameters?: NodeArray<TypeParameterDeclaration>;
|
||||
@@ -1249,26 +1261,26 @@ declare namespace ts {
|
||||
token: SyntaxKind.ExtendsKeyword | SyntaxKind.ImplementsKeyword;
|
||||
types: NodeArray<ExpressionWithTypeArguments>;
|
||||
}
|
||||
interface TypeAliasDeclaration extends DeclarationStatement {
|
||||
interface TypeAliasDeclaration extends DeclarationStatement, JSDocContainer {
|
||||
kind: SyntaxKind.TypeAliasDeclaration;
|
||||
name: Identifier;
|
||||
typeParameters?: NodeArray<TypeParameterDeclaration>;
|
||||
type: TypeNode;
|
||||
}
|
||||
interface EnumMember extends NamedDeclaration {
|
||||
interface EnumMember extends NamedDeclaration, JSDocContainer {
|
||||
kind: SyntaxKind.EnumMember;
|
||||
parent?: EnumDeclaration;
|
||||
name: PropertyName;
|
||||
initializer?: Expression;
|
||||
}
|
||||
interface EnumDeclaration extends DeclarationStatement {
|
||||
interface EnumDeclaration extends DeclarationStatement, JSDocContainer {
|
||||
kind: SyntaxKind.EnumDeclaration;
|
||||
name: Identifier;
|
||||
members: NodeArray<EnumMember>;
|
||||
}
|
||||
type ModuleName = Identifier | StringLiteral;
|
||||
type ModuleBody = NamespaceBody | JSDocNamespaceBody;
|
||||
interface ModuleDeclaration extends DeclarationStatement {
|
||||
interface ModuleDeclaration extends DeclarationStatement, JSDocContainer {
|
||||
kind: SyntaxKind.ModuleDeclaration;
|
||||
parent?: ModuleBody | SourceFile;
|
||||
name: ModuleName;
|
||||
@@ -1295,7 +1307,7 @@ declare namespace ts {
|
||||
* - import x = require("mod");
|
||||
* - import x = M.x;
|
||||
*/
|
||||
interface ImportEqualsDeclaration extends DeclarationStatement {
|
||||
interface ImportEqualsDeclaration extends DeclarationStatement, JSDocContainer {
|
||||
kind: SyntaxKind.ImportEqualsDeclaration;
|
||||
parent?: SourceFile | ModuleBlock;
|
||||
name: Identifier;
|
||||
@@ -1407,7 +1419,7 @@ declare namespace ts {
|
||||
kind: SyntaxKind.JSDocOptionalType;
|
||||
type: TypeNode;
|
||||
}
|
||||
interface JSDocFunctionType extends JSDocType, SignatureDeclaration {
|
||||
interface JSDocFunctionType extends JSDocType, SignatureDeclarationBase {
|
||||
kind: SyntaxKind.JSDocFunctionType;
|
||||
}
|
||||
interface JSDocVariadicType extends JSDocType {
|
||||
@@ -1417,6 +1429,7 @@ declare namespace ts {
|
||||
type JSDocTypeReferencingNode = JSDocVariadicType | JSDocOptionalType | JSDocNullableType | JSDocNonNullableType;
|
||||
interface JSDoc extends Node {
|
||||
kind: SyntaxKind.JSDocComment;
|
||||
parent?: HasJSDoc;
|
||||
tags: NodeArray<JSDocTag> | undefined;
|
||||
comment: string | undefined;
|
||||
}
|
||||
@@ -1472,7 +1485,6 @@ declare namespace ts {
|
||||
interface JSDocTypeLiteral extends JSDocType {
|
||||
kind: SyntaxKind.JSDocTypeLiteral;
|
||||
jsDocPropertyTags?: ReadonlyArray<JSDocPropertyLikeTag>;
|
||||
jsDocTypeTag?: JSDocTypeTag;
|
||||
/** If true, then this type literal represents an *array* of its type. */
|
||||
isArrayType?: boolean;
|
||||
}
|
||||
@@ -1547,10 +1559,10 @@ declare namespace ts {
|
||||
endOfFileToken: Token<SyntaxKind.EndOfFileToken>;
|
||||
fileName: string;
|
||||
text: string;
|
||||
amdDependencies: AmdDependency[];
|
||||
amdDependencies: ReadonlyArray<AmdDependency>;
|
||||
moduleName: string;
|
||||
referencedFiles: FileReference[];
|
||||
typeReferenceDirectives: FileReference[];
|
||||
referencedFiles: ReadonlyArray<FileReference>;
|
||||
typeReferenceDirectives: ReadonlyArray<FileReference>;
|
||||
languageVariant: LanguageVariant;
|
||||
isDeclarationFile: boolean;
|
||||
/**
|
||||
@@ -1566,7 +1578,7 @@ declare namespace ts {
|
||||
}
|
||||
interface Bundle extends Node {
|
||||
kind: SyntaxKind.Bundle;
|
||||
sourceFiles: SourceFile[];
|
||||
sourceFiles: ReadonlyArray<SourceFile>;
|
||||
}
|
||||
interface JsonSourceFile extends SourceFile {
|
||||
jsonObject?: ObjectLiteralExpression;
|
||||
@@ -1589,7 +1601,7 @@ declare namespace ts {
|
||||
readFile(path: string): string | undefined;
|
||||
}
|
||||
interface WriteFileCallback {
|
||||
(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void, sourceFiles?: ReadonlyArray<SourceFile>): void;
|
||||
(fileName: string, data: string, writeByteOrderMark: boolean, onError: ((message: string) => void) | undefined, sourceFiles: ReadonlyArray<SourceFile>): void;
|
||||
}
|
||||
class OperationCanceledException {
|
||||
}
|
||||
@@ -1602,11 +1614,11 @@ declare namespace ts {
|
||||
/**
|
||||
* Get a list of root file names that were passed to a 'createProgram'
|
||||
*/
|
||||
getRootFileNames(): string[];
|
||||
getRootFileNames(): ReadonlyArray<string>;
|
||||
/**
|
||||
* Get a list of files in the program
|
||||
*/
|
||||
getSourceFiles(): SourceFile[];
|
||||
getSourceFiles(): ReadonlyArray<SourceFile>;
|
||||
/**
|
||||
* Emits the JavaScript and declaration files. If targetSourceFile is not specified, then
|
||||
* the JavaScript and declaration files will be produced for all the files in this program.
|
||||
@@ -1618,15 +1630,16 @@ declare namespace ts {
|
||||
* will be invoked when writing the JavaScript and declaration files.
|
||||
*/
|
||||
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult;
|
||||
getOptionsDiagnostics(cancellationToken?: CancellationToken): Diagnostic[];
|
||||
getGlobalDiagnostics(cancellationToken?: CancellationToken): Diagnostic[];
|
||||
getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
|
||||
getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
|
||||
getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
|
||||
getOptionsDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
|
||||
getGlobalDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
|
||||
getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
|
||||
getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
|
||||
getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
|
||||
/**
|
||||
* Gets a type checker that can be used to semantically analyze source fils in the program.
|
||||
* Gets a type checker that can be used to semantically analyze source files in the program.
|
||||
*/
|
||||
getTypeChecker(): TypeChecker;
|
||||
isSourceFileFromExternalLibrary(file: SourceFile): boolean;
|
||||
}
|
||||
interface CustomTransformers {
|
||||
/** Custom transformers to evaluate before built-in transformations. */
|
||||
@@ -1669,7 +1682,7 @@ declare namespace ts {
|
||||
interface EmitResult {
|
||||
emitSkipped: boolean;
|
||||
/** Contains declaration emit diagnostics */
|
||||
diagnostics: Diagnostic[];
|
||||
diagnostics: ReadonlyArray<Diagnostic>;
|
||||
emittedFiles: string[];
|
||||
}
|
||||
interface TypeChecker {
|
||||
@@ -1970,6 +1983,7 @@ declare namespace ts {
|
||||
IndexedAccess = 524288,
|
||||
NonPrimitive = 16777216,
|
||||
Literal = 224,
|
||||
Unit = 6368,
|
||||
StringOrNumberLiteral = 96,
|
||||
PossiblyFalsy = 7406,
|
||||
StringLike = 262178,
|
||||
@@ -2172,7 +2186,7 @@ declare namespace ts {
|
||||
interface PluginImport {
|
||||
name: string;
|
||||
}
|
||||
type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike<string[]> | PluginImport[];
|
||||
type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike<string[]> | PluginImport[] | null | undefined;
|
||||
interface CompilerOptions {
|
||||
allowJs?: boolean;
|
||||
allowSyntheticDefaultImports?: boolean;
|
||||
@@ -2372,6 +2386,11 @@ declare namespace ts {
|
||||
* If accessing a non-index file, this should include its name e.g. "foo/bar".
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Name of a submodule within this package.
|
||||
* May be "".
|
||||
*/
|
||||
subModuleName: string;
|
||||
/** Version of the package, e.g. "1.2.3" */
|
||||
version: string;
|
||||
}
|
||||
@@ -2388,14 +2407,15 @@ declare namespace ts {
|
||||
interface ResolvedTypeReferenceDirective {
|
||||
primary: boolean;
|
||||
resolvedFileName?: string;
|
||||
packageId?: PackageId;
|
||||
}
|
||||
interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
|
||||
resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective;
|
||||
failedLookupLocations: string[];
|
||||
}
|
||||
interface CompilerHost extends ModuleResolutionHost {
|
||||
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile;
|
||||
getSourceFileByPath?(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile;
|
||||
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile | undefined;
|
||||
getSourceFileByPath?(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile | undefined;
|
||||
getCancellationToken?(): CancellationToken;
|
||||
getDefaultLibFileName(options: CompilerOptions): string;
|
||||
getDefaultLibLocation?(): string;
|
||||
@@ -2460,7 +2480,8 @@ declare namespace ts {
|
||||
SourceFile = 0,
|
||||
Expression = 1,
|
||||
IdentifierName = 2,
|
||||
Unspecified = 3,
|
||||
MappedTypeParameter = 3,
|
||||
Unspecified = 4,
|
||||
}
|
||||
interface TransformationContext {
|
||||
/** Gets the compiler options supplied to the transformer. */
|
||||
@@ -2639,6 +2660,9 @@ declare namespace ts {
|
||||
/** The version of the TypeScript compiler release */
|
||||
const version: string;
|
||||
}
|
||||
declare namespace ts {
|
||||
function isExternalModuleNameRelative(moduleName: string): boolean;
|
||||
}
|
||||
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): any;
|
||||
declare function clearTimeout(handle: any): void;
|
||||
declare namespace ts {
|
||||
@@ -2834,7 +2858,60 @@ declare namespace ts {
|
||||
* @returns The unescaped identifier text.
|
||||
*/
|
||||
function unescapeIdentifier(id: string): string;
|
||||
function getNameOfDeclaration(declaration: Declaration): DeclarationName | undefined;
|
||||
function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | undefined;
|
||||
function getNameOfDeclaration(declaration: Declaration | Expression): DeclarationName | undefined;
|
||||
/**
|
||||
* Gets the JSDoc parameter tags for the node if present.
|
||||
*
|
||||
* @remarks Returns any JSDoc param tag that matches the provided
|
||||
* parameter, whether a param tag on a containing function
|
||||
* expression, or a param tag on a variable declaration whose
|
||||
* initializer is the containing function. The tags closest to the
|
||||
* node are returned first, so in the previous example, the param
|
||||
* tag on the containing function expression would be first.
|
||||
*
|
||||
* Does not return tags for binding patterns, because JSDoc matches
|
||||
* parameters by name and binding patterns do not have a name.
|
||||
*/
|
||||
function getJSDocParameterTags(param: ParameterDeclaration): ReadonlyArray<JSDocParameterTag> | undefined;
|
||||
/**
|
||||
* Return true if the node has JSDoc parameter tags.
|
||||
*
|
||||
* @remarks Includes parameter tags that are not directly on the node,
|
||||
* for example on a variable declaration whose initializer is a function expression.
|
||||
*/
|
||||
function hasJSDocParameterTags(node: FunctionLikeDeclaration | SignatureDeclaration): boolean;
|
||||
/** Gets the JSDoc augments tag for the node if present */
|
||||
function getJSDocAugmentsTag(node: Node): JSDocAugmentsTag | undefined;
|
||||
/** Gets the JSDoc class tag for the node if present */
|
||||
function getJSDocClassTag(node: Node): JSDocClassTag | undefined;
|
||||
/** Gets the JSDoc return tag for the node if present */
|
||||
function getJSDocReturnTag(node: Node): JSDocReturnTag | undefined;
|
||||
/** Gets the JSDoc template tag for the node if present */
|
||||
function getJSDocTemplateTag(node: Node): JSDocTemplateTag | undefined;
|
||||
/** Gets the JSDoc type tag for the node if present and valid */
|
||||
function getJSDocTypeTag(node: Node): JSDocTypeTag | undefined;
|
||||
/**
|
||||
* Gets the type node for the node if provided via JSDoc.
|
||||
*
|
||||
* @remarks The search includes any JSDoc param tag that relates
|
||||
* to the provided parameter, for example a type tag on the
|
||||
* parameter itself, or a param tag on a containing function
|
||||
* expression, or a param tag on a variable declaration whose
|
||||
* initializer is the containing function. The tags closest to the
|
||||
* node are examined first, so in the previous example, the type
|
||||
* tag directly on the node would be returned.
|
||||
*/
|
||||
function getJSDocType(node: Node): TypeNode | undefined;
|
||||
/**
|
||||
* Gets the return type node for the node if provided via JSDoc's return tag.
|
||||
*
|
||||
* @remarks `getJSDocReturnTag` just gets the whole JSDoc tag. This function
|
||||
* gets the type from inside the braces.
|
||||
*/
|
||||
function getJSDocReturnType(node: Node): TypeNode | undefined;
|
||||
/** Get all JSDoc tags related to a node, including those on parent nodes. */
|
||||
function getJSDocTags(node: Node): ReadonlyArray<JSDocTag> | undefined;
|
||||
}
|
||||
declare namespace ts {
|
||||
function isNumericLiteral(node: Node): node is NumericLiteral;
|
||||
@@ -3184,8 +3261,8 @@ declare namespace ts {
|
||||
function updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode;
|
||||
function createMappedTypeNode(readonlyToken: ReadonlyToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | undefined, type: TypeNode | undefined): MappedTypeNode;
|
||||
function updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | undefined, type: TypeNode | undefined): MappedTypeNode;
|
||||
function createLiteralTypeNode(literal: Expression): LiteralTypeNode;
|
||||
function updateLiteralTypeNode(node: LiteralTypeNode, literal: Expression): LiteralTypeNode;
|
||||
function createLiteralTypeNode(literal: LiteralTypeNode["literal"]): LiteralTypeNode;
|
||||
function updateLiteralTypeNode(node: LiteralTypeNode, literal: LiteralTypeNode["literal"]): LiteralTypeNode;
|
||||
function createObjectBindingPattern(elements: ReadonlyArray<BindingElement>): ObjectBindingPattern;
|
||||
function updateObjectBindingPattern(node: ObjectBindingPattern, elements: ReadonlyArray<BindingElement>): ObjectBindingPattern;
|
||||
function createArrayBindingPattern(elements: ReadonlyArray<ArrayBindingElement>): ArrayBindingPattern;
|
||||
@@ -3214,6 +3291,7 @@ declare namespace ts {
|
||||
function updateFunctionExpression(node: FunctionExpression, modifiers: ReadonlyArray<Modifier> | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration>, type: TypeNode | undefined, body: Block): FunctionExpression;
|
||||
function createArrowFunction(modifiers: ReadonlyArray<Modifier> | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration>, type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken | undefined, body: ConciseBody): ArrowFunction;
|
||||
function updateArrowFunction(node: ArrowFunction, modifiers: ReadonlyArray<Modifier> | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration>, type: TypeNode | undefined, body: ConciseBody): ArrowFunction;
|
||||
function updateArrowFunction(node: ArrowFunction, modifiers: ReadonlyArray<Modifier> | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration>, type: TypeNode | undefined, equalsGreaterThanToken: Token<SyntaxKind.EqualsGreaterThanToken>, body: ConciseBody): ArrowFunction;
|
||||
function createDelete(expression: Expression): DeleteExpression;
|
||||
function updateDelete(node: DeleteExpression, expression: Expression): DeleteExpression;
|
||||
function createTypeOf(expression: Expression): TypeOfExpression;
|
||||
@@ -3231,8 +3309,13 @@ declare namespace ts {
|
||||
function createConditional(condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression;
|
||||
function createConditional(condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression): ConditionalExpression;
|
||||
function updateConditional(node: ConditionalExpression, condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression;
|
||||
function updateConditional(node: ConditionalExpression, condition: Expression, questionToken: Token<SyntaxKind.QuestionToken>, whenTrue: Expression, colonToken: Token<SyntaxKind.ColonToken>, whenFalse: Expression): ConditionalExpression;
|
||||
function createTemplateExpression(head: TemplateHead, templateSpans: ReadonlyArray<TemplateSpan>): TemplateExpression;
|
||||
function updateTemplateExpression(node: TemplateExpression, head: TemplateHead, templateSpans: ReadonlyArray<TemplateSpan>): TemplateExpression;
|
||||
function createTemplateHead(text: string): TemplateHead;
|
||||
function createTemplateMiddle(text: string): TemplateMiddle;
|
||||
function createTemplateTail(text: string): TemplateTail;
|
||||
function createNoSubstitutionTemplateLiteral(text: string): NoSubstitutionTemplateLiteral;
|
||||
function createYield(expression?: Expression): YieldExpression;
|
||||
function createYield(asteriskToken: AsteriskToken, expression: Expression): YieldExpression;
|
||||
function updateYield(node: YieldExpression, asteriskToken: AsteriskToken | undefined, expression: Expression): YieldExpression;
|
||||
@@ -3388,10 +3471,12 @@ declare namespace ts {
|
||||
function updatePartiallyEmittedExpression(node: PartiallyEmittedExpression, expression: Expression): PartiallyEmittedExpression;
|
||||
function createCommaList(elements: ReadonlyArray<Expression>): CommaListExpression;
|
||||
function updateCommaList(node: CommaListExpression, elements: ReadonlyArray<Expression>): CommaListExpression;
|
||||
function createBundle(sourceFiles: SourceFile[]): Bundle;
|
||||
function updateBundle(node: Bundle, sourceFiles: SourceFile[]): Bundle;
|
||||
function createBundle(sourceFiles: ReadonlyArray<SourceFile>): Bundle;
|
||||
function updateBundle(node: Bundle, sourceFiles: ReadonlyArray<SourceFile>): Bundle;
|
||||
function createImmediatelyInvokedFunctionExpression(statements: Statement[]): CallExpression;
|
||||
function createImmediatelyInvokedFunctionExpression(statements: Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression;
|
||||
function createImmediatelyInvokedArrowFunction(statements: Statement[]): CallExpression;
|
||||
function createImmediatelyInvokedArrowFunction(statements: Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression;
|
||||
function createComma(left: Expression, right: Expression): Expression;
|
||||
function createLessThan(left: Expression, right: Expression): Expression;
|
||||
function createAssignment(left: ObjectLiteralExpression | ArrayLiteralExpression, right: Expression): DestructuringAssignment;
|
||||
@@ -3575,8 +3660,8 @@ declare namespace ts {
|
||||
getCanonicalFileName(fileName: string): string;
|
||||
getNewLine(): string;
|
||||
}
|
||||
function formatDiagnostics(diagnostics: Diagnostic[], host: FormatDiagnosticsHost): string;
|
||||
function formatDiagnosticsWithColorAndContext(diagnostics: Diagnostic[], host: FormatDiagnosticsHost): string;
|
||||
function formatDiagnostics(diagnostics: ReadonlyArray<Diagnostic>, host: FormatDiagnosticsHost): string;
|
||||
function formatDiagnosticsWithColorAndContext(diagnostics: ReadonlyArray<Diagnostic>, host: FormatDiagnosticsHost): string;
|
||||
function flattenDiagnosticMessageText(messageText: string | DiagnosticMessageChain, newLine: string): string;
|
||||
/**
|
||||
* Create a new 'Program' instance. A Program is an immutable collection of 'SourceFile's and a 'CompilerOptions'
|
||||
@@ -3591,7 +3676,7 @@ declare namespace ts {
|
||||
* @param oldProgram - Reuses an old program structure.
|
||||
* @returns A 'Program' object.
|
||||
*/
|
||||
function createProgram(rootNames: string[], options: CompilerOptions, host?: CompilerHost, oldProgram?: Program): Program;
|
||||
function createProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program): Program;
|
||||
}
|
||||
declare namespace ts {
|
||||
function parseCommandLine(commandLine: ReadonlyArray<string>, readFile?: (path: string) => string | undefined): ParsedCommandLine;
|
||||
@@ -3700,7 +3785,7 @@ declare namespace ts {
|
||||
interface SourceFile {
|
||||
getLineAndCharacterOfPosition(pos: number): LineAndCharacter;
|
||||
getLineEndOfPosition(pos: number): number;
|
||||
getLineStarts(): number[];
|
||||
getLineStarts(): ReadonlyArray<number>;
|
||||
getPositionOfLineAndCharacter(line: number, character: number): number;
|
||||
update(newText: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
}
|
||||
@@ -3917,7 +4002,7 @@ declare namespace ts {
|
||||
* Represents a single refactoring action - for example, the "Extract Method..." refactor might
|
||||
* offer several actions, each corresponding to a surround class or closure to extract into.
|
||||
*/
|
||||
type RefactorActionInfo = {
|
||||
interface RefactorActionInfo {
|
||||
/**
|
||||
* The programmatic name of the refactoring action
|
||||
*/
|
||||
@@ -3928,16 +4013,16 @@ declare namespace ts {
|
||||
* so this description should make sense by itself if the parent is inlineable=true
|
||||
*/
|
||||
description: string;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* A set of edits to make in response to a refactor action, plus an optional
|
||||
* location where renaming should be invoked from
|
||||
*/
|
||||
type RefactorEditInfo = {
|
||||
interface RefactorEditInfo {
|
||||
edits: FileTextChanges[];
|
||||
renameFilename?: string;
|
||||
renameLocation?: number;
|
||||
};
|
||||
renameFilename: string | undefined;
|
||||
renameLocation: number | undefined;
|
||||
}
|
||||
interface TextInsertion {
|
||||
newText: string;
|
||||
/** The position in newText the caret should point to after the insertion. */
|
||||
|
||||
+2896
-2113
File diff suppressed because it is too large
Load Diff
+606
-366
File diff suppressed because it is too large
Load Diff
@@ -49,6 +49,8 @@
|
||||
"@types/q": "latest",
|
||||
"@types/run-sequence": "latest",
|
||||
"@types/through2": "latest",
|
||||
"@types/xml2js": "^0.4.0",
|
||||
"xml2js": "^0.4.19",
|
||||
"browser-resolve": "^1.11.2",
|
||||
"browserify": "latest",
|
||||
"chai": "latest",
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import * as xml2js from "xml2js";
|
||||
|
||||
function main(): void {
|
||||
const args = process.argv.slice(2);
|
||||
if (args.length !== 3) {
|
||||
console.log("Usage:");
|
||||
console.log("\tnode generateLocalizedDiagnosticMessages.js <lcl source directory> <output directory> <generated diagnostics map file>");
|
||||
return;
|
||||
}
|
||||
|
||||
const inputPath = args[0];
|
||||
const outputPath = args[1];
|
||||
const diagnosticsMapFilePath = args[2];
|
||||
|
||||
// generate the lcg file for enu
|
||||
generateLCGFile();
|
||||
|
||||
// generate other langs
|
||||
fs.readdir(inputPath, (err, files) => {
|
||||
handleError(err);
|
||||
files.forEach(visitDirectory);
|
||||
});
|
||||
|
||||
return;
|
||||
|
||||
function visitDirectory(name: string) {
|
||||
const inputFilePath = path.join(inputPath, name, "diagnosticMessages", "diagnosticMessages.generated.json.lcl");
|
||||
const outputFilePath = path.join(outputPath, name, "diagnosticMessages.generated.json");
|
||||
fs.readFile(inputFilePath, (err, data) => {
|
||||
handleError(err);
|
||||
xml2js.parseString(data.toString(), (err, result) => {
|
||||
handleError(err);
|
||||
writeFile(outputFilePath, xmlObjectToString(result));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function handleError(err: null | object) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function xmlObjectToString(o: any) {
|
||||
const out: any = {};
|
||||
for (const item of o["LCX"]["Item"][0]["Item"][0]["Item"]) {
|
||||
let ItemId = item["$"]["ItemId"];
|
||||
let Val = item["Str"][0]["Tgt"] ? item["Str"][0]["Tgt"][0]["Val"][0] : item["Str"][0]["Val"][0];
|
||||
|
||||
if (typeof ItemId !== "string" || typeof Val !== "string") {
|
||||
console.error("Unexpected XML file structure");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (ItemId.charAt(0) === ";") {
|
||||
ItemId = ItemId.slice(1); // remove leading semicolon
|
||||
}
|
||||
|
||||
Val = Val.replace(/]5D;/, "]"); // unescape `]`
|
||||
out[ItemId] = Val;
|
||||
}
|
||||
return JSON.stringify(out, undefined, 2);
|
||||
}
|
||||
|
||||
|
||||
function ensureDirectoryExists(directoryPath: string, action: () => void) {
|
||||
fs.exists(directoryPath, exists => {
|
||||
if (!exists) {
|
||||
const basePath = path.dirname(directoryPath);
|
||||
if (basePath !== directoryPath) {
|
||||
return ensureDirectoryExists(basePath, () => fs.mkdir(directoryPath, action));
|
||||
}
|
||||
}
|
||||
action();
|
||||
});
|
||||
}
|
||||
|
||||
function writeFile(fileName: string, contents: string) {
|
||||
ensureDirectoryExists(path.dirname(fileName), () => {
|
||||
fs.writeFile(fileName, contents, handleError);
|
||||
});
|
||||
}
|
||||
|
||||
function objectToList(o: Record<string, string>) {
|
||||
const list: { key: string, value: string }[] = [];
|
||||
for (const key in o) {
|
||||
list.push({ key, value: o[key] });
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
function generateLCGFile() {
|
||||
return fs.readFile(diagnosticsMapFilePath, (err, data) => {
|
||||
handleError(err);
|
||||
writeFile(
|
||||
path.join(outputPath, "enu", "diagnosticMessages.generated.json.lcg"),
|
||||
getLCGFileXML(
|
||||
objectToList(JSON.parse(data.toString()))
|
||||
.sort((a, b) => a.key > b.key ? 1 : -1) // lcg sorted by property keys
|
||||
.reduce((s, { key, value }) => s + getItemXML(key, value), "")
|
||||
));
|
||||
});
|
||||
|
||||
function getItemXML(key: string, value: string) {
|
||||
// escape entrt value
|
||||
value = value.replace(/]/, "]5D;");
|
||||
|
||||
return `
|
||||
<Item ItemId=";${key}" ItemType="0" PsrId="306" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[${value}]]></Val>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>`;
|
||||
}
|
||||
|
||||
function getLCGFileXML(items: string) {
|
||||
return `<?xml version="1.0" encoding="utf-8"?>
|
||||
<LCX SchemaVersion="6.0" Name="diagnosticMessages.generated.json" PsrId="306" FileType="1" SrcCul="en-US" xmlns="http://schemas.microsoft.com/locstudio/2006/6/lcx">
|
||||
<OwnedComments>
|
||||
<Cmt Name="Dev" />
|
||||
<Cmt Name="LcxAdmin" />
|
||||
<Cmt Name="Rccx" />
|
||||
</OwnedComments>
|
||||
<Item ItemId=";String Table" ItemType="0" PsrId="306" Leaf="false">
|
||||
<Disp Icon="Expand" Expand="true" Disp="true" LocTbl="false" />
|
||||
<Item ItemId=";Strings" ItemType="0" PsrId="306" Leaf="false">
|
||||
<Disp Icon="Str" Disp="true" LocTbl="false" />${items}
|
||||
</Item>
|
||||
</Item>
|
||||
</LCX>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -244,7 +244,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
Debug.assert(isWellKnownSymbolSyntactically(nameExpression));
|
||||
return getPropertyNameForKnownSymbolName(unescapeLeadingUnderscores((<PropertyAccessExpression>nameExpression).name.escapedText));
|
||||
return getPropertyNameForKnownSymbolName(idText((<PropertyAccessExpression>nameExpression).name));
|
||||
}
|
||||
return getEscapedTextOfIdentifierOrLiteral(<Identifier | LiteralExpression>name);
|
||||
}
|
||||
@@ -1456,11 +1456,6 @@ namespace ts {
|
||||
}
|
||||
|
||||
function declareSymbolAndAddToSymbolTable(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol {
|
||||
// Just call this directly so that the return type of this function stays "void".
|
||||
return declareSymbolAndAddToSymbolTableWorker(node, symbolFlags, symbolExcludes);
|
||||
}
|
||||
|
||||
function declareSymbolAndAddToSymbolTableWorker(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol {
|
||||
switch (container.kind) {
|
||||
// Modules, source files, and classes need specialized handling for how their
|
||||
// members are declared (for example, a member of a class will go into a specific
|
||||
@@ -1683,6 +1678,9 @@ namespace ts {
|
||||
|
||||
function bindAnonymousDeclaration(node: Declaration, symbolFlags: SymbolFlags, name: __String) {
|
||||
const symbol = createSymbol(symbolFlags, name);
|
||||
if (symbolFlags & SymbolFlags.EnumMember) {
|
||||
symbol.parent = container.symbol;
|
||||
}
|
||||
addDeclarationToSymbol(symbol, node, symbolFlags);
|
||||
}
|
||||
|
||||
@@ -1779,7 +1777,7 @@ namespace ts {
|
||||
// otherwise report generic error message.
|
||||
const span = getErrorSpanForNode(file, name);
|
||||
file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length,
|
||||
getStrictModeEvalOrArgumentsMessage(contextNode), unescapeLeadingUnderscores(identifier.escapedText)));
|
||||
getStrictModeEvalOrArgumentsMessage(contextNode), idText(identifier)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2433,7 +2431,7 @@ namespace ts {
|
||||
if (node.name) {
|
||||
node.name.parent = node;
|
||||
}
|
||||
file.bindDiagnostics.push(createDiagnosticForNode(symbolExport.declarations[0], Diagnostics.Duplicate_identifier_0, unescapeLeadingUnderscores(prototypeSymbol.escapedName)));
|
||||
file.bindDiagnostics.push(createDiagnosticForNode(symbolExport.declarations[0], Diagnostics.Duplicate_identifier_0, symbolName(prototypeSymbol)));
|
||||
}
|
||||
symbol.exports.set(prototypeSymbol.escapedName, prototypeSymbol);
|
||||
prototypeSymbol.parent = symbol;
|
||||
|
||||
@@ -0,0 +1,534 @@
|
||||
/// <reference path="program.ts" />
|
||||
|
||||
namespace ts {
|
||||
export interface EmitOutput {
|
||||
outputFiles: OutputFile[];
|
||||
emitSkipped: boolean;
|
||||
}
|
||||
|
||||
export interface EmitOutputDetailed extends EmitOutput {
|
||||
diagnostics: Diagnostic[];
|
||||
sourceMaps: SourceMapData[];
|
||||
emittedSourceFiles: SourceFile[];
|
||||
}
|
||||
|
||||
export interface OutputFile {
|
||||
name: string;
|
||||
writeByteOrderMark: boolean;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export function getFileEmitOutput(program: Program, sourceFile: SourceFile, emitOnlyDtsFiles: boolean, isDetailed: boolean,
|
||||
cancellationToken?: CancellationToken, customTransformers?: CustomTransformers): EmitOutput | EmitOutputDetailed {
|
||||
const outputFiles: OutputFile[] = [];
|
||||
let emittedSourceFiles: SourceFile[];
|
||||
const emitResult = program.emit(sourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers);
|
||||
if (!isDetailed) {
|
||||
return { outputFiles, emitSkipped: emitResult.emitSkipped };
|
||||
}
|
||||
|
||||
return {
|
||||
outputFiles,
|
||||
emitSkipped: emitResult.emitSkipped,
|
||||
diagnostics: emitResult.diagnostics,
|
||||
sourceMaps: emitResult.sourceMaps,
|
||||
emittedSourceFiles
|
||||
};
|
||||
|
||||
function writeFile(fileName: string, text: string, writeByteOrderMark: boolean, _onError: (message: string) => void, sourceFiles: SourceFile[]) {
|
||||
outputFiles.push({ name: fileName, writeByteOrderMark, text });
|
||||
if (isDetailed) {
|
||||
emittedSourceFiles = addRange(emittedSourceFiles, sourceFiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export interface Builder {
|
||||
/**
|
||||
* Call this to feed new program
|
||||
*/
|
||||
updateProgram(newProgram: Program): void;
|
||||
getFilesAffectedBy(program: Program, path: Path): string[];
|
||||
emitFile(program: Program, path: Path): EmitOutput;
|
||||
|
||||
/** Emit the changed files and clear the cache of the changed files */
|
||||
emitChangedFiles(program: Program): EmitOutputDetailed[];
|
||||
/** When called gets the semantic diagnostics for the program. It also caches the diagnostics and manage them */
|
||||
getSemanticDiagnostics(program: Program, cancellationToken?: CancellationToken): Diagnostic[];
|
||||
|
||||
/** Called to reset the status of the builder */
|
||||
clear(): void;
|
||||
}
|
||||
|
||||
interface EmitHandler {
|
||||
/**
|
||||
* Called when sourceFile is added to the program
|
||||
*/
|
||||
onAddSourceFile(program: Program, sourceFile: SourceFile): void;
|
||||
/**
|
||||
* Called when sourceFile is removed from the program
|
||||
*/
|
||||
onRemoveSourceFile(path: Path): void;
|
||||
/**
|
||||
* Called when sourceFile is changed
|
||||
*/
|
||||
onUpdateSourceFile(program: Program, sourceFile: SourceFile): void;
|
||||
/**
|
||||
* Called when source file has not changed but has some of the resolutions invalidated
|
||||
* If returned true, builder will mark the file as changed (noting that something associated with file has changed)
|
||||
*/
|
||||
onUpdateSourceFileWithSameVersion(program: Program, sourceFile: SourceFile): boolean;
|
||||
/**
|
||||
* Gets the files affected by the script info which has updated shape from the known one
|
||||
*/
|
||||
getFilesAffectedByUpdatedShape(program: Program, sourceFile: SourceFile, singleFileResult: string[]): string[];
|
||||
}
|
||||
|
||||
interface FileInfo {
|
||||
fileName: string;
|
||||
version: string;
|
||||
signature: string;
|
||||
}
|
||||
|
||||
export interface BuilderOptions {
|
||||
getCanonicalFileName: (fileName: string) => string;
|
||||
getEmitOutput: (program: Program, sourceFile: SourceFile, emitOnlyDtsFiles: boolean, isDetailed: boolean) => EmitOutput | EmitOutputDetailed;
|
||||
computeHash: (data: string) => string;
|
||||
shouldEmitFile: (sourceFile: SourceFile) => boolean;
|
||||
}
|
||||
|
||||
export function createBuilder(options: BuilderOptions): Builder {
|
||||
let isModuleEmit: boolean | undefined;
|
||||
const fileInfos = createMap<FileInfo>();
|
||||
const semanticDiagnosticsPerFile = createMap<ReadonlyArray<Diagnostic>>();
|
||||
/** The map has key by source file's path that has been changed */
|
||||
const changedFileNames = createMap<string>();
|
||||
let emitHandler: EmitHandler;
|
||||
return {
|
||||
updateProgram,
|
||||
getFilesAffectedBy,
|
||||
emitFile,
|
||||
emitChangedFiles,
|
||||
getSemanticDiagnostics,
|
||||
clear
|
||||
};
|
||||
|
||||
function createProgramGraph(program: Program) {
|
||||
const currentIsModuleEmit = program.getCompilerOptions().module !== ModuleKind.None;
|
||||
if (isModuleEmit !== currentIsModuleEmit) {
|
||||
isModuleEmit = currentIsModuleEmit;
|
||||
emitHandler = isModuleEmit ? getModuleEmitHandler() : getNonModuleEmitHandler();
|
||||
fileInfos.clear();
|
||||
semanticDiagnosticsPerFile.clear();
|
||||
}
|
||||
mutateMap(
|
||||
fileInfos,
|
||||
arrayToMap(program.getSourceFiles(), sourceFile => sourceFile.path),
|
||||
{
|
||||
// Add new file info
|
||||
createNewValue: (_path, sourceFile) => addNewFileInfo(program, sourceFile),
|
||||
// Remove existing file info
|
||||
onDeleteValue: removeExistingFileInfo,
|
||||
// We will update in place instead of deleting existing value and adding new one
|
||||
onExistingValue: (existingInfo, sourceFile) => updateExistingFileInfo(program, existingInfo, sourceFile)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function registerChangedFile(path: Path, fileName: string) {
|
||||
changedFileNames.set(path, fileName);
|
||||
// All changed files need to re-evaluate its semantic diagnostics
|
||||
semanticDiagnosticsPerFile.delete(path);
|
||||
}
|
||||
|
||||
function addNewFileInfo(program: Program, sourceFile: SourceFile): FileInfo {
|
||||
registerChangedFile(sourceFile.path, sourceFile.fileName);
|
||||
emitHandler.onAddSourceFile(program, sourceFile);
|
||||
return { fileName: sourceFile.fileName, version: sourceFile.version, signature: undefined };
|
||||
}
|
||||
|
||||
function removeExistingFileInfo(existingFileInfo: FileInfo, path: Path) {
|
||||
registerChangedFile(path, existingFileInfo.fileName);
|
||||
emitHandler.onRemoveSourceFile(path);
|
||||
}
|
||||
|
||||
function updateExistingFileInfo(program: Program, existingInfo: FileInfo, sourceFile: SourceFile) {
|
||||
if (existingInfo.version !== sourceFile.version) {
|
||||
registerChangedFile(sourceFile.path, sourceFile.fileName);
|
||||
existingInfo.version = sourceFile.version;
|
||||
emitHandler.onUpdateSourceFile(program, sourceFile);
|
||||
}
|
||||
else if (program.hasInvalidatedResolution(sourceFile.path) &&
|
||||
emitHandler.onUpdateSourceFileWithSameVersion(program, sourceFile)) {
|
||||
registerChangedFile(sourceFile.path, sourceFile.fileName);
|
||||
}
|
||||
}
|
||||
|
||||
function ensureProgramGraph(program: Program) {
|
||||
if (!emitHandler) {
|
||||
createProgramGraph(program);
|
||||
}
|
||||
}
|
||||
|
||||
function updateProgram(newProgram: Program) {
|
||||
if (emitHandler) {
|
||||
createProgramGraph(newProgram);
|
||||
}
|
||||
}
|
||||
|
||||
function getFilesAffectedBy(program: Program, path: Path): string[] {
|
||||
ensureProgramGraph(program);
|
||||
|
||||
const sourceFile = program.getSourceFile(path);
|
||||
const singleFileResult = sourceFile && options.shouldEmitFile(sourceFile) ? [sourceFile.fileName] : [];
|
||||
const info = fileInfos.get(path);
|
||||
if (!info || !updateShapeSignature(program, sourceFile, info)) {
|
||||
return singleFileResult;
|
||||
}
|
||||
|
||||
Debug.assert(!!sourceFile);
|
||||
return emitHandler.getFilesAffectedByUpdatedShape(program, sourceFile, singleFileResult);
|
||||
}
|
||||
|
||||
function emitFile(program: Program, path: Path) {
|
||||
ensureProgramGraph(program);
|
||||
if (!fileInfos.has(path)) {
|
||||
return { outputFiles: [], emitSkipped: true };
|
||||
}
|
||||
|
||||
return options.getEmitOutput(program, program.getSourceFileByPath(path), /*emitOnlyDtsFiles*/ false, /*isDetailed*/ false);
|
||||
}
|
||||
|
||||
function enumerateChangedFilesSet(
|
||||
program: Program,
|
||||
onChangedFile: (fileName: string, path: Path) => void,
|
||||
onAffectedFile: (fileName: string, sourceFile: SourceFile) => void
|
||||
) {
|
||||
changedFileNames.forEach((fileName, path) => {
|
||||
onChangedFile(fileName, path as Path);
|
||||
const affectedFiles = getFilesAffectedBy(program, path as Path);
|
||||
for (const file of affectedFiles) {
|
||||
onAffectedFile(file, program.getSourceFile(file));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function enumerateChangedFilesEmitOutput(
|
||||
program: Program,
|
||||
emitOnlyDtsFiles: boolean,
|
||||
onChangedFile: (fileName: string, path: Path) => void,
|
||||
onEmitOutput: (emitOutput: EmitOutputDetailed, sourceFile: SourceFile) => void
|
||||
) {
|
||||
const seenFiles = createMap<true>();
|
||||
enumerateChangedFilesSet(program, onChangedFile, (fileName, sourceFile) => {
|
||||
if (!seenFiles.has(fileName)) {
|
||||
seenFiles.set(fileName, true);
|
||||
if (sourceFile) {
|
||||
// Any affected file shouldnt have the cached diagnostics
|
||||
semanticDiagnosticsPerFile.delete(sourceFile.path);
|
||||
|
||||
const emitOutput = options.getEmitOutput(program, sourceFile, emitOnlyDtsFiles, /*isDetailed*/ true) as EmitOutputDetailed;
|
||||
onEmitOutput(emitOutput, sourceFile);
|
||||
|
||||
// mark all the emitted source files as seen
|
||||
if (emitOutput.emittedSourceFiles) {
|
||||
for (const file of emitOutput.emittedSourceFiles) {
|
||||
seenFiles.set(file.fileName, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function emitChangedFiles(program: Program): EmitOutputDetailed[] {
|
||||
ensureProgramGraph(program);
|
||||
const result: EmitOutputDetailed[] = [];
|
||||
enumerateChangedFilesEmitOutput(program, /*emitOnlyDtsFiles*/ false,
|
||||
/*onChangedFile*/ noop, emitOutput => result.push(emitOutput));
|
||||
changedFileNames.clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
function getSemanticDiagnostics(program: Program, cancellationToken?: CancellationToken): Diagnostic[] {
|
||||
ensureProgramGraph(program);
|
||||
|
||||
// Ensure that changed files have cleared their respective
|
||||
enumerateChangedFilesSet(program, /*onChangedFile*/ noop, (_affectedFileName, sourceFile) => {
|
||||
if (sourceFile) {
|
||||
semanticDiagnosticsPerFile.delete(sourceFile.path);
|
||||
}
|
||||
});
|
||||
|
||||
let diagnostics: Diagnostic[];
|
||||
for (const sourceFile of program.getSourceFiles()) {
|
||||
const path = sourceFile.path;
|
||||
const cachedDiagnostics = semanticDiagnosticsPerFile.get(path);
|
||||
// Report the semantic diagnostics from the cache if we already have those diagnostics present
|
||||
if (cachedDiagnostics) {
|
||||
diagnostics = addRange(diagnostics, cachedDiagnostics);
|
||||
}
|
||||
else {
|
||||
// Diagnostics werent cached, get them from program, and cache the result
|
||||
const cachedDiagnostics = program.getSemanticDiagnostics(sourceFile, cancellationToken);
|
||||
semanticDiagnosticsPerFile.set(path, cachedDiagnostics);
|
||||
diagnostics = addRange(diagnostics, cachedDiagnostics);
|
||||
}
|
||||
}
|
||||
return diagnostics || emptyArray;
|
||||
}
|
||||
|
||||
function clear() {
|
||||
isModuleEmit = undefined;
|
||||
emitHandler = undefined;
|
||||
fileInfos.clear();
|
||||
semanticDiagnosticsPerFile.clear();
|
||||
changedFileNames.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* For script files that contains only ambient external modules, although they are not actually external module files,
|
||||
* they can only be consumed via importing elements from them. Regular script files cannot consume them. Therefore,
|
||||
* there are no point to rebuild all script files if these special files have changed. However, if any statement
|
||||
* in the file is not ambient external module, we treat it as a regular script file.
|
||||
*/
|
||||
function containsOnlyAmbientModules(sourceFile: SourceFile) {
|
||||
for (const statement of sourceFile.statements) {
|
||||
if (!isModuleWithStringLiteralName(statement)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {boolean} indicates if the shape signature has changed since last update.
|
||||
*/
|
||||
function updateShapeSignature(program: Program, sourceFile: SourceFile, info: FileInfo) {
|
||||
const prevSignature = info.signature;
|
||||
let latestSignature: string;
|
||||
if (sourceFile.isDeclarationFile) {
|
||||
latestSignature = options.computeHash(sourceFile.text);
|
||||
info.signature = latestSignature;
|
||||
}
|
||||
else {
|
||||
const emitOutput = options.getEmitOutput(program, sourceFile, /*emitOnlyDtsFiles*/ true, /*isDetailed*/ false);
|
||||
if (emitOutput.outputFiles && emitOutput.outputFiles.length > 0) {
|
||||
latestSignature = options.computeHash(emitOutput.outputFiles[0].text);
|
||||
info.signature = latestSignature;
|
||||
}
|
||||
else {
|
||||
latestSignature = prevSignature;
|
||||
}
|
||||
}
|
||||
|
||||
return !prevSignature || latestSignature !== prevSignature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the referenced files for a file from the program with values for the keys as referenced file's path to be true
|
||||
*/
|
||||
function getReferencedFiles(program: Program, sourceFile: SourceFile): Map<true> | undefined {
|
||||
let referencedFiles: Map<true> | undefined;
|
||||
|
||||
// We need to use a set here since the code can contain the same import twice,
|
||||
// but that will only be one dependency.
|
||||
// To avoid invernal conversion, the key of the referencedFiles map must be of type Path
|
||||
if (sourceFile.imports && sourceFile.imports.length > 0) {
|
||||
const checker: TypeChecker = program.getTypeChecker();
|
||||
for (const importName of sourceFile.imports) {
|
||||
const symbol = checker.getSymbolAtLocation(importName);
|
||||
if (symbol && symbol.declarations && symbol.declarations[0]) {
|
||||
const declarationSourceFile = getSourceFileOfNode(symbol.declarations[0]);
|
||||
if (declarationSourceFile) {
|
||||
addReferencedFile(declarationSourceFile.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const sourceFileDirectory = getDirectoryPath(sourceFile.path);
|
||||
// Handle triple slash references
|
||||
if (sourceFile.referencedFiles && sourceFile.referencedFiles.length > 0) {
|
||||
for (const referencedFile of sourceFile.referencedFiles) {
|
||||
const referencedPath = toPath(referencedFile.fileName, sourceFileDirectory, options.getCanonicalFileName);
|
||||
addReferencedFile(referencedPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle type reference directives
|
||||
if (sourceFile.resolvedTypeReferenceDirectiveNames) {
|
||||
sourceFile.resolvedTypeReferenceDirectiveNames.forEach((resolvedTypeReferenceDirective) => {
|
||||
if (!resolvedTypeReferenceDirective) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fileName = resolvedTypeReferenceDirective.resolvedFileName;
|
||||
const typeFilePath = toPath(fileName, sourceFileDirectory, options.getCanonicalFileName);
|
||||
addReferencedFile(typeFilePath);
|
||||
});
|
||||
}
|
||||
|
||||
return referencedFiles;
|
||||
|
||||
function addReferencedFile(referencedPath: Path) {
|
||||
if (!referencedFiles) {
|
||||
referencedFiles = createMap<true>();
|
||||
}
|
||||
referencedFiles.set(referencedPath, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the emittable files from the program.
|
||||
* @param firstSourceFile This one will be emitted first. See https://github.com/Microsoft/TypeScript/issues/16888
|
||||
*/
|
||||
function getAllEmittableFiles(program: Program, firstSourceFile: SourceFile): string[] {
|
||||
const defaultLibraryFileName = getDefaultLibFileName(program.getCompilerOptions());
|
||||
const sourceFiles = program.getSourceFiles();
|
||||
const result: string[] = [];
|
||||
add(firstSourceFile);
|
||||
for (const sourceFile of sourceFiles) {
|
||||
if (sourceFile !== firstSourceFile) {
|
||||
add(sourceFile);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
function add(sourceFile: SourceFile): void {
|
||||
if (getBaseFileName(sourceFile.fileName) !== defaultLibraryFileName && options.shouldEmitFile(sourceFile)) {
|
||||
result.push(sourceFile.fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getNonModuleEmitHandler(): EmitHandler {
|
||||
return {
|
||||
onAddSourceFile: noop,
|
||||
onRemoveSourceFile: noop,
|
||||
onUpdateSourceFile: noop,
|
||||
onUpdateSourceFileWithSameVersion: returnFalse,
|
||||
getFilesAffectedByUpdatedShape
|
||||
};
|
||||
|
||||
function getFilesAffectedByUpdatedShape(program: Program, sourceFile: SourceFile, singleFileResult: string[]): string[] {
|
||||
const options = program.getCompilerOptions();
|
||||
// If `--out` or `--outFile` is specified, any new emit will result in re-emitting the entire project,
|
||||
// so returning the file itself is good enough.
|
||||
if (options && (options.out || options.outFile)) {
|
||||
return singleFileResult;
|
||||
}
|
||||
return getAllEmittableFiles(program, sourceFile);
|
||||
}
|
||||
}
|
||||
|
||||
function getModuleEmitHandler(): EmitHandler {
|
||||
const references = createMap<Map<true>>();
|
||||
return {
|
||||
onAddSourceFile: setReferences,
|
||||
onRemoveSourceFile,
|
||||
onUpdateSourceFile: updateReferences,
|
||||
onUpdateSourceFileWithSameVersion: updateReferencesTrackingChangedReferences,
|
||||
getFilesAffectedByUpdatedShape
|
||||
};
|
||||
|
||||
function setReferences(program: Program, sourceFile: SourceFile) {
|
||||
const newReferences = getReferencedFiles(program, sourceFile);
|
||||
if (newReferences) {
|
||||
references.set(sourceFile.path, newReferences);
|
||||
}
|
||||
}
|
||||
|
||||
function updateReferences(program: Program, sourceFile: SourceFile) {
|
||||
const newReferences = getReferencedFiles(program, sourceFile);
|
||||
if (newReferences) {
|
||||
references.set(sourceFile.path, newReferences);
|
||||
}
|
||||
else {
|
||||
references.delete(sourceFile.path);
|
||||
}
|
||||
}
|
||||
|
||||
function updateReferencesTrackingChangedReferences(program: Program, sourceFile: SourceFile) {
|
||||
const newReferences = getReferencedFiles(program, sourceFile);
|
||||
if (!newReferences) {
|
||||
// Changed if we had references
|
||||
return references.delete(sourceFile.path);
|
||||
}
|
||||
|
||||
const oldReferences = references.get(sourceFile.path);
|
||||
references.set(sourceFile.path, newReferences);
|
||||
if (!oldReferences || oldReferences.size !== newReferences.size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If there are any new references that werent present previously there is change
|
||||
return forEachEntry(newReferences, (_true, referencedPath) => !oldReferences.delete(referencedPath)) ||
|
||||
// Otherwise its changed if there are more references previously than now
|
||||
!!oldReferences.size;
|
||||
}
|
||||
|
||||
function onRemoveSourceFile(removedFilePath: Path) {
|
||||
// Remove existing references
|
||||
references.forEach((referencesInFile, filePath) => {
|
||||
if (referencesInFile.has(removedFilePath)) {
|
||||
// add files referencing the removedFilePath, as changed files too
|
||||
const referencedByInfo = fileInfos.get(filePath);
|
||||
if (referencedByInfo) {
|
||||
registerChangedFile(filePath as Path, referencedByInfo.fileName);
|
||||
}
|
||||
}
|
||||
});
|
||||
// Delete the entry for the removed file path
|
||||
references.delete(removedFilePath);
|
||||
}
|
||||
|
||||
function getReferencedByPaths(referencedFilePath: Path) {
|
||||
return mapDefinedIter(references.entries(), ([filePath, referencesInFile]) =>
|
||||
referencesInFile.has(referencedFilePath) ? filePath as Path : undefined
|
||||
);
|
||||
}
|
||||
|
||||
function getFilesAffectedByUpdatedShape(program: Program, sourceFile: SourceFile, singleFileResult: string[]): string[] {
|
||||
if (!isExternalModule(sourceFile) && !containsOnlyAmbientModules(sourceFile)) {
|
||||
return getAllEmittableFiles(program, sourceFile);
|
||||
}
|
||||
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
if (compilerOptions && (compilerOptions.isolatedModules || compilerOptions.out || compilerOptions.outFile)) {
|
||||
return singleFileResult;
|
||||
}
|
||||
|
||||
// Now we need to if each file in the referencedBy list has a shape change as well.
|
||||
// Because if so, its own referencedBy files need to be saved as well to make the
|
||||
// emitting result consistent with files on disk.
|
||||
|
||||
const seenFileNamesMap = createMap<string>();
|
||||
const setSeenFileName = (path: Path, sourceFile: SourceFile) => {
|
||||
seenFileNamesMap.set(path, sourceFile && options.shouldEmitFile(sourceFile) ? sourceFile.fileName : undefined);
|
||||
};
|
||||
|
||||
// Start with the paths this file was referenced by
|
||||
const path = sourceFile.path;
|
||||
setSeenFileName(path, sourceFile);
|
||||
const queue = getReferencedByPaths(path);
|
||||
while (queue.length > 0) {
|
||||
const currentPath = queue.pop();
|
||||
if (!seenFileNamesMap.has(currentPath)) {
|
||||
const currentSourceFile = program.getSourceFileByPath(currentPath);
|
||||
if (currentSourceFile && updateShapeSignature(program, currentSourceFile, fileInfos.get(currentPath))) {
|
||||
queue.push(...getReferencedByPaths(currentPath));
|
||||
}
|
||||
setSeenFileName(currentPath, currentSourceFile);
|
||||
}
|
||||
}
|
||||
|
||||
// Return array of values that needs emit
|
||||
return flatMapIter(seenFileNamesMap.values(), value => value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+416
-164
File diff suppressed because it is too large
Load Diff
@@ -269,6 +269,13 @@ namespace ts {
|
||||
category: Diagnostics.Strict_Type_Checking_Options,
|
||||
description: Diagnostics.Enable_strict_null_checks
|
||||
},
|
||||
{
|
||||
name: "strictFunctionTypes",
|
||||
type: "boolean",
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Strict_Type_Checking_Options,
|
||||
description: Diagnostics.Enable_strict_checking_of_function_types
|
||||
},
|
||||
{
|
||||
name: "noImplicitThis",
|
||||
type: "boolean",
|
||||
@@ -885,7 +892,7 @@ namespace ts {
|
||||
*/
|
||||
export function readConfigFile(fileName: string, readFile: (path: string) => string | undefined): { config?: any; error?: Diagnostic } {
|
||||
const textOrDiagnostic = tryReadFile(fileName, readFile);
|
||||
return typeof textOrDiagnostic === "string" ? parseConfigFileTextToJson(fileName, textOrDiagnostic) : { config: {}, error: textOrDiagnostic };
|
||||
return isString(textOrDiagnostic) ? parseConfigFileTextToJson(fileName, textOrDiagnostic) : { config: {}, error: textOrDiagnostic };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -907,7 +914,7 @@ namespace ts {
|
||||
*/
|
||||
export function readJsonConfigFile(fileName: string, readFile: (path: string) => string | undefined): JsonSourceFile {
|
||||
const textOrDiagnostic = tryReadFile(fileName, readFile);
|
||||
return typeof textOrDiagnostic === "string" ? parseJsonText(fileName, textOrDiagnostic) : <JsonSourceFile>{ parseDiagnostics: [textOrDiagnostic] };
|
||||
return isString(textOrDiagnostic) ? parseJsonText(fileName, textOrDiagnostic) : <JsonSourceFile>{ parseDiagnostics: [textOrDiagnostic] };
|
||||
}
|
||||
|
||||
function tryReadFile(fileName: string, readFile: (path: string) => string | undefined): string | Diagnostic {
|
||||
@@ -1111,9 +1118,9 @@ namespace ts {
|
||||
if (!isDoubleQuotedString(valueExpression)) {
|
||||
errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, Diagnostics.String_literal_with_double_quotes_expected));
|
||||
}
|
||||
reportInvalidOptionValue(option && (typeof option.type === "string" && option.type !== "string"));
|
||||
reportInvalidOptionValue(option && (isString(option.type) && option.type !== "string"));
|
||||
const text = (<StringLiteral>valueExpression).text;
|
||||
if (option && typeof option.type !== "string") {
|
||||
if (option && !isString(option.type)) {
|
||||
const customOption = <CommandLineOptionOfCustomType>option;
|
||||
// Validate custom option type
|
||||
if (!customOption.type.has(text.toLowerCase())) {
|
||||
@@ -1184,7 +1191,7 @@ namespace ts {
|
||||
function getCompilerOptionValueTypeString(option: CommandLineOption) {
|
||||
return option.type === "list" ?
|
||||
"Array" :
|
||||
typeof option.type === "string" ? option.type : "string";
|
||||
isString(option.type) ? option.type : "string";
|
||||
}
|
||||
|
||||
function isCompilerOptionsValue(option: CommandLineOption, value: any): value is CompilerOptionsValue {
|
||||
@@ -1193,7 +1200,7 @@ namespace ts {
|
||||
if (option.type === "list") {
|
||||
return isArray(value);
|
||||
}
|
||||
const expectedType = typeof option.type === "string" ? option.type : "string";
|
||||
const expectedType = isString(option.type) ? option.type : "string";
|
||||
return typeof value === expectedType;
|
||||
}
|
||||
}
|
||||
@@ -1413,12 +1420,13 @@ namespace ts {
|
||||
Debug.assert((json === undefined && sourceFile !== undefined) || (json !== undefined && sourceFile === undefined));
|
||||
const errors: Diagnostic[] = [];
|
||||
|
||||
const parsedConfig = parseConfig(json, sourceFile, host, basePath, configFileName, resolutionStack, errors);
|
||||
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
|
||||
const parsedConfig = parseConfig(json, sourceFile, host, basePath, configFileName, getCanonicalFileName, resolutionStack, errors);
|
||||
const { raw } = parsedConfig;
|
||||
const options = extend(existingOptions, parsedConfig.options || {});
|
||||
options.configFilePath = configFileName;
|
||||
setConfigFileInOptions(options, sourceFile);
|
||||
const { fileNames, wildcardDirectories } = getFileNames();
|
||||
const { fileNames, wildcardDirectories, spec } = getFileNames();
|
||||
return {
|
||||
options,
|
||||
fileNames,
|
||||
@@ -1426,15 +1434,16 @@ namespace ts {
|
||||
raw,
|
||||
errors,
|
||||
wildcardDirectories,
|
||||
compileOnSave: !!raw.compileOnSave
|
||||
compileOnSave: !!raw.compileOnSave,
|
||||
configFileSpecs: spec
|
||||
};
|
||||
|
||||
function getFileNames(): ExpandResult {
|
||||
let fileNames: ReadonlyArray<string>;
|
||||
let filesSpecs: ReadonlyArray<string>;
|
||||
if (hasProperty(raw, "files") && !isNullOrUndefined(raw["files"])) {
|
||||
if (isArray(raw["files"])) {
|
||||
fileNames = <ReadonlyArray<string>>raw["files"];
|
||||
if (fileNames.length === 0) {
|
||||
filesSpecs = <ReadonlyArray<string>>raw["files"];
|
||||
if (filesSpecs.length === 0) {
|
||||
createCompilerDiagnosticOnlyIfJson(Diagnostics.The_files_list_in_config_file_0_is_empty, configFileName || "tsconfig.json");
|
||||
}
|
||||
}
|
||||
@@ -1469,19 +1478,13 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
if (fileNames === undefined && includeSpecs === undefined) {
|
||||
if (filesSpecs === undefined && includeSpecs === undefined) {
|
||||
includeSpecs = ["**/*"];
|
||||
}
|
||||
|
||||
const result = matchFileNames(fileNames, includeSpecs, excludeSpecs, configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath, options, host, errors, extraFileExtensions, sourceFile);
|
||||
|
||||
const result = matchFileNames(filesSpecs, includeSpecs, excludeSpecs, configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath, options, host, errors, extraFileExtensions, sourceFile);
|
||||
if (result.fileNames.length === 0 && !hasProperty(raw, "files") && resolutionStack.length === 0) {
|
||||
errors.push(
|
||||
createCompilerDiagnostic(
|
||||
Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2,
|
||||
configFileName || "tsconfig.json",
|
||||
JSON.stringify(includeSpecs || []),
|
||||
JSON.stringify(excludeSpecs || [])));
|
||||
errors.push(getErrorForNoInputFiles(result.spec, configFileName));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1494,6 +1497,20 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function isErrorNoInputFiles(error: Diagnostic) {
|
||||
return error.code === Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function getErrorForNoInputFiles({ includeSpecs, excludeSpecs }: ConfigFileSpecs, configFileName: string | undefined) {
|
||||
return createCompilerDiagnostic(
|
||||
Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2,
|
||||
configFileName || "tsconfig.json",
|
||||
JSON.stringify(includeSpecs || []),
|
||||
JSON.stringify(excludeSpecs || []));
|
||||
}
|
||||
|
||||
interface ParsedTsconfig {
|
||||
raw: any;
|
||||
options?: CompilerOptions;
|
||||
@@ -1515,11 +1532,11 @@ namespace ts {
|
||||
host: ParseConfigHost,
|
||||
basePath: string,
|
||||
configFileName: string,
|
||||
getCanonicalFileName: (fileName: string) => string,
|
||||
resolutionStack: Path[],
|
||||
errors: Push<Diagnostic>,
|
||||
): ParsedTsconfig {
|
||||
basePath = normalizeSlashes(basePath);
|
||||
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
|
||||
const resolvedPath = toPath(configFileName || "", basePath, getCanonicalFileName);
|
||||
|
||||
if (resolutionStack.indexOf(resolvedPath) >= 0) {
|
||||
@@ -1579,7 +1596,7 @@ namespace ts {
|
||||
let extendedConfigPath: Path;
|
||||
|
||||
if (json.extends) {
|
||||
if (typeof json.extends !== "string") {
|
||||
if (!isString(json.extends)) {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "extends", "string"));
|
||||
}
|
||||
else {
|
||||
@@ -1673,7 +1690,7 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
let extendedConfigPath = toPath(extendedConfig, basePath, getCanonicalFileName);
|
||||
if (!host.fileExists(extendedConfigPath) && !endsWith(extendedConfigPath, ".json")) {
|
||||
if (!host.fileExists(extendedConfigPath) && !endsWith(extendedConfigPath, Extension.Json)) {
|
||||
extendedConfigPath = `${extendedConfigPath}.json` as Path;
|
||||
if (!host.fileExists(extendedConfigPath)) {
|
||||
errors.push(createDiagnostic(Diagnostics.File_0_does_not_exist, extendedConfig));
|
||||
@@ -1703,7 +1720,7 @@ namespace ts {
|
||||
|
||||
const extendedDirname = getDirectoryPath(extendedConfigPath);
|
||||
const extendedConfig = parseConfig(/*json*/ undefined, extendedResult, host, extendedDirname,
|
||||
getBaseFileName(extendedConfigPath), resolutionStack, errors);
|
||||
getBaseFileName(extendedConfigPath), getCanonicalFileName, resolutionStack, errors);
|
||||
if (sourceFile) {
|
||||
sourceFile.extendedSourceFiles.push(...extendedResult.extendedSourceFiles);
|
||||
}
|
||||
@@ -1806,7 +1823,7 @@ namespace ts {
|
||||
if (optType === "list" && isArray(value)) {
|
||||
return convertJsonOptionOfListType(<CommandLineOptionOfListType>opt, value, basePath, errors);
|
||||
}
|
||||
else if (typeof optType !== "string") {
|
||||
else if (!isString(optType)) {
|
||||
return convertJsonOptionOfCustomType(<CommandLineOptionOfCustomType>opt, <string>value, errors);
|
||||
}
|
||||
return normalizeNonListOptionValue(opt, basePath, value);
|
||||
@@ -1820,13 +1837,13 @@ namespace ts {
|
||||
if (isNullOrUndefined(value)) return undefined;
|
||||
if (option.type === "list") {
|
||||
const listOption = <CommandLineOptionOfListType>option;
|
||||
if (listOption.element.isFilePath || typeof listOption.element.type !== "string") {
|
||||
if (listOption.element.isFilePath || !isString(listOption.element.type)) {
|
||||
return <CompilerOptionsValue>filter(map(value, v => normalizeOptionValue(listOption.element, basePath, v)), v => !!v);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
else if (typeof option.type !== "string") {
|
||||
return option.type.get(typeof value === "string" ? value.toLowerCase() : value);
|
||||
else if (!isString(option.type)) {
|
||||
return option.type.get(isString(value) ? value.toLowerCase() : value);
|
||||
}
|
||||
return normalizeNonListOptionValue(option, basePath, value);
|
||||
}
|
||||
@@ -1936,29 +1953,63 @@ namespace ts {
|
||||
/**
|
||||
* Expands an array of file specifications.
|
||||
*
|
||||
* @param fileNames The literal file names to include.
|
||||
* @param include The wildcard file specifications to include.
|
||||
* @param exclude The wildcard file specifications to exclude.
|
||||
* @param filesSpecs The literal file names to include.
|
||||
* @param includeSpecs The wildcard file specifications to include.
|
||||
* @param excludeSpecs The wildcard file specifications to exclude.
|
||||
* @param basePath The base path for any relative file specifications.
|
||||
* @param options Compiler options.
|
||||
* @param host The host used to resolve files and directories.
|
||||
* @param errors An array for diagnostic reporting.
|
||||
*/
|
||||
function matchFileNames(
|
||||
fileNames: ReadonlyArray<string>,
|
||||
include: ReadonlyArray<string>,
|
||||
exclude: ReadonlyArray<string>,
|
||||
filesSpecs: ReadonlyArray<string>,
|
||||
includeSpecs: ReadonlyArray<string>,
|
||||
excludeSpecs: ReadonlyArray<string>,
|
||||
basePath: string,
|
||||
options: CompilerOptions,
|
||||
host: ParseConfigHost,
|
||||
errors: Push<Diagnostic>,
|
||||
extraFileExtensions: ReadonlyArray<JsFileExtensionInfo>,
|
||||
jsonSourceFile: JsonSourceFile): ExpandResult {
|
||||
jsonSourceFile: JsonSourceFile
|
||||
): ExpandResult {
|
||||
basePath = normalizePath(basePath);
|
||||
let validatedIncludeSpecs: ReadonlyArray<string>, validatedExcludeSpecs: ReadonlyArray<string>;
|
||||
|
||||
// The exclude spec list is converted into a regular expression, which allows us to quickly
|
||||
// test whether a file or directory should be excluded before recursively traversing the
|
||||
// file system.
|
||||
|
||||
if (includeSpecs) {
|
||||
validatedIncludeSpecs = validateSpecs(includeSpecs, errors, /*allowTrailingRecursion*/ false, jsonSourceFile, "include");
|
||||
}
|
||||
|
||||
if (excludeSpecs) {
|
||||
validatedExcludeSpecs = validateSpecs(excludeSpecs, errors, /*allowTrailingRecursion*/ true, jsonSourceFile, "exclude");
|
||||
}
|
||||
|
||||
// Wildcard directories (provided as part of a wildcard path) are stored in a
|
||||
// file map that marks whether it was a regular wildcard match (with a `*` or `?` token),
|
||||
// or a recursive directory. This information is used by filesystem watchers to monitor for
|
||||
// new entries in these paths.
|
||||
const wildcardDirectories = getWildcardDirectories(validatedIncludeSpecs, validatedExcludeSpecs, basePath, host.useCaseSensitiveFileNames);
|
||||
|
||||
const spec: ConfigFileSpecs = { filesSpecs, includeSpecs, excludeSpecs, validatedIncludeSpecs, validatedExcludeSpecs, wildcardDirectories };
|
||||
return getFileNamesFromConfigSpecs(spec, basePath, options, host, extraFileExtensions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file names from the provided config file specs that contain, files, include, exclude and
|
||||
* other properties needed to resolve the file names
|
||||
* @param spec The config file specs extracted with file names to include, wildcards to include/exclude and other details
|
||||
* @param basePath The base path for any relative file specifications.
|
||||
* @param options Compiler options.
|
||||
* @param host The host used to resolve files and directories.
|
||||
* @param extraFileExtensions optionaly file extra file extension information from host
|
||||
*/
|
||||
/* @internal */
|
||||
export function getFileNamesFromConfigSpecs(spec: ConfigFileSpecs, basePath: string, options: CompilerOptions, host: ParseConfigHost, extraFileExtensions: ReadonlyArray<JsFileExtensionInfo> = []): ExpandResult {
|
||||
basePath = normalizePath(basePath);
|
||||
|
||||
const keyMapper = host.useCaseSensitiveFileNames ? caseSensitiveKeyMapper : caseInsensitiveKeyMapper;
|
||||
|
||||
// Literal file names (provided via the "files" array in tsconfig.json) are stored in a
|
||||
@@ -1971,19 +2022,7 @@ namespace ts {
|
||||
// via wildcard, and to handle extension priority.
|
||||
const wildcardFileMap = createMap<string>();
|
||||
|
||||
if (include) {
|
||||
include = validateSpecs(include, errors, /*allowTrailingRecursion*/ false, jsonSourceFile, "include");
|
||||
}
|
||||
|
||||
if (exclude) {
|
||||
exclude = validateSpecs(exclude, errors, /*allowTrailingRecursion*/ true, jsonSourceFile, "exclude");
|
||||
}
|
||||
|
||||
// Wildcard directories (provided as part of a wildcard path) are stored in a
|
||||
// file map that marks whether it was a regular wildcard match (with a `*` or `?` token),
|
||||
// or a recursive directory. This information is used by filesystem watchers to monitor for
|
||||
// new entries in these paths.
|
||||
const wildcardDirectories = getWildcardDirectories(include, exclude, basePath, host.useCaseSensitiveFileNames);
|
||||
const { filesSpecs, validatedIncludeSpecs, validatedExcludeSpecs, wildcardDirectories } = spec;
|
||||
|
||||
// Rather than requery this for each file and filespec, we query the supported extensions
|
||||
// once and store it on the expansion context.
|
||||
@@ -1991,15 +2030,15 @@ namespace ts {
|
||||
|
||||
// Literal files are always included verbatim. An "include" or "exclude" specification cannot
|
||||
// remove a literal file.
|
||||
if (fileNames) {
|
||||
for (const fileName of fileNames) {
|
||||
if (filesSpecs) {
|
||||
for (const fileName of filesSpecs) {
|
||||
const file = getNormalizedAbsolutePath(fileName, basePath);
|
||||
literalFileMap.set(keyMapper(file), file);
|
||||
}
|
||||
}
|
||||
|
||||
if (include && include.length > 0) {
|
||||
for (const file of host.readDirectory(basePath, supportedExtensions, exclude, include, /*depth*/ undefined)) {
|
||||
if (validatedIncludeSpecs && validatedIncludeSpecs.length > 0) {
|
||||
for (const file of host.readDirectory(basePath, supportedExtensions, validatedExcludeSpecs, validatedIncludeSpecs, /*depth*/ undefined)) {
|
||||
// If we have already included a literal or wildcard path with a
|
||||
// higher priority extension, we should skip this file.
|
||||
//
|
||||
@@ -2027,11 +2066,12 @@ namespace ts {
|
||||
const wildcardFiles = arrayFrom(wildcardFileMap.values());
|
||||
return {
|
||||
fileNames: literalFiles.concat(wildcardFiles),
|
||||
wildcardDirectories
|
||||
wildcardDirectories,
|
||||
spec
|
||||
};
|
||||
}
|
||||
|
||||
function validateSpecs(specs: ReadonlyArray<string>, errors: Push<Diagnostic>, allowTrailingRecursion: boolean, jsonSourceFile: JsonSourceFile, specKey: string) {
|
||||
function validateSpecs(specs: ReadonlyArray<string>, errors: Push<Diagnostic>, allowTrailingRecursion: boolean, jsonSourceFile: JsonSourceFile, specKey: string): ReadonlyArray<string> {
|
||||
return specs.filter(spec => {
|
||||
const diag = specToDiagnostic(spec, allowTrailingRecursion);
|
||||
if (diag !== undefined) {
|
||||
|
||||
+257
-12
@@ -247,6 +247,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** Works like Array.prototype.find, returning `undefined` if no element satisfying the predicate is found. */
|
||||
export function find<T, U extends T>(array: ReadonlyArray<T>, predicate: (element: T, index: number) => element is U): U | undefined;
|
||||
export function find<T>(array: ReadonlyArray<T>, predicate: (element: T, index: number) => boolean): T | undefined;
|
||||
export function find<T>(array: ReadonlyArray<T>, predicate: (element: T, index: number) => boolean): T | undefined {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const value = array[i];
|
||||
@@ -467,13 +469,20 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
export function flatMapIter<T, U>(iter: Iterator<T>, mapfn: (x: T) => U[] | undefined): U[] {
|
||||
export function flatMapIter<T, U>(iter: Iterator<T>, mapfn: (x: T) => U | U[] | undefined): U[] {
|
||||
const result: U[] = [];
|
||||
while (true) {
|
||||
const { value, done } = iter.next();
|
||||
if (done) break;
|
||||
const res = mapfn(value);
|
||||
if (res) result.push(...res);
|
||||
if (res) {
|
||||
if (isArray(res)) {
|
||||
result.push(...res);
|
||||
}
|
||||
else {
|
||||
result.push(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -523,6 +532,19 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
export function mapDefinedIter<T, U>(iter: Iterator<T>, mapFn: (x: T) => U | undefined): U[] {
|
||||
const result: U[] = [];
|
||||
while (true) {
|
||||
const { value, done } = iter.next();
|
||||
if (done) break;
|
||||
const res = mapFn(value);
|
||||
if (res !== undefined) {
|
||||
result.push(res);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the first matching span of elements and returns a tuple of the first span
|
||||
* and the remaining elements.
|
||||
@@ -766,7 +788,7 @@ namespace ts {
|
||||
* @param end The offset in `from` at which to stop copying values (non-inclusive).
|
||||
*/
|
||||
export function addRange<T>(to: T[] | undefined, from: ReadonlyArray<T> | undefined, start?: number, end?: number): T[] | undefined {
|
||||
if (from === undefined) return to;
|
||||
if (from === undefined || from.length === 0) return to;
|
||||
if (to === undefined) return from.slice(start, end);
|
||||
start = start === undefined ? 0 : toOffset(from, start);
|
||||
end = end === undefined ? from.length : toOffset(from, end);
|
||||
@@ -846,6 +868,11 @@ namespace ts {
|
||||
return elementAt(array, 0);
|
||||
}
|
||||
|
||||
export function first<T>(array: ReadonlyArray<T>): T {
|
||||
Debug.assert(array.length !== 0);
|
||||
return array[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last element of an array if non-empty, `undefined` otherwise.
|
||||
*/
|
||||
@@ -853,6 +880,11 @@ namespace ts {
|
||||
return elementAt(array, -1);
|
||||
}
|
||||
|
||||
export function last<T>(array: ReadonlyArray<T>): T {
|
||||
Debug.assert(array.length !== 0);
|
||||
return array[array.length - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the only element of an array if it contains only one element, `undefined` otherwise.
|
||||
*/
|
||||
@@ -1222,6 +1254,13 @@ namespace ts {
|
||||
return Array.isArray ? Array.isArray(value) : value instanceof Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a value is string
|
||||
*/
|
||||
export function isString(text: any): text is string {
|
||||
return typeof text === "string";
|
||||
}
|
||||
|
||||
export function tryCast<TOut extends TIn, TIn = any>(value: TIn | undefined, test: (value: TIn) => value is TOut): TOut | undefined {
|
||||
return value !== undefined && test(value) ? value : undefined;
|
||||
}
|
||||
@@ -1232,7 +1271,13 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** Does nothing. */
|
||||
export function noop(): void {}
|
||||
export function noop(): void { }
|
||||
|
||||
/** Do nothing and return false */
|
||||
export function returnFalse(): false { return false; }
|
||||
|
||||
/** Do nothing and return true */
|
||||
export function returnTrue(): true { return true; }
|
||||
|
||||
/** Returns its argument. */
|
||||
export function identity<T>(x: T) { return x; }
|
||||
@@ -1476,16 +1521,16 @@ namespace ts {
|
||||
function compareMessageText(text1: string | DiagnosticMessageChain, text2: string | DiagnosticMessageChain): Comparison {
|
||||
while (text1 && text2) {
|
||||
// We still have both chains.
|
||||
const string1 = typeof text1 === "string" ? text1 : text1.messageText;
|
||||
const string2 = typeof text2 === "string" ? text2 : text2.messageText;
|
||||
const string1 = isString(text1) ? text1 : text1.messageText;
|
||||
const string2 = isString(text2) ? text2 : text2.messageText;
|
||||
|
||||
const res = compareValues(string1, string2);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
text1 = typeof text1 === "string" ? undefined : text1.next;
|
||||
text2 = typeof text2 === "string" ? undefined : text2.next;
|
||||
text1 = isString(text1) ? undefined : text1.next;
|
||||
text2 = isString(text2) ? undefined : text2.next;
|
||||
}
|
||||
|
||||
if (!text1 && !text2) {
|
||||
@@ -1811,6 +1856,8 @@ namespace ts {
|
||||
* Removes a trailing directory separator from a path.
|
||||
* @param path The path.
|
||||
*/
|
||||
export function removeTrailingDirectorySeparator(path: Path): Path;
|
||||
export function removeTrailingDirectorySeparator(path: string): string;
|
||||
export function removeTrailingDirectorySeparator(path: string) {
|
||||
if (path.charAt(path.length - 1) === directorySeparator) {
|
||||
return path.substr(0, path.length - 1);
|
||||
@@ -2073,8 +2120,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
export interface FileSystemEntries {
|
||||
files: ReadonlyArray<string>;
|
||||
directories: ReadonlyArray<string>;
|
||||
readonly files: ReadonlyArray<string>;
|
||||
readonly directories: ReadonlyArray<string>;
|
||||
}
|
||||
|
||||
export interface FileMatcherPatterns {
|
||||
@@ -2227,7 +2274,7 @@ namespace ts {
|
||||
return ScriptKind.TS;
|
||||
case Extension.Tsx:
|
||||
return ScriptKind.TSX;
|
||||
case ".json":
|
||||
case Extension.Json:
|
||||
return ScriptKind.JSON;
|
||||
default:
|
||||
return ScriptKind.Unknown;
|
||||
@@ -2631,5 +2678,203 @@ namespace ts {
|
||||
return (arg: T) => f(arg) && g(arg);
|
||||
}
|
||||
|
||||
export function assertTypeIsNever(_: never): void {}
|
||||
export function assertTypeIsNever(_: never): void { }
|
||||
|
||||
export interface CachedDirectoryStructureHost extends DirectoryStructureHost {
|
||||
addOrDeleteFileOrDirectory(fileOrDirectory: string, fileOrDirectoryPath: Path): void;
|
||||
addOrDeleteFile(fileName: string, filePath: Path, eventKind: FileWatcherEventKind): void;
|
||||
clearCache(): void;
|
||||
}
|
||||
|
||||
interface MutableFileSystemEntries {
|
||||
readonly files: string[];
|
||||
readonly directories: string[];
|
||||
}
|
||||
|
||||
export function createCachedDirectoryStructureHost(host: DirectoryStructureHost): CachedDirectoryStructureHost {
|
||||
const cachedReadDirectoryResult = createMap<MutableFileSystemEntries>();
|
||||
const getCurrentDirectory = memoize(() => host.getCurrentDirectory());
|
||||
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
|
||||
return {
|
||||
useCaseSensitiveFileNames: host.useCaseSensitiveFileNames,
|
||||
newLine: host.newLine,
|
||||
readFile: (path, encoding) => host.readFile(path, encoding),
|
||||
write: s => host.write(s),
|
||||
writeFile,
|
||||
fileExists,
|
||||
directoryExists,
|
||||
createDirectory,
|
||||
getCurrentDirectory,
|
||||
getDirectories,
|
||||
readDirectory,
|
||||
addOrDeleteFileOrDirectory,
|
||||
addOrDeleteFile,
|
||||
clearCache,
|
||||
exit: code => host.exit(code)
|
||||
};
|
||||
|
||||
function toPath(fileName: string) {
|
||||
return ts.toPath(fileName, getCurrentDirectory(), getCanonicalFileName);
|
||||
}
|
||||
|
||||
function getCachedFileSystemEntries(rootDirPath: Path): MutableFileSystemEntries | undefined {
|
||||
return cachedReadDirectoryResult.get(rootDirPath);
|
||||
}
|
||||
|
||||
function getCachedFileSystemEntriesForBaseDir(path: Path): MutableFileSystemEntries | undefined {
|
||||
return getCachedFileSystemEntries(getDirectoryPath(path));
|
||||
}
|
||||
|
||||
function getBaseNameOfFileName(fileName: string) {
|
||||
return getBaseFileName(normalizePath(fileName));
|
||||
}
|
||||
|
||||
function createCachedFileSystemEntries(rootDir: string, rootDirPath: Path) {
|
||||
const resultFromHost: MutableFileSystemEntries = {
|
||||
files: map(host.readDirectory(rootDir, /*extensions*/ undefined, /*exclude*/ undefined, /*include*/["*.*"]), getBaseNameOfFileName) || [],
|
||||
directories: host.getDirectories(rootDir) || []
|
||||
};
|
||||
|
||||
cachedReadDirectoryResult.set(rootDirPath, resultFromHost);
|
||||
return resultFromHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the readDirectory result was already cached, it returns that
|
||||
* Otherwise gets result from host and caches it.
|
||||
* The host request is done under try catch block to avoid caching incorrect result
|
||||
*/
|
||||
function tryReadDirectory(rootDir: string, rootDirPath: Path): MutableFileSystemEntries | undefined {
|
||||
const cachedResult = getCachedFileSystemEntries(rootDirPath);
|
||||
if (cachedResult) {
|
||||
return cachedResult;
|
||||
}
|
||||
|
||||
try {
|
||||
return createCachedFileSystemEntries(rootDir, rootDirPath);
|
||||
}
|
||||
catch (_e) {
|
||||
// If there is exception to read directories, dont cache the result and direct the calls to host
|
||||
Debug.assert(!cachedReadDirectoryResult.has(rootDirPath));
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function fileNameEqual(name1: string, name2: string) {
|
||||
return getCanonicalFileName(name1) === getCanonicalFileName(name2);
|
||||
}
|
||||
|
||||
function hasEntry(entries: ReadonlyArray<string>, name: string) {
|
||||
return some(entries, file => fileNameEqual(file, name));
|
||||
}
|
||||
|
||||
function updateFileSystemEntry(entries: string[], baseName: string, isValid: boolean) {
|
||||
if (hasEntry(entries, baseName)) {
|
||||
if (!isValid) {
|
||||
return filterMutate(entries, entry => !fileNameEqual(entry, baseName));
|
||||
}
|
||||
}
|
||||
else if (isValid) {
|
||||
return entries.push(baseName);
|
||||
}
|
||||
}
|
||||
|
||||
function writeFile(fileName: string, data: string, writeByteOrderMark?: boolean): void {
|
||||
const path = toPath(fileName);
|
||||
const result = getCachedFileSystemEntriesForBaseDir(path);
|
||||
if (result) {
|
||||
updateFilesOfFileSystemEntry(result, getBaseNameOfFileName(fileName), /*fileExists*/ true);
|
||||
}
|
||||
return host.writeFile(fileName, data, writeByteOrderMark);
|
||||
}
|
||||
|
||||
function fileExists(fileName: string): boolean {
|
||||
const path = toPath(fileName);
|
||||
const result = getCachedFileSystemEntriesForBaseDir(path);
|
||||
return result && hasEntry(result.files, getBaseNameOfFileName(fileName)) ||
|
||||
host.fileExists(fileName);
|
||||
}
|
||||
|
||||
function directoryExists(dirPath: string): boolean {
|
||||
const path = toPath(dirPath);
|
||||
return cachedReadDirectoryResult.has(path) || host.directoryExists(dirPath);
|
||||
}
|
||||
|
||||
function createDirectory(dirPath: string) {
|
||||
const path = toPath(dirPath);
|
||||
const result = getCachedFileSystemEntriesForBaseDir(path);
|
||||
const baseFileName = getBaseNameOfFileName(dirPath);
|
||||
if (result) {
|
||||
updateFileSystemEntry(result.directories, baseFileName, /*isValid*/ true);
|
||||
}
|
||||
host.createDirectory(dirPath);
|
||||
}
|
||||
|
||||
function getDirectories(rootDir: string): string[] {
|
||||
const rootDirPath = toPath(rootDir);
|
||||
const result = tryReadDirectory(rootDir, rootDirPath);
|
||||
if (result) {
|
||||
return result.directories.slice();
|
||||
}
|
||||
return host.getDirectories(rootDir);
|
||||
}
|
||||
|
||||
function readDirectory(rootDir: string, extensions?: ReadonlyArray<string>, excludes?: ReadonlyArray<string>, includes?: ReadonlyArray<string>, depth?: number): string[] {
|
||||
const rootDirPath = toPath(rootDir);
|
||||
const result = tryReadDirectory(rootDir, rootDirPath);
|
||||
if (result) {
|
||||
return matchFiles(rootDir, extensions, excludes, includes, host.useCaseSensitiveFileNames, getCurrentDirectory(), depth, getFileSystemEntries);
|
||||
}
|
||||
return host.readDirectory(rootDir, extensions, excludes, includes, depth);
|
||||
|
||||
function getFileSystemEntries(dir: string) {
|
||||
const path = toPath(dir);
|
||||
if (path === rootDirPath) {
|
||||
return result;
|
||||
}
|
||||
return getCachedFileSystemEntries(path) || createCachedFileSystemEntries(dir, path);
|
||||
}
|
||||
}
|
||||
|
||||
function addOrDeleteFileOrDirectory(fileOrDirectory: string, fileOrDirectoryPath: Path) {
|
||||
const existingResult = getCachedFileSystemEntries(fileOrDirectoryPath);
|
||||
if (existingResult) {
|
||||
// This was a folder already present, remove it if this doesnt exist any more
|
||||
if (!host.directoryExists(fileOrDirectory)) {
|
||||
cachedReadDirectoryResult.delete(fileOrDirectoryPath);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// This was earlier a file (hence not in cached directory contents)
|
||||
// or we never cached the directory containing it
|
||||
const parentResult = getCachedFileSystemEntriesForBaseDir(fileOrDirectoryPath);
|
||||
if (parentResult) {
|
||||
const baseName = getBaseNameOfFileName(fileOrDirectory);
|
||||
if (parentResult) {
|
||||
updateFilesOfFileSystemEntry(parentResult, baseName, host.fileExists(fileOrDirectoryPath));
|
||||
updateFileSystemEntry(parentResult.directories, baseName, host.directoryExists(fileOrDirectoryPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addOrDeleteFile(fileName: string, filePath: Path, eventKind: FileWatcherEventKind) {
|
||||
if (eventKind === FileWatcherEventKind.Changed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const parentResult = getCachedFileSystemEntriesForBaseDir(filePath);
|
||||
if (parentResult) {
|
||||
updateFilesOfFileSystemEntry(parentResult, getBaseNameOfFileName(fileName), eventKind === FileWatcherEventKind.Created);
|
||||
}
|
||||
}
|
||||
|
||||
function updateFilesOfFileSystemEntry(parentResult: MutableFileSystemEntries, baseName: string, fileExists: boolean) {
|
||||
updateFileSystemEntry(parentResult.files, baseName, fileExists);
|
||||
}
|
||||
|
||||
function clearCache() {
|
||||
cachedReadDirectoryResult.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -907,6 +907,10 @@
|
||||
"category": "Error",
|
||||
"code": 1328
|
||||
},
|
||||
"'{0}' accepts too few arguments to be used as a decorator here. Did you mean to call it first and write '@{0}()'?": {
|
||||
"category": "Error",
|
||||
"code": 1329
|
||||
},
|
||||
|
||||
"Duplicate identifier '{0}'.": {
|
||||
"category": "Error",
|
||||
@@ -3090,10 +3094,6 @@
|
||||
"category": "Message",
|
||||
"code": 6128
|
||||
},
|
||||
"The config file '{0}' found doesn't contain any source files.": {
|
||||
"category": "Error",
|
||||
"code": 6129
|
||||
},
|
||||
"Resolving real path for '{0}', result '{1}'.": {
|
||||
"category": "Message",
|
||||
"code": 6130
|
||||
@@ -3314,6 +3314,10 @@
|
||||
"category": "Message",
|
||||
"code": 6185
|
||||
},
|
||||
"Enable strict checking of function types.": {
|
||||
"category": "Message",
|
||||
"code": 6186
|
||||
},
|
||||
"Variable '{0}' implicitly has an '{1}' type.": {
|
||||
"category": "Error",
|
||||
"code": 7005
|
||||
@@ -3507,6 +3511,22 @@
|
||||
"category": "Error",
|
||||
"code": 8020
|
||||
},
|
||||
"JSDoc '@typedef' tag should either have a type annotation or be followed by '@property' or '@member' tags.": {
|
||||
"category": "Error",
|
||||
"code": 8021
|
||||
},
|
||||
"JSDoc '@augments' is not attached to a class declaration.": {
|
||||
"category": "Error",
|
||||
"code": 8022
|
||||
},
|
||||
"JSDoc '@augments {0}' does not match the 'extends {1}' clause.": {
|
||||
"category": "Error",
|
||||
"code": 8023
|
||||
},
|
||||
"JSDoc '@param' tag has name '{0}', but there is no parameter with that name.": {
|
||||
"category": "Error",
|
||||
"code": 8024
|
||||
},
|
||||
"Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clause.": {
|
||||
"category": "Error",
|
||||
"code": 9002
|
||||
@@ -3685,6 +3705,14 @@
|
||||
"category": "Message",
|
||||
"code": 90026
|
||||
},
|
||||
"Declare static property '{0}'.": {
|
||||
"category": "Message",
|
||||
"code": 90027
|
||||
},
|
||||
"Call decorator expression.": {
|
||||
"category": "Message",
|
||||
"code": 90028
|
||||
},
|
||||
|
||||
"Convert function to an ES2015 class": {
|
||||
"category": "Message",
|
||||
@@ -3695,13 +3723,33 @@
|
||||
"code": 95002
|
||||
},
|
||||
|
||||
"Extract function": {
|
||||
"Extract symbol": {
|
||||
"category": "Message",
|
||||
"code": 95003
|
||||
},
|
||||
|
||||
"Extract to {0}": {
|
||||
"Extract to {0} in {1}": {
|
||||
"category": "Message",
|
||||
"code": 95004
|
||||
},
|
||||
|
||||
"Extract function": {
|
||||
"category": "Message",
|
||||
"code": 95005
|
||||
},
|
||||
|
||||
"Extract constant": {
|
||||
"category": "Message",
|
||||
"code": 95006
|
||||
},
|
||||
|
||||
"Extract to {0} in enclosing scope": {
|
||||
"category": "Message",
|
||||
"code": 95007
|
||||
},
|
||||
|
||||
"Extract to {0} in {1} scope": {
|
||||
"category": "Message",
|
||||
"code": 95008
|
||||
}
|
||||
}
|
||||
|
||||
Executable → Regular
+2
-2
@@ -2766,7 +2766,7 @@ namespace ts {
|
||||
return generateName(node);
|
||||
}
|
||||
else if (isIdentifier(node) && (nodeIsSynthesized(node) || !node.parent)) {
|
||||
return unescapeLeadingUnderscores(node.escapedText);
|
||||
return idText(node);
|
||||
}
|
||||
else if (node.kind === SyntaxKind.StringLiteral && (<StringLiteral>node).textSourceNode) {
|
||||
return getTextOfNode((<StringLiteral>node).textSourceNode, includeTrivia);
|
||||
@@ -2986,7 +2986,7 @@ namespace ts {
|
||||
case GeneratedIdentifierKind.Loop:
|
||||
return makeTempVariableName(TempFlags._i);
|
||||
case GeneratedIdentifierKind.Unique:
|
||||
return makeUniqueName(unescapeLeadingUnderscores(name.escapedText));
|
||||
return makeUniqueName(idText(name));
|
||||
}
|
||||
|
||||
Debug.fail("Unsupported GeneratedIdentifierKind.");
|
||||
|
||||
+44
-15
@@ -81,7 +81,7 @@ namespace ts {
|
||||
if (typeof value === "boolean") {
|
||||
return value ? createTrue() : createFalse();
|
||||
}
|
||||
if (typeof value === "string") {
|
||||
if (isString(value)) {
|
||||
return createStringLiteral(value);
|
||||
}
|
||||
return createLiteralFromNode(value);
|
||||
@@ -126,7 +126,7 @@ namespace ts {
|
||||
|
||||
export function updateIdentifier(node: Identifier, typeArguments: NodeArray<TypeNode> | undefined): Identifier {
|
||||
return node.typeArguments !== typeArguments
|
||||
? updateNode(createIdentifier(unescapeLeadingUnderscores(node.escapedText), typeArguments), node)
|
||||
? updateNode(createIdentifier(idText(node), typeArguments), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
@@ -1207,6 +1207,30 @@ namespace ts {
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createTemplateHead(text: string) {
|
||||
const node = <TemplateHead>createSynthesizedNode(SyntaxKind.TemplateHead);
|
||||
node.text = text;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createTemplateMiddle(text: string) {
|
||||
const node = <TemplateMiddle>createSynthesizedNode(SyntaxKind.TemplateMiddle);
|
||||
node.text = text;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createTemplateTail(text: string) {
|
||||
const node = <TemplateTail>createSynthesizedNode(SyntaxKind.TemplateTail);
|
||||
node.text = text;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createNoSubstitutionTemplateLiteral(text: string) {
|
||||
const node = <NoSubstitutionTemplateLiteral>createSynthesizedNode(SyntaxKind.NoSubstitutionTemplateLiteral);
|
||||
node.text = text;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createYield(expression?: Expression): YieldExpression;
|
||||
export function createYield(asteriskToken: AsteriskToken, expression: Expression): YieldExpression;
|
||||
export function createYield(asteriskTokenOrExpression?: AsteriskToken | Expression, expression?: Expression) {
|
||||
@@ -2180,7 +2204,7 @@ namespace ts {
|
||||
|
||||
export function createCatchClause(variableDeclaration: string | VariableDeclaration | undefined, block: Block) {
|
||||
const node = <CatchClause>createSynthesizedNode(SyntaxKind.CatchClause);
|
||||
node.variableDeclaration = typeof variableDeclaration === "string" ? createVariableDeclaration(variableDeclaration) : variableDeclaration;
|
||||
node.variableDeclaration = isString(variableDeclaration) ? createVariableDeclaration(variableDeclaration) : variableDeclaration;
|
||||
node.block = block;
|
||||
return node;
|
||||
}
|
||||
@@ -2506,11 +2530,11 @@ namespace ts {
|
||||
function asName(name: string | EntityName): EntityName;
|
||||
function asName(name: string | Identifier | ThisTypeNode): Identifier | ThisTypeNode;
|
||||
function asName(name: string | Identifier | BindingName | PropertyName | QualifiedName | ThisTypeNode) {
|
||||
return typeof name === "string" ? createIdentifier(name) : name;
|
||||
return isString(name) ? createIdentifier(name) : name;
|
||||
}
|
||||
|
||||
function asExpression(value: string | number | Expression) {
|
||||
return typeof value === "string" || typeof value === "number" ? createLiteral(value) : value;
|
||||
return isString(value) || typeof value === "number" ? createLiteral(value) : value;
|
||||
}
|
||||
|
||||
function asNodeArray<T extends Node>(array: ReadonlyArray<T> | undefined): NodeArray<T> | undefined {
|
||||
@@ -2927,12 +2951,12 @@ namespace ts {
|
||||
function createJsxFactoryExpressionFromEntityName(jsxFactory: EntityName, parent: JsxOpeningLikeElement): Expression {
|
||||
if (isQualifiedName(jsxFactory)) {
|
||||
const left = createJsxFactoryExpressionFromEntityName(jsxFactory.left, parent);
|
||||
const right = createIdentifier(unescapeLeadingUnderscores(jsxFactory.right.escapedText));
|
||||
const right = createIdentifier(idText(jsxFactory.right));
|
||||
right.escapedText = jsxFactory.right.escapedText;
|
||||
return createPropertyAccess(left, right);
|
||||
}
|
||||
else {
|
||||
return createReactNamespace(unescapeLeadingUnderscores(jsxFactory.escapedText), parent);
|
||||
return createReactNamespace(idText(jsxFactory), parent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3853,15 +3877,15 @@ namespace ts {
|
||||
* @param expression The Expression node.
|
||||
*/
|
||||
export function parenthesizeForNew(expression: Expression): LeftHandSideExpression {
|
||||
const emittedExpression = skipPartiallyEmittedExpressions(expression);
|
||||
switch (emittedExpression.kind) {
|
||||
const leftmostExpr = getLeftmostExpression(expression, /*stopAtCallExpressions*/ true);
|
||||
switch (leftmostExpr.kind) {
|
||||
case SyntaxKind.CallExpression:
|
||||
return createParen(expression);
|
||||
|
||||
case SyntaxKind.NewExpression:
|
||||
return (<NewExpression>emittedExpression).arguments
|
||||
? <LeftHandSideExpression>expression
|
||||
: createParen(expression);
|
||||
return !(leftmostExpr as NewExpression).arguments
|
||||
? createParen(expression)
|
||||
: <LeftHandSideExpression>expression;
|
||||
}
|
||||
|
||||
return parenthesizeForAccess(expression);
|
||||
@@ -3942,7 +3966,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
const leftmostExpressionKind = getLeftmostExpression(emittedExpression).kind;
|
||||
const leftmostExpressionKind = getLeftmostExpression(emittedExpression, /*stopAtCallExpressions*/ false).kind;
|
||||
if (leftmostExpressionKind === SyntaxKind.ObjectLiteralExpression || leftmostExpressionKind === SyntaxKind.FunctionExpression) {
|
||||
return setTextRange(createParen(expression), expression);
|
||||
}
|
||||
@@ -3988,7 +4012,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getLeftmostExpression(node: Expression): Expression {
|
||||
function getLeftmostExpression(node: Expression, stopAtCallExpressions: boolean) {
|
||||
while (true) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.PostfixUnaryExpression:
|
||||
@@ -4004,6 +4028,10 @@ namespace ts {
|
||||
continue;
|
||||
|
||||
case SyntaxKind.CallExpression:
|
||||
if (stopAtCallExpressions) {
|
||||
return node;
|
||||
}
|
||||
// falls through
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
node = (<CallExpression | PropertyAccessExpression | ElementAccessExpression>node).expression;
|
||||
@@ -4016,10 +4044,11 @@ namespace ts {
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function parenthesizeConciseBody(body: ConciseBody): ConciseBody {
|
||||
if (!isBlock(body) && getLeftmostExpression(body).kind === SyntaxKind.ObjectLiteralExpression) {
|
||||
if (!isBlock(body) && getLeftmostExpression(body, /*stopAtCallExpressions*/ false).kind === SyntaxKind.ObjectLiteralExpression) {
|
||||
return setTextRange(createParen(<Expression>body), body);
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
const fileName = jsonContent[fieldName];
|
||||
if (typeof fileName !== "string") {
|
||||
if (!isString(fileName)) {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_string_got_1, fieldName, typeof fileName);
|
||||
}
|
||||
@@ -663,8 +663,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (matchedPattern) {
|
||||
const matchedStar = typeof matchedPattern === "string" ? undefined : matchedText(matchedPattern, moduleName);
|
||||
const matchedPatternText = typeof matchedPattern === "string" ? matchedPattern : patternText(matchedPattern);
|
||||
const matchedStar = isString(matchedPattern) ? undefined : matchedText(matchedPattern, moduleName);
|
||||
const matchedPatternText = isString(matchedPattern) ? matchedPattern : patternText(matchedPattern);
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Module_name_0_matched_pattern_1, moduleName, matchedPatternText);
|
||||
}
|
||||
@@ -1153,21 +1153,4 @@ namespace ts {
|
||||
function toSearchResult<T>(value: T | undefined): SearchResult<T> {
|
||||
return value !== undefined ? { value } : undefined;
|
||||
}
|
||||
|
||||
/** Calls `callback` on `directory` and every ancestor directory it has, returning the first defined result. */
|
||||
function forEachAncestorDirectory<T>(directory: string, callback: (directory: string) => SearchResult<T>): SearchResult<T> {
|
||||
while (true) {
|
||||
const result = callback(directory);
|
||||
if (result !== undefined) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const parentPath = getDirectoryPath(directory);
|
||||
if (parentPath === directory) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
directory = parentPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+81
-54
@@ -423,9 +423,8 @@ namespace ts {
|
||||
return visitNode(cbNode, (<JSDocReturnTag>node).typeExpression);
|
||||
case SyntaxKind.JSDocTypeTag:
|
||||
return visitNode(cbNode, (<JSDocTypeTag>node).typeExpression);
|
||||
case SyntaxKind.JSDocAugmentsOrExtendsTag:
|
||||
case SyntaxKind.JSDocExtendsTag:
|
||||
return visitNode(cbNode, (<JSDocAugmentsOrExtendsTag>node).typeExpression);
|
||||
case SyntaxKind.JSDocAugmentsTag:
|
||||
return visitNode(cbNode, (<JSDocAugmentsTag>node).class);
|
||||
case SyntaxKind.JSDocTemplateTag:
|
||||
return visitNodes(cbNode, cbNodes, (<JSDocTemplateTag>node).typeParameters);
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
@@ -1218,8 +1217,8 @@ namespace ts {
|
||||
return createIdentifier(isIdentifier(), diagnosticMessage);
|
||||
}
|
||||
|
||||
function parseIdentifierName(): Identifier {
|
||||
return createIdentifier(tokenIsIdentifierOrKeyword(token()));
|
||||
function parseIdentifierName(diagnosticMessage?: DiagnosticMessage): Identifier {
|
||||
return createIdentifier(tokenIsIdentifierOrKeyword(token()), diagnosticMessage);
|
||||
}
|
||||
|
||||
function isLiteralPropertyName(): boolean {
|
||||
@@ -1957,7 +1956,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function parseEntityName(allowReservedWords: boolean, diagnosticMessage?: DiagnosticMessage): EntityName {
|
||||
let entity: EntityName = allowReservedWords ? parseIdentifierName() : parseIdentifier(diagnosticMessage);
|
||||
let entity: EntityName = allowReservedWords ? parseIdentifierName(diagnosticMessage) : parseIdentifier(diagnosticMessage);
|
||||
let dotPos = scanner.getStartPos();
|
||||
while (parseOptional(SyntaxKind.DotToken)) {
|
||||
if (token() === SyntaxKind.LessThanToken) {
|
||||
@@ -2097,7 +2096,7 @@ namespace ts {
|
||||
|
||||
function parseTypeReference(): TypeReferenceNode {
|
||||
const node = <TypeReferenceNode>createNode(SyntaxKind.TypeReference);
|
||||
node.typeName = parseEntityName(/*allowReservedWords*/ !!(contextFlags & NodeFlags.JSDoc), Diagnostics.Type_expected);
|
||||
node.typeName = parseEntityName(/*allowReservedWords*/ true, Diagnostics.Type_expected);
|
||||
if (!scanner.hasPrecedingLineBreak() && token() === SyntaxKind.LessThanToken) {
|
||||
node.typeArguments = parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken);
|
||||
}
|
||||
@@ -2181,7 +2180,7 @@ namespace ts {
|
||||
function parseJSDocNodeWithType(kind: SyntaxKind.JSDocVariadicType | SyntaxKind.JSDocNonNullableType): TypeNode {
|
||||
const result = createNode(kind) as JSDocVariadicType | JSDocNonNullableType;
|
||||
nextToken();
|
||||
result.type = parseType();
|
||||
result.type = parseNonArrayType();
|
||||
return finishNode(result);
|
||||
}
|
||||
|
||||
@@ -2734,49 +2733,53 @@ namespace ts {
|
||||
return token() === SyntaxKind.CloseParenToken || isStartOfParameter() || isStartOfType();
|
||||
}
|
||||
|
||||
function parseJSDocPostfixTypeOrHigher(): TypeNode {
|
||||
const type = parseNonArrayType();
|
||||
const kind = getKind(token());
|
||||
if (!kind) return type;
|
||||
nextToken();
|
||||
|
||||
const postfix = createNode(kind, type.pos) as JSDocOptionalType | JSDocNonNullableType | JSDocNullableType;
|
||||
postfix.type = type;
|
||||
return finishNode(postfix);
|
||||
|
||||
function getKind(tokenKind: SyntaxKind): SyntaxKind | undefined {
|
||||
switch (tokenKind) {
|
||||
function parsePostfixTypeOrHigher(): TypeNode {
|
||||
let type = parseNonArrayType();
|
||||
while (!scanner.hasPrecedingLineBreak()) {
|
||||
switch (token()) {
|
||||
case SyntaxKind.EqualsToken:
|
||||
// only parse postfix = inside jsdoc, because it's ambiguous elsewhere
|
||||
return contextFlags & NodeFlags.JSDoc ? SyntaxKind.JSDocOptionalType : undefined;
|
||||
if (!(contextFlags & NodeFlags.JSDoc)) {
|
||||
return type;
|
||||
}
|
||||
type = createJSDocPostfixType(SyntaxKind.JSDocOptionalType, type);
|
||||
break;
|
||||
case SyntaxKind.ExclamationToken:
|
||||
return SyntaxKind.JSDocNonNullableType;
|
||||
type = createJSDocPostfixType(SyntaxKind.JSDocNonNullableType, type);
|
||||
break;
|
||||
case SyntaxKind.QuestionToken:
|
||||
return SyntaxKind.JSDocNullableType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function parseArrayTypeOrHigher(): TypeNode {
|
||||
let type = parseJSDocPostfixTypeOrHigher();
|
||||
while (!scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.OpenBracketToken)) {
|
||||
if (isStartOfType()) {
|
||||
const node = <IndexedAccessTypeNode>createNode(SyntaxKind.IndexedAccessType, type.pos);
|
||||
node.objectType = type;
|
||||
node.indexType = parseType();
|
||||
parseExpected(SyntaxKind.CloseBracketToken);
|
||||
type = finishNode(node);
|
||||
}
|
||||
else {
|
||||
const node = <ArrayTypeNode>createNode(SyntaxKind.ArrayType, type.pos);
|
||||
node.elementType = type;
|
||||
parseExpected(SyntaxKind.CloseBracketToken);
|
||||
type = finishNode(node);
|
||||
type = createJSDocPostfixType(SyntaxKind.JSDocNullableType, type);
|
||||
break;
|
||||
case SyntaxKind.OpenBracketToken:
|
||||
parseExpected(SyntaxKind.OpenBracketToken);
|
||||
if (isStartOfType()) {
|
||||
const node = createNode(SyntaxKind.IndexedAccessType, type.pos) as IndexedAccessTypeNode;
|
||||
node.objectType = type;
|
||||
node.indexType = parseType();
|
||||
parseExpected(SyntaxKind.CloseBracketToken);
|
||||
type = finishNode(node);
|
||||
}
|
||||
else {
|
||||
const node = createNode(SyntaxKind.ArrayType, type.pos) as ArrayTypeNode;
|
||||
node.elementType = type;
|
||||
parseExpected(SyntaxKind.CloseBracketToken);
|
||||
type = finishNode(node);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
function createJSDocPostfixType(kind: SyntaxKind, type: TypeNode) {
|
||||
nextToken();
|
||||
const postfix = createNode(kind, type.pos) as JSDocOptionalType | JSDocNonNullableType | JSDocNullableType;
|
||||
postfix.type = type;
|
||||
return finishNode(postfix);
|
||||
}
|
||||
|
||||
function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword) {
|
||||
const node = <TypeOperatorNode>createNode(SyntaxKind.TypeOperator);
|
||||
parseExpected(operator);
|
||||
@@ -2790,7 +2793,7 @@ namespace ts {
|
||||
case SyntaxKind.KeyOfKeyword:
|
||||
return parseTypeOperator(SyntaxKind.KeyOfKeyword);
|
||||
}
|
||||
return parseArrayTypeOrHigher();
|
||||
return parsePostfixTypeOrHigher();
|
||||
}
|
||||
|
||||
function parseUnionOrIntersectionType(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, parseConstituentType: () => TypeNode, operator: SyntaxKind.BarToken | SyntaxKind.AmpersandToken): TypeNode {
|
||||
@@ -5625,13 +5628,16 @@ namespace ts {
|
||||
function parseExpressionWithTypeArguments(): ExpressionWithTypeArguments {
|
||||
const node = <ExpressionWithTypeArguments>createNode(SyntaxKind.ExpressionWithTypeArguments);
|
||||
node.expression = parseLeftHandSideExpressionOrHigher();
|
||||
if (token() === SyntaxKind.LessThanToken) {
|
||||
node.typeArguments = parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken);
|
||||
}
|
||||
|
||||
node.typeArguments = tryParseTypeArguments();
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function tryParseTypeArguments(): NodeArray<TypeNode> | undefined {
|
||||
return token() === SyntaxKind.LessThanToken
|
||||
? parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
function isHeritageClause(): boolean {
|
||||
return token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword;
|
||||
}
|
||||
@@ -6368,7 +6374,7 @@ namespace ts {
|
||||
switch (tagName.escapedText) {
|
||||
case "augments":
|
||||
case "extends":
|
||||
tag = parseAugmentsOrExtendsTag(atToken, tagName);
|
||||
tag = parseAugmentsTag(atToken, tagName);
|
||||
break;
|
||||
case "class":
|
||||
case "constructor":
|
||||
@@ -6601,20 +6607,41 @@ namespace ts {
|
||||
const result = <JSDocTypeTag>createNode(SyntaxKind.JSDocTypeTag, atToken.pos);
|
||||
result.atToken = atToken;
|
||||
result.tagName = tagName;
|
||||
result.typeExpression = parseJSDocTypeExpression(/*mayBail*/ true);
|
||||
result.typeExpression = parseJSDocTypeExpression(/*requireBraces*/ true);
|
||||
return finishNode(result);
|
||||
}
|
||||
|
||||
function parseAugmentsOrExtendsTag(atToken: AtToken, tagName: Identifier): JSDocAugmentsOrExtendsTag {
|
||||
const typeExpression = tryParseTypeExpression();
|
||||
|
||||
const result = <JSDocAugmentsOrExtendsTag>createNode(SyntaxKind.JSDocAugmentsOrExtendsTag, atToken.pos);
|
||||
function parseAugmentsTag(atToken: AtToken, tagName: Identifier): JSDocAugmentsTag {
|
||||
const result = <JSDocAugmentsTag>createNode(SyntaxKind.JSDocAugmentsTag, atToken.pos);
|
||||
result.atToken = atToken;
|
||||
result.tagName = tagName;
|
||||
result.typeExpression = typeExpression;
|
||||
result.class = parseExpressionWithTypeArgumentsForAugments();
|
||||
return finishNode(result);
|
||||
}
|
||||
|
||||
function parseExpressionWithTypeArgumentsForAugments(): ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression } {
|
||||
const usedBrace = parseOptional(SyntaxKind.OpenBraceToken);
|
||||
const node = createNode(SyntaxKind.ExpressionWithTypeArguments) as ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression };
|
||||
node.expression = parsePropertyAccessEntityNameExpression();
|
||||
node.typeArguments = tryParseTypeArguments();
|
||||
const res = finishNode(node);
|
||||
if (usedBrace) {
|
||||
parseExpected(SyntaxKind.CloseBraceToken);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function parsePropertyAccessEntityNameExpression() {
|
||||
let node: Identifier | PropertyAccessEntityNameExpression = parseJSDocIdentifierName(/*createIfMissing*/ true);
|
||||
while (parseOptional(SyntaxKind.DotToken)) {
|
||||
const prop: PropertyAccessEntityNameExpression = createNode(SyntaxKind.PropertyAccessExpression, node.pos) as PropertyAccessEntityNameExpression;
|
||||
prop.expression = node;
|
||||
prop.name = parseJSDocIdentifierName();
|
||||
node = finishNode(prop);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
function parseClassTag(atToken: AtToken, tagName: Identifier): JSDocClassTag {
|
||||
const tag = <JSDocClassTag>createNode(SyntaxKind.JSDocClassTag, atToken.pos);
|
||||
tag.atToken = atToken;
|
||||
|
||||
Regular → Executable
+154
-46
@@ -1,6 +1,7 @@
|
||||
/// <reference path="sys.ts" />
|
||||
/// <reference path="emitter.ts" />
|
||||
/// <reference path="core.ts" />
|
||||
/// <reference path="builder.ts" />
|
||||
|
||||
namespace ts {
|
||||
const ignoreDiagnosticCommentRegEx = /(^\s*$)|(^\s*\/\/\/?\s*(@ts-ignore)?)/;
|
||||
@@ -229,19 +230,25 @@ namespace ts {
|
||||
let output = "";
|
||||
|
||||
for (const diagnostic of diagnostics) {
|
||||
if (diagnostic.file) {
|
||||
const { line, character } = getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start);
|
||||
const fileName = diagnostic.file.fileName;
|
||||
const relativeFileName = convertToRelativePath(fileName, host.getCurrentDirectory(), fileName => host.getCanonicalFileName(fileName));
|
||||
output += `${relativeFileName}(${line + 1},${character + 1}): `;
|
||||
}
|
||||
|
||||
const category = DiagnosticCategory[diagnostic.category].toLowerCase();
|
||||
output += `${category} TS${diagnostic.code}: ${flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine())}${host.getNewLine()}`;
|
||||
output += formatDiagnostic(diagnostic, host);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
export function formatDiagnostic(diagnostic: Diagnostic, host: FormatDiagnosticsHost): string {
|
||||
const category = DiagnosticCategory[diagnostic.category].toLowerCase();
|
||||
const errorMessage = `${category} TS${diagnostic.code}: ${flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine())}${host.getNewLine()}`;
|
||||
|
||||
if (diagnostic.file) {
|
||||
const { line, character } = getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start);
|
||||
const fileName = diagnostic.file.fileName;
|
||||
const relativeFileName = convertToRelativePath(fileName, host.getCurrentDirectory(), fileName => host.getCanonicalFileName(fileName));
|
||||
return `${relativeFileName}(${line + 1},${character + 1}): ` + errorMessage;
|
||||
}
|
||||
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
const redForegroundEscapeSequence = "\u001b[91m";
|
||||
const yellowForegroundEscapeSequence = "\u001b[93m";
|
||||
const blueForegroundEscapeSequence = "\u001b[93m";
|
||||
@@ -271,6 +278,7 @@ namespace ts {
|
||||
export function formatDiagnosticsWithColorAndContext(diagnostics: ReadonlyArray<Diagnostic>, host: FormatDiagnosticsHost): string {
|
||||
let output = "";
|
||||
for (const diagnostic of diagnostics) {
|
||||
let context = "";
|
||||
if (diagnostic.file) {
|
||||
const { start, length, file } = diagnostic;
|
||||
const { line: firstLine, character: firstLineChar } = getLineAndCharacterOfPosition(file, start);
|
||||
@@ -284,12 +292,12 @@ namespace ts {
|
||||
gutterWidth = Math.max(ellipsis.length, gutterWidth);
|
||||
}
|
||||
|
||||
output += host.getNewLine();
|
||||
context += host.getNewLine();
|
||||
for (let i = firstLine; i <= lastLine; i++) {
|
||||
// If the error spans over 5 lines, we'll only show the first 2 and last 2 lines,
|
||||
// so we'll skip ahead to the second-to-last line.
|
||||
if (hasMoreThanFiveLines && firstLine + 1 < i && i < lastLine - 1) {
|
||||
output += formatAndReset(padLeft(ellipsis, gutterWidth), gutterStyleSequence) + gutterSeparator + host.getNewLine();
|
||||
context += formatAndReset(padLeft(ellipsis, gutterWidth), gutterStyleSequence) + gutterSeparator + host.getNewLine();
|
||||
i = lastLine - 1;
|
||||
}
|
||||
|
||||
@@ -300,30 +308,28 @@ namespace ts {
|
||||
lineContent = lineContent.replace("\t", " "); // convert tabs to single spaces
|
||||
|
||||
// Output the gutter and the actual contents of the line.
|
||||
output += formatAndReset(padLeft(i + 1 + "", gutterWidth), gutterStyleSequence) + gutterSeparator;
|
||||
output += lineContent + host.getNewLine();
|
||||
context += formatAndReset(padLeft(i + 1 + "", gutterWidth), gutterStyleSequence) + gutterSeparator;
|
||||
context += lineContent + host.getNewLine();
|
||||
|
||||
// Output the gutter and the error span for the line using tildes.
|
||||
output += formatAndReset(padLeft("", gutterWidth), gutterStyleSequence) + gutterSeparator;
|
||||
output += redForegroundEscapeSequence;
|
||||
context += formatAndReset(padLeft("", gutterWidth), gutterStyleSequence) + gutterSeparator;
|
||||
context += redForegroundEscapeSequence;
|
||||
if (i === firstLine) {
|
||||
// If we're on the last line, then limit it to the last character of the last line.
|
||||
// Otherwise, we'll just squiggle the rest of the line, giving 'slice' no end position.
|
||||
const lastCharForLine = i === lastLine ? lastLineChar : undefined;
|
||||
|
||||
output += lineContent.slice(0, firstLineChar).replace(/\S/g, " ");
|
||||
output += lineContent.slice(firstLineChar, lastCharForLine).replace(/./g, "~");
|
||||
context += lineContent.slice(0, firstLineChar).replace(/\S/g, " ");
|
||||
context += lineContent.slice(firstLineChar, lastCharForLine).replace(/./g, "~");
|
||||
}
|
||||
else if (i === lastLine) {
|
||||
output += lineContent.slice(0, lastLineChar).replace(/./g, "~");
|
||||
context += lineContent.slice(0, lastLineChar).replace(/./g, "~");
|
||||
}
|
||||
else {
|
||||
// Squiggle the entire line.
|
||||
output += lineContent.replace(/./g, "~");
|
||||
context += lineContent.replace(/./g, "~");
|
||||
}
|
||||
output += resetEscapeSequence;
|
||||
|
||||
output += host.getNewLine();
|
||||
context += resetEscapeSequence;
|
||||
}
|
||||
|
||||
output += host.getNewLine();
|
||||
@@ -333,13 +339,19 @@ namespace ts {
|
||||
const categoryColor = getCategoryFormat(diagnostic.category);
|
||||
const category = DiagnosticCategory[diagnostic.category].toLowerCase();
|
||||
output += `${ formatAndReset(category, categoryColor) } TS${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine()) }`;
|
||||
|
||||
if (diagnostic.file) {
|
||||
output += host.getNewLine();
|
||||
output += context;
|
||||
}
|
||||
|
||||
output += host.getNewLine();
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
export function flattenDiagnosticMessageText(messageText: string | DiagnosticMessageChain, newLine: string): string {
|
||||
if (typeof messageText === "string") {
|
||||
if (isString(messageText)) {
|
||||
return messageText;
|
||||
}
|
||||
else {
|
||||
@@ -388,6 +400,79 @@ namespace ts {
|
||||
allDiagnostics?: Diagnostic[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if program structure is upto date or needs to be recreated
|
||||
*/
|
||||
/* @internal */
|
||||
export function isProgramUptoDate(
|
||||
program: Program | undefined,
|
||||
rootFileNames: string[],
|
||||
newOptions: CompilerOptions,
|
||||
getSourceVersion: (path: Path) => string,
|
||||
fileExists: (fileName: string) => boolean,
|
||||
hasInvalidatedResolution: HasInvalidatedResolution,
|
||||
hasChangedAutomaticTypeDirectiveNames: boolean,
|
||||
): boolean {
|
||||
// If we haven't create a program yet or has changed automatic type directives, then it is not up-to-date
|
||||
if (!program || hasChangedAutomaticTypeDirectiveNames) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If number of files in the program do not match, it is not up-to-date
|
||||
if (program.getRootFileNames().length !== rootFileNames.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If any file is not up-to-date, then the whole program is not up-to-date
|
||||
if (program.getSourceFiles().some(sourceFileNotUptoDate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If any of the missing file paths are now created
|
||||
if (program.getMissingFilePaths().some(fileExists)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const currentOptions = program.getCompilerOptions();
|
||||
// If the compilation settings do no match, then the program is not up-to-date
|
||||
if (!compareDataObjects(currentOptions, newOptions)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If everything matches but the text of config file is changed,
|
||||
// error locations can change for program options, so update the program
|
||||
if (currentOptions.configFile && newOptions.configFile) {
|
||||
return currentOptions.configFile.text === newOptions.configFile.text;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
function sourceFileNotUptoDate(sourceFile: SourceFile): boolean {
|
||||
return sourceFile.version !== getSourceVersion(sourceFile.path) ||
|
||||
hasInvalidatedResolution(sourceFile.path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determined if source file needs to be re-created even if its text hasnt changed
|
||||
*/
|
||||
function shouldProgramCreateNewSourceFiles(program: Program, newOptions: CompilerOptions) {
|
||||
// If any of these options change, we cant reuse old source file even if version match
|
||||
// The change in options like these could result in change in syntax tree change
|
||||
const oldOptions = program && program.getCompilerOptions();
|
||||
return oldOptions && (
|
||||
oldOptions.target !== newOptions.target ||
|
||||
oldOptions.module !== newOptions.module ||
|
||||
oldOptions.moduleResolution !== newOptions.moduleResolution ||
|
||||
oldOptions.noResolve !== newOptions.noResolve ||
|
||||
oldOptions.jsx !== newOptions.jsx ||
|
||||
oldOptions.allowJs !== newOptions.allowJs ||
|
||||
oldOptions.disableSizeLimit !== newOptions.disableSizeLimit ||
|
||||
oldOptions.baseUrl !== newOptions.baseUrl ||
|
||||
!equalOwnProperties(oldOptions.paths, newOptions.paths)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new 'Program' instance. A Program is an immutable collection of 'SourceFile's and a 'CompilerOptions'
|
||||
* that represent a compilation unit.
|
||||
@@ -449,9 +534,10 @@ namespace ts {
|
||||
let _compilerOptionsObjectLiteralSyntax: ObjectLiteralExpression;
|
||||
|
||||
let moduleResolutionCache: ModuleResolutionCache;
|
||||
let resolveModuleNamesWorker: (moduleNames: string[], containingFile: string) => ResolvedModuleFull[];
|
||||
let resolveModuleNamesWorker: (moduleNames: string[], containingFile: string, reusedNames?: string[]) => ResolvedModuleFull[];
|
||||
const hasInvalidatedResolution = host.hasInvalidatedResolution || returnFalse;
|
||||
if (host.resolveModuleNames) {
|
||||
resolveModuleNamesWorker = (moduleNames, containingFile) => host.resolveModuleNames(checkAllDefined(moduleNames), containingFile).map(resolved => {
|
||||
resolveModuleNamesWorker = (moduleNames, containingFile, reusedNames) => host.resolveModuleNames(checkAllDefined(moduleNames), containingFile, reusedNames).map(resolved => {
|
||||
// An older host may have omitted extension, in which case we should infer it from the file extension of resolvedFileName.
|
||||
if (!resolved || (resolved as ResolvedModuleFull).extension !== undefined) {
|
||||
return resolved as ResolvedModuleFull;
|
||||
@@ -486,10 +572,12 @@ namespace ts {
|
||||
let redirectTargetsSet = createMap<true>();
|
||||
|
||||
const filesByName = createMap<SourceFile | undefined>();
|
||||
let missingFilePaths: ReadonlyArray<Path>;
|
||||
// stores 'filename -> file association' ignoring case
|
||||
// used to track cases when two file names differ only in casing
|
||||
const filesByNameIgnoreCase = host.useCaseSensitiveFileNames() ? createMap<SourceFile>() : undefined;
|
||||
|
||||
const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options);
|
||||
const structuralIsReused = tryReuseStructureFromOldProgram();
|
||||
if (structuralIsReused !== StructureIsReused.Completely) {
|
||||
forEach(rootNames, name => processRootFile(name, /*isDefaultLib*/ false));
|
||||
@@ -523,13 +611,26 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
missingFilePaths = arrayFrom(filesByName.keys(), p => <Path>p).filter(p => !filesByName.get(p));
|
||||
}
|
||||
|
||||
const missingFilePaths = arrayFrom(filesByName.keys(), p => <Path>p).filter(p => !filesByName.get(p));
|
||||
Debug.assert(!!missingFilePaths);
|
||||
|
||||
// unconditionally set moduleResolutionCache to undefined to avoid unnecessary leaks
|
||||
moduleResolutionCache = undefined;
|
||||
|
||||
// Release any files we have acquired in the old program but are
|
||||
// not part of the new program.
|
||||
if (oldProgram && host.onReleaseOldSourceFile) {
|
||||
const oldSourceFiles = oldProgram.getSourceFiles();
|
||||
for (const oldSourceFile of oldSourceFiles) {
|
||||
if (!getSourceFile(oldSourceFile.path) || shouldCreateNewSourceFile) {
|
||||
host.onReleaseOldSourceFile(oldSourceFile, oldProgram.getCompilerOptions());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unconditionally set oldProgram to undefined to prevent it from being captured in closure
|
||||
oldProgram = undefined;
|
||||
|
||||
@@ -563,6 +664,7 @@ namespace ts {
|
||||
getSourceFileFromReference,
|
||||
sourceFileToPackageName,
|
||||
redirectTargetsSet,
|
||||
hasInvalidatedResolution
|
||||
};
|
||||
|
||||
verifyCompilerOptions();
|
||||
@@ -657,21 +759,22 @@ namespace ts {
|
||||
* * ResolvedModuleFull instance: can be reused.
|
||||
*/
|
||||
let result: ResolvedModuleFull[];
|
||||
let reusedNames: string[];
|
||||
/** A transient placeholder used to mark predicted resolution in the result list. */
|
||||
const predictedToResolveToAmbientModuleMarker: ResolvedModuleFull = <any>{};
|
||||
|
||||
|
||||
for (let i = 0; i < moduleNames.length; i++) {
|
||||
const moduleName = moduleNames[i];
|
||||
// If we want to reuse resolutions more aggressively, we can refine this to check for whether the
|
||||
// text of the corresponding modulenames has changed.
|
||||
if (file === oldSourceFile) {
|
||||
// If the source file is unchanged and doesnt have invalidated resolution, reuse the module resolutions
|
||||
if (file === oldSourceFile && !hasInvalidatedResolution(oldSourceFile.path)) {
|
||||
const oldResolvedModule = oldSourceFile && oldSourceFile.resolvedModules.get(moduleName);
|
||||
if (oldResolvedModule) {
|
||||
if (isTraceEnabled(options, host)) {
|
||||
trace(host, Diagnostics.Reusing_resolution_of_module_0_to_file_1_from_old_program, moduleName, containingFile);
|
||||
}
|
||||
(result || (result = new Array(moduleNames.length)))[i] = oldResolvedModule;
|
||||
(reusedNames || (reusedNames = [])).push(moduleName);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -700,7 +803,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
const resolutions = unknownModuleNames && unknownModuleNames.length
|
||||
? resolveModuleNamesWorker(unknownModuleNames, containingFile)
|
||||
? resolveModuleNamesWorker(unknownModuleNames, containingFile, reusedNames)
|
||||
: emptyArray;
|
||||
|
||||
// Combine results of resolutions and predicted results
|
||||
@@ -788,14 +891,21 @@ namespace ts {
|
||||
const modifiedSourceFiles: { oldFile: SourceFile, newFile: SourceFile }[] = [];
|
||||
oldProgram.structureIsReused = StructureIsReused.Completely;
|
||||
|
||||
// If the missing file paths are now present, it can change the progam structure,
|
||||
// and hence cant reuse the structure.
|
||||
// This is same as how we dont reuse the structure if one of the file from old program is now missing
|
||||
if (oldProgram.getMissingFilePaths().some(missingFilePath => host.fileExists(missingFilePath))) {
|
||||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
}
|
||||
|
||||
const oldSourceFiles = oldProgram.getSourceFiles();
|
||||
const enum SeenPackageName { Exists, Modified }
|
||||
const seenPackageNames = createMap<SeenPackageName>();
|
||||
|
||||
for (const oldSourceFile of oldSourceFiles) {
|
||||
let newSourceFile = host.getSourceFileByPath
|
||||
? host.getSourceFileByPath(oldSourceFile.fileName, oldSourceFile.path, options.target)
|
||||
: host.getSourceFile(oldSourceFile.fileName, options.target);
|
||||
? host.getSourceFileByPath(oldSourceFile.fileName, oldSourceFile.path, options.target, /*onError*/ undefined, shouldCreateNewSourceFile)
|
||||
: host.getSourceFile(oldSourceFile.fileName, options.target, /*onError*/ undefined, shouldCreateNewSourceFile);
|
||||
|
||||
if (!newSourceFile) {
|
||||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
@@ -878,6 +988,13 @@ namespace ts {
|
||||
// tentatively approve the file
|
||||
modifiedSourceFiles.push({ oldFile: oldSourceFile, newFile: newSourceFile });
|
||||
}
|
||||
else if (hasInvalidatedResolution(oldSourceFile.path)) {
|
||||
// 'module/types' references could have changed
|
||||
oldProgram.structureIsReused = StructureIsReused.SafeModules;
|
||||
|
||||
// add file to the modified list so that we will resolve it later
|
||||
modifiedSourceFiles.push({ oldFile: oldSourceFile, newFile: newSourceFile });
|
||||
}
|
||||
|
||||
// if file has passed all checks it should be safe to reuse it
|
||||
newSourceFiles.push(newSourceFile);
|
||||
@@ -924,20 +1041,11 @@ namespace ts {
|
||||
return oldProgram.structureIsReused;
|
||||
}
|
||||
|
||||
// If a file has ceased to be missing, then we need to discard some of the old
|
||||
// structure in order to pick it up.
|
||||
// Caution: if the file has created and then deleted between since it was discovered to
|
||||
// be missing, then the corresponding file watcher will have been closed and no new one
|
||||
// will be created until we encounter a change that prevents complete structure reuse.
|
||||
// During this interval, creation of the file will go unnoticed. We expect this to be
|
||||
// both rare and low-impact.
|
||||
if (oldProgram.getMissingFilePaths().some(missingFilePath => host.fileExists(missingFilePath))) {
|
||||
if (host.hasChangedAutomaticTypeDirectiveNames) {
|
||||
return oldProgram.structureIsReused = StructureIsReused.SafeModules;
|
||||
}
|
||||
|
||||
for (const p of oldProgram.getMissingFilePaths()) {
|
||||
filesByName.set(p, undefined);
|
||||
}
|
||||
missingFilePaths = oldProgram.getMissingFilePaths();
|
||||
|
||||
// update fileName -> file mapping
|
||||
for (let i = 0; i < newSourceFiles.length; i++) {
|
||||
@@ -1462,7 +1570,7 @@ namespace ts {
|
||||
|
||||
// file.imports may not be undefined if there exists dynamic import
|
||||
let imports: StringLiteral[];
|
||||
let moduleAugmentations: Array<StringLiteral | Identifier>;
|
||||
let moduleAugmentations: (StringLiteral | Identifier)[];
|
||||
let ambientModules: string[];
|
||||
|
||||
// If we are importing helpers, we need to add a synthetic reference to resolve the
|
||||
@@ -1582,7 +1690,7 @@ namespace ts {
|
||||
fail(Diagnostics.File_0_not_found, fileName);
|
||||
}
|
||||
else if (refFile && host.getCanonicalFileName(fileName) === host.getCanonicalFileName(refFile.fileName)) {
|
||||
fail(Diagnostics.A_file_cannot_have_a_reference_to_itself, fileName);
|
||||
fail(Diagnostics.A_file_cannot_have_a_reference_to_itself);
|
||||
}
|
||||
}
|
||||
return sourceFile;
|
||||
@@ -1684,7 +1792,7 @@ namespace ts {
|
||||
else {
|
||||
fileProcessingDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage));
|
||||
}
|
||||
});
|
||||
}, shouldCreateNewSourceFile);
|
||||
|
||||
if (packageId) {
|
||||
const packageIdKey = `${packageId.name}/${packageId.subModuleName}@${packageId.version}`;
|
||||
|
||||
@@ -0,0 +1,595 @@
|
||||
/// <reference path="types.ts"/>
|
||||
/// <reference path="core.ts"/>
|
||||
/// <reference path="watchUtilities.ts"/>
|
||||
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
/** This is the cache of module/typedirectives resolution that can be retained across program */
|
||||
export interface ResolutionCache {
|
||||
startRecordingFilesWithChangedResolutions(): void;
|
||||
finishRecordingFilesWithChangedResolutions(): Path[];
|
||||
|
||||
resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, logChanges: boolean): ResolvedModuleFull[];
|
||||
resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
|
||||
invalidateResolutionOfFile(filePath: Path): void;
|
||||
removeResolutionsOfFile(filePath: Path): void;
|
||||
createHasInvalidatedResolution(): HasInvalidatedResolution;
|
||||
|
||||
startCachingPerDirectoryResolution(): void;
|
||||
finishCachingPerDirectoryResolution(): void;
|
||||
|
||||
updateTypeRootsWatch(): void;
|
||||
closeTypeRootsWatch(): void;
|
||||
|
||||
clear(): void;
|
||||
}
|
||||
|
||||
interface ResolutionWithFailedLookupLocations {
|
||||
readonly failedLookupLocations: ReadonlyArray<string>;
|
||||
isInvalidated?: boolean;
|
||||
}
|
||||
|
||||
interface ResolutionWithResolvedFileName {
|
||||
resolvedFileName: string | undefined;
|
||||
}
|
||||
|
||||
interface ResolvedModuleWithFailedLookupLocations extends ts.ResolvedModuleWithFailedLookupLocations, ResolutionWithFailedLookupLocations {
|
||||
}
|
||||
|
||||
interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations extends ts.ResolvedTypeReferenceDirectiveWithFailedLookupLocations, ResolutionWithFailedLookupLocations {
|
||||
}
|
||||
|
||||
export interface ResolutionCacheHost extends ModuleResolutionHost {
|
||||
toPath(fileName: string): Path;
|
||||
getCompilationSettings(): CompilerOptions;
|
||||
watchDirectoryOfFailedLookupLocation(directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags): FileWatcher;
|
||||
onInvalidatedResolution(): void;
|
||||
watchTypeRootsDirectory(directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags): FileWatcher;
|
||||
onChangedAutomaticTypeDirectiveNames(): void;
|
||||
getCachedDirectoryStructureHost?(): CachedDirectoryStructureHost;
|
||||
projectName?: string;
|
||||
getGlobalCache?(): string | undefined;
|
||||
writeLog(s: string): void;
|
||||
maxNumberOfFilesToIterateForInvalidation?: number;
|
||||
}
|
||||
|
||||
interface DirectoryWatchesOfFailedLookup {
|
||||
/** watcher for the directory of failed lookup */
|
||||
watcher: FileWatcher;
|
||||
/** ref count keeping this directory watch alive */
|
||||
refCount: number;
|
||||
}
|
||||
|
||||
interface DirectoryOfFailedLookupWatch {
|
||||
dir: string;
|
||||
dirPath: Path;
|
||||
}
|
||||
|
||||
export const maxNumberOfFilesToIterateForInvalidation = 256;
|
||||
|
||||
interface GetResolutionWithResolvedFileName<T extends ResolutionWithFailedLookupLocations = ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName = ResolutionWithResolvedFileName> {
|
||||
(resolution: T): R;
|
||||
}
|
||||
|
||||
export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootDirForResolution: string): ResolutionCache {
|
||||
let filesWithChangedSetOfUnresolvedImports: Path[] | undefined;
|
||||
let filesWithInvalidatedResolutions: Map<true> | undefined;
|
||||
let allFilesHaveInvalidatedResolution = false;
|
||||
|
||||
// The resolvedModuleNames and resolvedTypeReferenceDirectives are the cache of resolutions per file.
|
||||
// The key in the map is source file's path.
|
||||
// The values are Map of resolutions with key being name lookedup.
|
||||
const resolvedModuleNames = createMap<Map<ResolvedModuleWithFailedLookupLocations>>();
|
||||
const perDirectoryResolvedModuleNames = createMap<Map<ResolvedModuleWithFailedLookupLocations>>();
|
||||
|
||||
const resolvedTypeReferenceDirectives = createMap<Map<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>();
|
||||
const perDirectoryResolvedTypeReferenceDirectives = createMap<Map<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>();
|
||||
|
||||
const getCurrentDirectory = memoize(() => resolutionHost.getCurrentDirectory());
|
||||
|
||||
/**
|
||||
* These are the extensions that failed lookup files will have by default,
|
||||
* any other extension of failed lookup will be store that path in custom failed lookup path
|
||||
* This helps in not having to comb through all resolutions when files are added/removed
|
||||
* Note that .d.ts file also has .d.ts extension hence will be part of default extensions
|
||||
*/
|
||||
const failedLookupDefaultExtensions = [Extension.Ts, Extension.Tsx, Extension.Js, Extension.Jsx, Extension.Json];
|
||||
const customFailedLookupPaths = createMap<number>();
|
||||
|
||||
const directoryWatchesOfFailedLookups = createMap<DirectoryWatchesOfFailedLookup>();
|
||||
const rootDir = rootDirForResolution && removeTrailingDirectorySeparator(getNormalizedAbsolutePath(rootDirForResolution, getCurrentDirectory()));
|
||||
const rootPath = rootDir && resolutionHost.toPath(rootDir);
|
||||
|
||||
// TypeRoot watches for the types that get added as part of getAutomaticTypeDirectiveNames
|
||||
const typeRootsWatches = createMap<FileWatcher>();
|
||||
|
||||
return {
|
||||
startRecordingFilesWithChangedResolutions,
|
||||
finishRecordingFilesWithChangedResolutions,
|
||||
startCachingPerDirectoryResolution,
|
||||
finishCachingPerDirectoryResolution,
|
||||
resolveModuleNames,
|
||||
resolveTypeReferenceDirectives,
|
||||
removeResolutionsOfFile,
|
||||
invalidateResolutionOfFile,
|
||||
createHasInvalidatedResolution,
|
||||
updateTypeRootsWatch,
|
||||
closeTypeRootsWatch,
|
||||
clear
|
||||
};
|
||||
|
||||
function getResolvedModule(resolution: ResolvedModuleWithFailedLookupLocations) {
|
||||
return resolution.resolvedModule;
|
||||
}
|
||||
|
||||
function getResolvedTypeReferenceDirective(resolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations) {
|
||||
return resolution.resolvedTypeReferenceDirective;
|
||||
}
|
||||
|
||||
function isInDirectoryPath(dir: Path, file: Path) {
|
||||
if (dir === undefined || file.length <= dir.length) {
|
||||
return false;
|
||||
}
|
||||
return startsWith(file, dir) && file[dir.length] === directorySeparator;
|
||||
}
|
||||
|
||||
function clear() {
|
||||
clearMap(directoryWatchesOfFailedLookups, closeFileWatcherOf);
|
||||
customFailedLookupPaths.clear();
|
||||
closeTypeRootsWatch();
|
||||
resolvedModuleNames.clear();
|
||||
resolvedTypeReferenceDirectives.clear();
|
||||
allFilesHaveInvalidatedResolution = false;
|
||||
Debug.assert(perDirectoryResolvedModuleNames.size === 0 && perDirectoryResolvedTypeReferenceDirectives.size === 0);
|
||||
}
|
||||
|
||||
function startRecordingFilesWithChangedResolutions() {
|
||||
filesWithChangedSetOfUnresolvedImports = [];
|
||||
}
|
||||
|
||||
function finishRecordingFilesWithChangedResolutions() {
|
||||
const collected = filesWithChangedSetOfUnresolvedImports;
|
||||
filesWithChangedSetOfUnresolvedImports = undefined;
|
||||
return collected;
|
||||
}
|
||||
|
||||
function createHasInvalidatedResolution(): HasInvalidatedResolution {
|
||||
if (allFilesHaveInvalidatedResolution) {
|
||||
// Any file asked would have invalidated resolution
|
||||
filesWithInvalidatedResolutions = undefined;
|
||||
return returnTrue;
|
||||
}
|
||||
const collected = filesWithInvalidatedResolutions;
|
||||
filesWithInvalidatedResolutions = undefined;
|
||||
return path => collected && collected.has(path);
|
||||
}
|
||||
|
||||
function startCachingPerDirectoryResolution() {
|
||||
Debug.assert(perDirectoryResolvedModuleNames.size === 0 && perDirectoryResolvedTypeReferenceDirectives.size === 0);
|
||||
}
|
||||
|
||||
function finishCachingPerDirectoryResolution() {
|
||||
allFilesHaveInvalidatedResolution = false;
|
||||
directoryWatchesOfFailedLookups.forEach((watcher, path) => {
|
||||
if (watcher.refCount === 0) {
|
||||
directoryWatchesOfFailedLookups.delete(path);
|
||||
watcher.watcher.close();
|
||||
}
|
||||
});
|
||||
|
||||
perDirectoryResolvedModuleNames.clear();
|
||||
perDirectoryResolvedTypeReferenceDirectives.clear();
|
||||
}
|
||||
|
||||
function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
|
||||
const primaryResult = ts.resolveModuleName(moduleName, containingFile, compilerOptions, host);
|
||||
// return result immediately only if global cache support is not enabled or if it is .ts, .tsx or .d.ts
|
||||
if (!resolutionHost.getGlobalCache) {
|
||||
return primaryResult;
|
||||
}
|
||||
|
||||
// otherwise try to load typings from @types
|
||||
const globalCache = resolutionHost.getGlobalCache();
|
||||
if (globalCache !== undefined && !isExternalModuleNameRelative(moduleName) && !(primaryResult.resolvedModule && extensionIsTypeScript(primaryResult.resolvedModule.extension))) {
|
||||
// create different collection of failed lookup locations for second pass
|
||||
// if it will fail and we've already found something during the first pass - we don't want to pollute its results
|
||||
const { resolvedModule, failedLookupLocations } = loadModuleFromGlobalCache(moduleName, resolutionHost.projectName, compilerOptions, host, globalCache);
|
||||
if (resolvedModule) {
|
||||
return { resolvedModule, failedLookupLocations: addRange(primaryResult.failedLookupLocations as string[], failedLookupLocations) };
|
||||
}
|
||||
}
|
||||
|
||||
// Default return the result from the first pass
|
||||
return primaryResult;
|
||||
}
|
||||
|
||||
function resolveNamesWithLocalCache<T extends ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName>(
|
||||
names: string[],
|
||||
containingFile: string,
|
||||
cache: Map<Map<T>>,
|
||||
perDirectoryCache: Map<Map<T>>,
|
||||
loader: (name: string, containingFile: string, options: CompilerOptions, host: ModuleResolutionHost) => T,
|
||||
getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>,
|
||||
reusedNames: string[] | undefined,
|
||||
logChanges: boolean): R[] {
|
||||
|
||||
const path = resolutionHost.toPath(containingFile);
|
||||
const resolutionsInFile = cache.get(path) || cache.set(path, createMap()).get(path);
|
||||
const dirPath = getDirectoryPath(path);
|
||||
let perDirectoryResolution = perDirectoryCache.get(dirPath);
|
||||
if (!perDirectoryResolution) {
|
||||
perDirectoryResolution = createMap();
|
||||
perDirectoryCache.set(dirPath, perDirectoryResolution);
|
||||
}
|
||||
|
||||
const resolvedModules: R[] = [];
|
||||
const compilerOptions = resolutionHost.getCompilationSettings();
|
||||
|
||||
const seenNamesInFile = createMap<true>();
|
||||
for (const name of names) {
|
||||
let resolution = resolutionsInFile.get(name);
|
||||
// Resolution is valid if it is present and not invalidated
|
||||
if (!seenNamesInFile.has(name) &&
|
||||
allFilesHaveInvalidatedResolution || !resolution || resolution.isInvalidated) {
|
||||
const existingResolution = resolution;
|
||||
const resolutionInDirectory = perDirectoryResolution.get(name);
|
||||
if (resolutionInDirectory) {
|
||||
resolution = resolutionInDirectory;
|
||||
}
|
||||
else {
|
||||
resolution = loader(name, containingFile, compilerOptions, resolutionHost);
|
||||
perDirectoryResolution.set(name, resolution);
|
||||
}
|
||||
resolutionsInFile.set(name, resolution);
|
||||
if (resolution.failedLookupLocations) {
|
||||
if (existingResolution && existingResolution.failedLookupLocations) {
|
||||
watchAndStopWatchDiffFailedLookupLocations(resolution, existingResolution);
|
||||
}
|
||||
else {
|
||||
watchFailedLookupLocationOfResolution(resolution, 0);
|
||||
}
|
||||
}
|
||||
else if (existingResolution) {
|
||||
stopWatchFailedLookupLocationOfResolution(existingResolution);
|
||||
}
|
||||
if (logChanges && filesWithChangedSetOfUnresolvedImports && !resolutionIsEqualTo(existingResolution, resolution)) {
|
||||
filesWithChangedSetOfUnresolvedImports.push(path);
|
||||
// reset log changes to avoid recording the same file multiple times
|
||||
logChanges = false;
|
||||
}
|
||||
}
|
||||
Debug.assert(resolution !== undefined && !resolution.isInvalidated);
|
||||
seenNamesInFile.set(name, true);
|
||||
resolvedModules.push(getResolutionWithResolvedFileName(resolution));
|
||||
}
|
||||
|
||||
// Stop watching and remove the unused name
|
||||
resolutionsInFile.forEach((resolution, name) => {
|
||||
if (!seenNamesInFile.has(name) && !contains(reusedNames, name)) {
|
||||
stopWatchFailedLookupLocationOfResolution(resolution);
|
||||
resolutionsInFile.delete(name);
|
||||
}
|
||||
});
|
||||
|
||||
return resolvedModules;
|
||||
|
||||
function resolutionIsEqualTo(oldResolution: T, newResolution: T): boolean {
|
||||
if (oldResolution === newResolution) {
|
||||
return true;
|
||||
}
|
||||
if (!oldResolution || !newResolution || oldResolution.isInvalidated) {
|
||||
return false;
|
||||
}
|
||||
const oldResult = getResolutionWithResolvedFileName(oldResolution);
|
||||
const newResult = getResolutionWithResolvedFileName(newResolution);
|
||||
if (oldResult === newResult) {
|
||||
return true;
|
||||
}
|
||||
if (!oldResult || !newResult) {
|
||||
return false;
|
||||
}
|
||||
return oldResult.resolvedFileName === newResult.resolvedFileName;
|
||||
}
|
||||
}
|
||||
|
||||
function resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[] {
|
||||
return resolveNamesWithLocalCache(
|
||||
typeDirectiveNames, containingFile,
|
||||
resolvedTypeReferenceDirectives, perDirectoryResolvedTypeReferenceDirectives,
|
||||
resolveTypeReferenceDirective, getResolvedTypeReferenceDirective,
|
||||
/*reusedNames*/ undefined, /*logChanges*/ false
|
||||
);
|
||||
}
|
||||
|
||||
function resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, logChanges: boolean): ResolvedModuleFull[] {
|
||||
return resolveNamesWithLocalCache(
|
||||
moduleNames, containingFile,
|
||||
resolvedModuleNames, perDirectoryResolvedModuleNames,
|
||||
resolveModuleName, getResolvedModule,
|
||||
reusedNames, logChanges
|
||||
);
|
||||
}
|
||||
|
||||
function isNodeModulesDirectory(dirPath: Path) {
|
||||
return endsWith(dirPath, "/node_modules");
|
||||
}
|
||||
|
||||
function getDirectoryToWatchFailedLookupLocation(failedLookupLocation: string, failedLookupLocationPath: Path): DirectoryOfFailedLookupWatch {
|
||||
if (isInDirectoryPath(rootPath, failedLookupLocationPath)) {
|
||||
return { dir: rootDir, dirPath: rootPath };
|
||||
}
|
||||
|
||||
let dir = getDirectoryPath(getNormalizedAbsolutePath(failedLookupLocation, getCurrentDirectory()));
|
||||
let dirPath = getDirectoryPath(failedLookupLocationPath);
|
||||
|
||||
// If the directory is node_modules use it to watch
|
||||
if (isNodeModulesDirectory(dirPath)) {
|
||||
return { dir, dirPath };
|
||||
}
|
||||
|
||||
// If directory path contains node module, get the node_modules directory for watching
|
||||
if (dirPath.indexOf("/node_modules/") !== -1) {
|
||||
while (!isNodeModulesDirectory(dirPath)) {
|
||||
dir = getDirectoryPath(dir);
|
||||
dirPath = getDirectoryPath(dirPath);
|
||||
}
|
||||
return { dir, dirPath };
|
||||
}
|
||||
|
||||
// Use some ancestor of the root directory
|
||||
if (rootPath !== undefined) {
|
||||
while (!isInDirectoryPath(dirPath, rootPath)) {
|
||||
const parentPath = getDirectoryPath(dirPath);
|
||||
if (parentPath === dirPath) {
|
||||
break;
|
||||
}
|
||||
dirPath = parentPath;
|
||||
dir = getDirectoryPath(dir);
|
||||
}
|
||||
}
|
||||
|
||||
return { dir, dirPath };
|
||||
}
|
||||
|
||||
function isPathWithDefaultFailedLookupExtension(path: Path) {
|
||||
return fileExtensionIsOneOf(path, failedLookupDefaultExtensions);
|
||||
}
|
||||
|
||||
function watchAndStopWatchDiffFailedLookupLocations(resolution: ResolutionWithFailedLookupLocations, existingResolution: ResolutionWithFailedLookupLocations) {
|
||||
const failedLookupLocations = resolution.failedLookupLocations;
|
||||
const existingFailedLookupLocations = existingResolution.failedLookupLocations;
|
||||
for (let index = 0; index < failedLookupLocations.length; index++) {
|
||||
if (index === existingFailedLookupLocations.length) {
|
||||
// Additional failed lookup locations, watch from this index
|
||||
watchFailedLookupLocationOfResolution(resolution, index);
|
||||
return;
|
||||
}
|
||||
else if (failedLookupLocations[index] !== existingFailedLookupLocations[index]) {
|
||||
// Different failed lookup locations,
|
||||
// Watch new resolution failed lookup locations from this index and
|
||||
// stop watching existing resolutions from this index
|
||||
watchFailedLookupLocationOfResolution(resolution, index);
|
||||
stopWatchFailedLookupLocationOfResolutionFrom(existingResolution, index);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// All new failed lookup locations are already watched (and are same),
|
||||
// Stop watching failed lookup locations of existing resolution after failed lookup locations length
|
||||
stopWatchFailedLookupLocationOfResolutionFrom(existingResolution, failedLookupLocations.length);
|
||||
}
|
||||
|
||||
function watchFailedLookupLocationOfResolution({ failedLookupLocations }: ResolutionWithFailedLookupLocations, startIndex: number) {
|
||||
for (let i = startIndex; i < failedLookupLocations.length; i++) {
|
||||
const failedLookupLocation = failedLookupLocations[i];
|
||||
const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation);
|
||||
// If the failed lookup location path is not one of the supported extensions,
|
||||
// store it in the custom path
|
||||
if (!isPathWithDefaultFailedLookupExtension(failedLookupLocationPath)) {
|
||||
const refCount = customFailedLookupPaths.get(failedLookupLocationPath) || 0;
|
||||
customFailedLookupPaths.set(failedLookupLocationPath, refCount + 1);
|
||||
}
|
||||
const { dir, dirPath } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath);
|
||||
const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath);
|
||||
if (dirWatcher) {
|
||||
dirWatcher.refCount++;
|
||||
}
|
||||
else {
|
||||
directoryWatchesOfFailedLookups.set(dirPath, { watcher: createDirectoryWatcher(dir, dirPath), refCount: 1 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function stopWatchFailedLookupLocationOfResolution(resolution: ResolutionWithFailedLookupLocations) {
|
||||
if (resolution.failedLookupLocations) {
|
||||
stopWatchFailedLookupLocationOfResolutionFrom(resolution, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function stopWatchFailedLookupLocationOfResolutionFrom({ failedLookupLocations }: ResolutionWithFailedLookupLocations, startIndex: number) {
|
||||
for (let i = startIndex; i < failedLookupLocations.length; i++) {
|
||||
const failedLookupLocation = failedLookupLocations[i];
|
||||
const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation);
|
||||
const refCount = customFailedLookupPaths.get(failedLookupLocationPath);
|
||||
if (refCount) {
|
||||
if (refCount === 1) {
|
||||
customFailedLookupPaths.delete(failedLookupLocationPath);
|
||||
}
|
||||
else {
|
||||
Debug.assert(refCount > 1);
|
||||
customFailedLookupPaths.set(failedLookupLocationPath, refCount - 1);
|
||||
}
|
||||
}
|
||||
const { dirPath } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath);
|
||||
const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath);
|
||||
// Do not close the watcher yet since it might be needed by other failed lookup locations.
|
||||
dirWatcher.refCount--;
|
||||
}
|
||||
}
|
||||
|
||||
function createDirectoryWatcher(directory: string, dirPath: Path) {
|
||||
return resolutionHost.watchDirectoryOfFailedLookupLocation(directory, fileOrDirectory => {
|
||||
const fileOrDirectoryPath = resolutionHost.toPath(fileOrDirectory);
|
||||
if (resolutionHost.getCachedDirectoryStructureHost) {
|
||||
// Since the file existance changed, update the sourceFiles cache
|
||||
resolutionHost.getCachedDirectoryStructureHost().addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath);
|
||||
}
|
||||
|
||||
// If the files are added to project root or node_modules directory, always run through the invalidation process
|
||||
// Otherwise run through invalidation only if adding to the immediate directory
|
||||
if (!allFilesHaveInvalidatedResolution &&
|
||||
dirPath === rootPath || isNodeModulesDirectory(dirPath) || getDirectoryPath(fileOrDirectoryPath) === dirPath) {
|
||||
if (invalidateResolutionOfFailedLookupLocation(fileOrDirectoryPath, dirPath === fileOrDirectoryPath)) {
|
||||
resolutionHost.onInvalidatedResolution();
|
||||
}
|
||||
}
|
||||
}, WatchDirectoryFlags.Recursive);
|
||||
}
|
||||
|
||||
function removeResolutionsOfFileFromCache(cache: Map<Map<ResolutionWithFailedLookupLocations>>, filePath: Path) {
|
||||
// Deleted file, stop watching failed lookups for all the resolutions in the file
|
||||
const resolutions = cache.get(filePath);
|
||||
if (resolutions) {
|
||||
resolutions.forEach(stopWatchFailedLookupLocationOfResolution);
|
||||
cache.delete(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
function removeResolutionsOfFile(filePath: Path) {
|
||||
removeResolutionsOfFileFromCache(resolvedModuleNames, filePath);
|
||||
removeResolutionsOfFileFromCache(resolvedTypeReferenceDirectives, filePath);
|
||||
}
|
||||
|
||||
function invalidateResolutionCache<T extends ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName>(
|
||||
cache: Map<Map<T>>,
|
||||
isInvalidatedResolution: (resolution: T, getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>) => boolean,
|
||||
getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>
|
||||
) {
|
||||
const seen = createMap<Map<true>>();
|
||||
cache.forEach((resolutions, containingFilePath) => {
|
||||
const dirPath = getDirectoryPath(containingFilePath);
|
||||
let seenInDir = seen.get(dirPath);
|
||||
if (!seenInDir) {
|
||||
seenInDir = createMap<true>();
|
||||
seen.set(dirPath, seenInDir);
|
||||
}
|
||||
resolutions.forEach((resolution, name) => {
|
||||
if (seenInDir.has(name)) {
|
||||
return;
|
||||
}
|
||||
seenInDir.set(name, true);
|
||||
if (!resolution.isInvalidated && isInvalidatedResolution(resolution, getResolutionWithResolvedFileName)) {
|
||||
// Mark the file as needing re-evaluation of module resolution instead of using it blindly.
|
||||
resolution.isInvalidated = true;
|
||||
(filesWithInvalidatedResolutions || (filesWithInvalidatedResolutions = createMap<true>())).set(containingFilePath, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function hasReachedResolutionIterationLimit() {
|
||||
const maxSize = resolutionHost.maxNumberOfFilesToIterateForInvalidation || maxNumberOfFilesToIterateForInvalidation;
|
||||
return resolvedModuleNames.size > maxSize || resolvedTypeReferenceDirectives.size > maxSize;
|
||||
}
|
||||
|
||||
function invalidateResolutions(
|
||||
isInvalidatedResolution: (resolution: ResolutionWithFailedLookupLocations, getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName) => boolean,
|
||||
) {
|
||||
// If more than maxNumberOfFilesToIterateForInvalidation present,
|
||||
// just invalidated all files and recalculate the resolutions for files instead
|
||||
if (hasReachedResolutionIterationLimit()) {
|
||||
allFilesHaveInvalidatedResolution = true;
|
||||
return;
|
||||
}
|
||||
invalidateResolutionCache(resolvedModuleNames, isInvalidatedResolution, getResolvedModule);
|
||||
invalidateResolutionCache(resolvedTypeReferenceDirectives, isInvalidatedResolution, getResolvedTypeReferenceDirective);
|
||||
}
|
||||
|
||||
function invalidateResolutionOfFile(filePath: Path) {
|
||||
removeResolutionsOfFile(filePath);
|
||||
invalidateResolutions(
|
||||
// Resolution is invalidated if the resulting file name is same as the deleted file path
|
||||
(resolution, getResolutionWithResolvedFileName) => {
|
||||
const result = getResolutionWithResolvedFileName(resolution);
|
||||
return result && resolutionHost.toPath(result.resolvedFileName) === filePath;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function invalidateResolutionOfFailedLookupLocation(fileOrDirectoryPath: Path, isCreatingWatchedDirectory: boolean) {
|
||||
let isChangedFailedLookupLocation: (location: string) => boolean;
|
||||
if (isCreatingWatchedDirectory) {
|
||||
// Watching directory is created
|
||||
// Invalidate any resolution has failed lookup in this directory
|
||||
isChangedFailedLookupLocation = location => isInDirectoryPath(fileOrDirectoryPath, resolutionHost.toPath(location));
|
||||
}
|
||||
else {
|
||||
// Some file or directory in the watching directory is created
|
||||
// Return early if it does not have any of the watching extension or not the custom failed lookup path
|
||||
if (!isPathWithDefaultFailedLookupExtension(fileOrDirectoryPath) && !customFailedLookupPaths.has(fileOrDirectoryPath)) {
|
||||
return false;
|
||||
}
|
||||
// Resolution need to be invalidated if failed lookup location is same as the file or directory getting created
|
||||
isChangedFailedLookupLocation = location => resolutionHost.toPath(location) === fileOrDirectoryPath;
|
||||
}
|
||||
const hasChangedFailedLookupLocation = (resolution: ResolutionWithFailedLookupLocations) => some(resolution.failedLookupLocations, isChangedFailedLookupLocation);
|
||||
const invalidatedFilesCount = filesWithInvalidatedResolutions && filesWithInvalidatedResolutions.size;
|
||||
invalidateResolutions(
|
||||
// Resolution is invalidated if the resulting file name is same as the deleted file path
|
||||
hasChangedFailedLookupLocation
|
||||
);
|
||||
return allFilesHaveInvalidatedResolution || filesWithInvalidatedResolutions && filesWithInvalidatedResolutions.size !== invalidatedFilesCount;
|
||||
}
|
||||
|
||||
function closeTypeRootsWatch() {
|
||||
clearMap(typeRootsWatches, closeFileWatcher);
|
||||
}
|
||||
|
||||
function createTypeRootsWatch(_typeRootPath: string, typeRoot: string): FileWatcher {
|
||||
// Create new watch and recursive info
|
||||
return resolutionHost.watchTypeRootsDirectory(typeRoot, fileOrDirectory => {
|
||||
const fileOrDirectoryPath = resolutionHost.toPath(fileOrDirectory);
|
||||
if (resolutionHost.getCachedDirectoryStructureHost) {
|
||||
// Since the file existance changed, update the sourceFiles cache
|
||||
resolutionHost.getCachedDirectoryStructureHost().addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath);
|
||||
}
|
||||
|
||||
// For now just recompile
|
||||
// We could potentially store more data here about whether it was/would be really be used or not
|
||||
// and with that determine to trigger compilation but for now this is enough
|
||||
resolutionHost.onChangedAutomaticTypeDirectiveNames();
|
||||
}, WatchDirectoryFlags.Recursive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Watches the types that would get added as part of getAutomaticTypeDirectiveNames
|
||||
* To be called when compiler options change
|
||||
*/
|
||||
function updateTypeRootsWatch() {
|
||||
const options = resolutionHost.getCompilationSettings();
|
||||
if (options.types) {
|
||||
// No need to do any watch since resolution cache is going to handle the failed lookups
|
||||
// for the types added by this
|
||||
closeTypeRootsWatch();
|
||||
return;
|
||||
}
|
||||
|
||||
// we need to assume the directories exist to ensure that we can get all the type root directories that get included
|
||||
const typeRoots = getEffectiveTypeRoots(options, { directoryExists: returnTrue, getCurrentDirectory });
|
||||
if (typeRoots) {
|
||||
mutateMap(
|
||||
typeRootsWatches,
|
||||
arrayToMap(typeRoots, tr => resolutionHost.toPath(tr)),
|
||||
{
|
||||
createNewValue: createTypeRootsWatch,
|
||||
onDeleteValue: closeFileWatcher
|
||||
}
|
||||
);
|
||||
}
|
||||
else {
|
||||
closeTypeRootsWatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1856,6 +1856,12 @@ namespace ts {
|
||||
case CharacterCodes.closeBracket:
|
||||
pos++;
|
||||
return token = SyntaxKind.CloseBracketToken;
|
||||
case CharacterCodes.lessThan:
|
||||
pos++;
|
||||
return token = SyntaxKind.LessThanToken;
|
||||
case CharacterCodes.greaterThan:
|
||||
pos++;
|
||||
return token = SyntaxKind.GreaterThanToken;
|
||||
case CharacterCodes.equals:
|
||||
pos++;
|
||||
return token = SyntaxKind.EqualsToken;
|
||||
|
||||
+119
-66
@@ -30,14 +30,27 @@ namespace ts {
|
||||
mtime?: Date;
|
||||
}
|
||||
|
||||
export interface System {
|
||||
args: string[];
|
||||
/**
|
||||
* Partial interface of the System thats needed to support the caching of directory structure
|
||||
*/
|
||||
export interface DirectoryStructureHost {
|
||||
newLine: string;
|
||||
useCaseSensitiveFileNames: boolean;
|
||||
write(s: string): void;
|
||||
readFile(path: string, encoding?: string): string | undefined;
|
||||
getFileSize?(path: string): number;
|
||||
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
|
||||
fileExists(path: string): boolean;
|
||||
directoryExists(path: string): boolean;
|
||||
createDirectory(path: string): void;
|
||||
getCurrentDirectory(): string;
|
||||
getDirectories(path: string): string[];
|
||||
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
|
||||
exit(exitCode?: number): void;
|
||||
}
|
||||
|
||||
export interface System extends DirectoryStructureHost {
|
||||
args: string[];
|
||||
getFileSize?(path: string): number;
|
||||
/**
|
||||
* @pollingInterval - this parameter is used in polling-based watchers and ignored in watchers that
|
||||
* use native OS file watching
|
||||
@@ -45,13 +58,7 @@ namespace ts {
|
||||
watchFile?(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
resolvePath(path: string): string;
|
||||
fileExists(path: string): boolean;
|
||||
directoryExists(path: string): boolean;
|
||||
createDirectory(path: string): void;
|
||||
getExecutingFilePath(): string;
|
||||
getCurrentDirectory(): string;
|
||||
getDirectories(path: string): string[];
|
||||
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
|
||||
getModifiedTime?(path: string): Date;
|
||||
/**
|
||||
* This should be cryptographically secure.
|
||||
@@ -59,7 +66,6 @@ namespace ts {
|
||||
*/
|
||||
createHash?(data: string): string;
|
||||
getMemoryUsage?(): number;
|
||||
exit(exitCode?: number): void;
|
||||
realpath?(path: string): string;
|
||||
/*@internal*/ getEnvironmentVariable(name: string): string;
|
||||
/*@internal*/ tryEnableSourceMapsForHost?(): void;
|
||||
@@ -72,8 +78,7 @@ namespace ts {
|
||||
close(): void;
|
||||
}
|
||||
|
||||
export interface DirectoryWatcher extends FileWatcher {
|
||||
directoryName: string;
|
||||
interface DirectoryWatcher extends FileWatcher {
|
||||
referenceCount: number;
|
||||
}
|
||||
|
||||
@@ -152,11 +157,10 @@ namespace ts {
|
||||
watcher.referenceCount += 1;
|
||||
return;
|
||||
}
|
||||
watcher = _fs.watch(
|
||||
watcher = fsWatchDirectory(
|
||||
dirPath || ".",
|
||||
{ persistent: true },
|
||||
(eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath)
|
||||
);
|
||||
) as DirectoryWatcher;
|
||||
watcher.referenceCount = 1;
|
||||
dirWatchers.set(dirPath, watcher);
|
||||
return;
|
||||
@@ -182,9 +186,9 @@ namespace ts {
|
||||
fileWatcherCallbacks.remove(filePath, callback);
|
||||
}
|
||||
|
||||
function fileEventHandler(eventName: string, relativeFileName: string, baseDirPath: string) {
|
||||
function fileEventHandler(eventName: string, relativeFileName: string | undefined, baseDirPath: string) {
|
||||
// When files are deleted from disk, the triggered "rename" event would have a relativefileName of "undefined"
|
||||
const fileName = typeof relativeFileName !== "string"
|
||||
const fileName = !isString(relativeFileName)
|
||||
? undefined
|
||||
: ts.getNormalizedAbsolutePath(relativeFileName, baseDirPath);
|
||||
// Some applications save a working file via rename operations
|
||||
@@ -223,6 +227,95 @@ namespace ts {
|
||||
const platform: string = _os.platform();
|
||||
const useCaseSensitiveFileNames = isFileSystemCaseSensitive();
|
||||
|
||||
function fsWatchFile(fileName: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher {
|
||||
_fs.watchFile(fileName, { persistent: true, interval: pollingInterval || 250 }, fileChanged);
|
||||
return {
|
||||
close: () => _fs.unwatchFile(fileName, fileChanged)
|
||||
};
|
||||
|
||||
function fileChanged(curr: any, prev: any) {
|
||||
const isCurrZero = +curr.mtime === 0;
|
||||
const isPrevZero = +prev.mtime === 0;
|
||||
const created = !isCurrZero && isPrevZero;
|
||||
const deleted = isCurrZero && !isPrevZero;
|
||||
|
||||
const eventKind = created
|
||||
? FileWatcherEventKind.Created
|
||||
: deleted
|
||||
? FileWatcherEventKind.Deleted
|
||||
: FileWatcherEventKind.Changed;
|
||||
|
||||
if (eventKind === FileWatcherEventKind.Changed && +curr.mtime <= +prev.mtime) {
|
||||
return;
|
||||
}
|
||||
|
||||
callback(fileName, eventKind);
|
||||
}
|
||||
}
|
||||
|
||||
function fsWatchDirectory(directoryName: string, callback: (eventName: string, relativeFileName: string) => void, recursive?: boolean): FileWatcher {
|
||||
let options: any;
|
||||
/** Watcher for the directory depending on whether it is missing or present */
|
||||
let watcher = !directoryExists(directoryName) ?
|
||||
watchMissingDirectory() :
|
||||
watchPresentDirectory();
|
||||
return {
|
||||
close: () => {
|
||||
// Close the watcher (either existing directory watcher or missing directory watcher)
|
||||
watcher.close();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Watch the directory that is currently present
|
||||
* and when the watched directory is deleted, switch to missing directory watcher
|
||||
*/
|
||||
function watchPresentDirectory(): FileWatcher {
|
||||
// Node 4.0 `fs.watch` function supports the "recursive" option on both OSX and Windows
|
||||
// (ref: https://github.com/nodejs/node/pull/2649 and https://github.com/Microsoft/TypeScript/issues/4643)
|
||||
if (options === undefined) {
|
||||
if (isNode4OrLater && (process.platform === "win32" || process.platform === "darwin")) {
|
||||
options = { persistent: true, recursive: !!recursive };
|
||||
}
|
||||
else {
|
||||
options = { persistent: true };
|
||||
}
|
||||
}
|
||||
|
||||
const dirWatcher = _fs.watch(
|
||||
directoryName,
|
||||
options,
|
||||
callback
|
||||
);
|
||||
dirWatcher.on("error", () => {
|
||||
if (!directoryExists(directoryName)) {
|
||||
// Deleting directory
|
||||
watcher = watchMissingDirectory();
|
||||
// Call the callback for current directory
|
||||
callback("rename", "");
|
||||
}
|
||||
});
|
||||
return dirWatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Watch the directory that is missing
|
||||
* and switch to existing directory when the directory is created
|
||||
*/
|
||||
function watchMissingDirectory(): FileWatcher {
|
||||
return fsWatchFile(directoryName, (_fileName, eventKind) => {
|
||||
if (eventKind === FileWatcherEventKind.Created && directoryExists(directoryName)) {
|
||||
watcher.close();
|
||||
watcher = watchPresentDirectory();
|
||||
// Call the callback for current directory
|
||||
// For now it could be callback for the inner directory creation,
|
||||
// but just return current directory, better than current no-op
|
||||
callback("rename", "");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function readFile(fileName: string, _encoding?: string): string | undefined {
|
||||
if (!fileExists(fileName)) {
|
||||
return undefined;
|
||||
@@ -340,7 +433,6 @@ namespace ts {
|
||||
return filter<string>(_fs.readdirSync(path), dir => fileSystemEntryExists(combinePaths(path, dir), FileSystemEntryKind.Directory));
|
||||
}
|
||||
|
||||
const noOpFileWatcher: FileWatcher = { close: noop };
|
||||
const nodeSystem: System = {
|
||||
args: process.argv.slice(2),
|
||||
newLine: _os.EOL,
|
||||
@@ -358,60 +450,21 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
else {
|
||||
_fs.watchFile(fileName, { persistent: true, interval: pollingInterval || 250 }, fileChanged);
|
||||
return {
|
||||
close: () => _fs.unwatchFile(fileName, fileChanged)
|
||||
};
|
||||
}
|
||||
|
||||
function fileChanged(curr: any, prev: any) {
|
||||
const isCurrZero = +curr.mtime === 0;
|
||||
const isPrevZero = +prev.mtime === 0;
|
||||
const created = !isCurrZero && isPrevZero;
|
||||
const deleted = isCurrZero && !isPrevZero;
|
||||
|
||||
const eventKind = created
|
||||
? FileWatcherEventKind.Created
|
||||
: deleted
|
||||
? FileWatcherEventKind.Deleted
|
||||
: FileWatcherEventKind.Changed;
|
||||
|
||||
if (eventKind === FileWatcherEventKind.Changed && +curr.mtime <= +prev.mtime) {
|
||||
return;
|
||||
}
|
||||
|
||||
callback(fileName, eventKind);
|
||||
return fsWatchFile(fileName, callback, pollingInterval);
|
||||
}
|
||||
},
|
||||
watchDirectory: (directoryName, callback, recursive) => {
|
||||
// Node 4.0 `fs.watch` function supports the "recursive" option on both OSX and Windows
|
||||
// (ref: https://github.com/nodejs/node/pull/2649 and https://github.com/Microsoft/TypeScript/issues/4643)
|
||||
let options: any;
|
||||
if (!directoryExists(directoryName)) {
|
||||
// do nothing if target folder does not exist
|
||||
return noOpFileWatcher;
|
||||
}
|
||||
|
||||
if (isNode4OrLater && (process.platform === "win32" || process.platform === "darwin")) {
|
||||
options = { persistent: true, recursive: !!recursive };
|
||||
}
|
||||
else {
|
||||
options = { persistent: true };
|
||||
}
|
||||
|
||||
return _fs.watch(
|
||||
directoryName,
|
||||
options,
|
||||
(eventName: string, relativeFileName: string) => {
|
||||
// In watchDirectory we only care about adding and removing files (when event name is
|
||||
// "rename"); changes made within files are handled by corresponding fileWatchers (when
|
||||
// event name is "change")
|
||||
if (eventName === "rename") {
|
||||
// When deleting a file, the passed baseFileName is null
|
||||
callback(!relativeFileName ? relativeFileName : normalizePath(combinePaths(directoryName, relativeFileName)));
|
||||
}
|
||||
return fsWatchDirectory(directoryName, (eventName, relativeFileName) => {
|
||||
// In watchDirectory we only care about adding and removing files (when event name is
|
||||
// "rename"); changes made within files are handled by corresponding fileWatchers (when
|
||||
// event name is "change")
|
||||
if (eventName === "rename") {
|
||||
// When deleting a file, the passed baseFileName is null
|
||||
callback(!relativeFileName ? relativeFileName : normalizePath(combinePaths(directoryName, relativeFileName)));
|
||||
}
|
||||
);
|
||||
}, recursive);
|
||||
},
|
||||
resolvePath: path => _path.resolve(path),
|
||||
fileExists,
|
||||
|
||||
@@ -418,7 +418,7 @@ namespace ts {
|
||||
return createElementAccess(value, argumentExpression);
|
||||
}
|
||||
else {
|
||||
const name = createIdentifier(unescapeLeadingUnderscores(propertyName.escapedText));
|
||||
const name = createIdentifier(idText(propertyName));
|
||||
return createPropertyAccess(value, name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,6 +279,13 @@ namespace ts {
|
||||
let currentSourceFile: SourceFile;
|
||||
let currentText: string;
|
||||
let hierarchyFacts: HierarchyFacts;
|
||||
let taggedTemplateStringDeclarations: VariableDeclaration[];
|
||||
|
||||
function recordTaggedTemplateString(temp: Identifier) {
|
||||
taggedTemplateStringDeclarations = append(
|
||||
taggedTemplateStringDeclarations,
|
||||
createVariableDeclaration(temp));
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to track if we are emitting body of the converted loop
|
||||
@@ -307,6 +314,7 @@ namespace ts {
|
||||
|
||||
currentSourceFile = undefined;
|
||||
currentText = undefined;
|
||||
taggedTemplateStringDeclarations = undefined;
|
||||
hierarchyFacts = HierarchyFacts.None;
|
||||
return visited;
|
||||
}
|
||||
@@ -520,6 +528,11 @@ namespace ts {
|
||||
addCaptureThisForNodeIfNeeded(statements, node);
|
||||
statementOffset = addCustomPrologue(statements, node.statements, statementOffset, visitor);
|
||||
addRange(statements, visitNodes(node.statements, visitor, isStatement, statementOffset));
|
||||
if (taggedTemplateStringDeclarations) {
|
||||
statements.push(
|
||||
createVariableStatement(/*modifiers*/ undefined,
|
||||
createVariableDeclarationList(taggedTemplateStringDeclarations)));
|
||||
}
|
||||
addRange(statements, endLexicalEnvironment());
|
||||
exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None);
|
||||
return updateSourceFileNode(
|
||||
@@ -609,7 +622,7 @@ namespace ts {
|
||||
// - break/continue is non-labeled and located in non-converted loop/switch statement
|
||||
const jump = node.kind === SyntaxKind.BreakStatement ? Jump.Break : Jump.Continue;
|
||||
const canUseBreakOrContinue =
|
||||
(node.label && convertedLoopState.labels && convertedLoopState.labels.get(unescapeLeadingUnderscores(node.label.escapedText))) ||
|
||||
(node.label && convertedLoopState.labels && convertedLoopState.labels.get(idText(node.label))) ||
|
||||
(!node.label && (convertedLoopState.allowedNonLabeledJumps & jump));
|
||||
|
||||
if (!canUseBreakOrContinue) {
|
||||
@@ -628,11 +641,11 @@ namespace ts {
|
||||
else {
|
||||
if (node.kind === SyntaxKind.BreakStatement) {
|
||||
labelMarker = `break-${node.label.escapedText}`;
|
||||
setLabeledJump(convertedLoopState, /*isBreak*/ true, unescapeLeadingUnderscores(node.label.escapedText), labelMarker);
|
||||
setLabeledJump(convertedLoopState, /*isBreak*/ true, idText(node.label), labelMarker);
|
||||
}
|
||||
else {
|
||||
labelMarker = `continue-${node.label.escapedText}`;
|
||||
setLabeledJump(convertedLoopState, /*isBreak*/ false, unescapeLeadingUnderscores(node.label.escapedText), labelMarker);
|
||||
setLabeledJump(convertedLoopState, /*isBreak*/ false, idText(node.label), labelMarker);
|
||||
}
|
||||
}
|
||||
let returnExpression: Expression = createLiteral(labelMarker);
|
||||
@@ -2187,11 +2200,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
function recordLabel(node: LabeledStatement) {
|
||||
convertedLoopState.labels.set(unescapeLeadingUnderscores(node.label.escapedText), true);
|
||||
convertedLoopState.labels.set(idText(node.label), true);
|
||||
}
|
||||
|
||||
function resetLabel(node: LabeledStatement) {
|
||||
convertedLoopState.labels.set(unescapeLeadingUnderscores(node.label.escapedText), false);
|
||||
convertedLoopState.labels.set(idText(node.label), false);
|
||||
}
|
||||
|
||||
function visitLabeledStatement(node: LabeledStatement): VisitResult<Statement> {
|
||||
@@ -3004,7 +3017,7 @@ namespace ts {
|
||||
else {
|
||||
loopParameters.push(createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, name));
|
||||
if (resolver.getNodeCheckFlags(decl) & NodeCheckFlags.NeedsLoopOutParameter) {
|
||||
const outParamName = createUniqueName("out_" + unescapeLeadingUnderscores(name.escapedText));
|
||||
const outParamName = createUniqueName("out_" + idText(name));
|
||||
loopOutParameters.push({ originalName: name, outParamName });
|
||||
}
|
||||
}
|
||||
@@ -3636,11 +3649,10 @@ namespace ts {
|
||||
// Visit the tag expression
|
||||
const tag = visitNode(node.tag, visitor, isExpression);
|
||||
|
||||
// Allocate storage for the template site object
|
||||
const temp = createTempVariable(hoistVariableDeclaration);
|
||||
|
||||
// Build up the template arguments and the raw and cooked strings for the template.
|
||||
const templateArguments: Expression[] = [temp];
|
||||
// We start out with 'undefined' for the first argument and revisit later
|
||||
// to avoid walking over the template string twice and shifting all our arguments over after the fact.
|
||||
const templateArguments: Expression[] = [undefined];
|
||||
const cookedStrings: Expression[] = [];
|
||||
const rawStrings: Expression[] = [];
|
||||
const template = node.template;
|
||||
@@ -3658,16 +3670,25 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: The parentheses here is entirely optional as we are now able to auto-
|
||||
// parenthesize when rebuilding the tree. This should be removed in a
|
||||
// future version. It is here for now to match our existing emit.
|
||||
return createParen(
|
||||
inlineExpressions([
|
||||
createAssignment(temp, createArrayLiteral(cookedStrings)),
|
||||
createAssignment(createPropertyAccess(temp, "raw"), createArrayLiteral(rawStrings)),
|
||||
createCall(tag, /*typeArguments*/ undefined, templateArguments)
|
||||
])
|
||||
);
|
||||
const helperCall = createTemplateObjectHelper(context, createArrayLiteral(cookedStrings), createArrayLiteral(rawStrings));
|
||||
|
||||
// Create a variable to cache the template object if we're in a module.
|
||||
// Do not do this in the global scope, as any variable we currently generate could conflict with
|
||||
// variables from outside of the current compilation. In the future, we can revisit this behavior.
|
||||
if (isExternalModule(currentSourceFile)) {
|
||||
const tempVar = createTempVariable(recordTaggedTemplateString);
|
||||
templateArguments[0] = createLogicalOr(
|
||||
tempVar,
|
||||
createAssignment(
|
||||
tempVar,
|
||||
helperCall)
|
||||
);
|
||||
}
|
||||
else {
|
||||
templateArguments[0] = helperCall;
|
||||
}
|
||||
|
||||
return createCall(tag, /*typeArguments*/ undefined, templateArguments);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4036,6 +4057,18 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
function createTemplateObjectHelper(context: TransformationContext, cooked: ArrayLiteralExpression, raw: ArrayLiteralExpression) {
|
||||
context.requestEmitHelper(templateObjectHelper);
|
||||
return createCall(
|
||||
getHelperName("__makeTemplateObject"),
|
||||
/*typeArguments*/ undefined,
|
||||
[
|
||||
cooked,
|
||||
raw
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
const extendsHelper: EmitHelper = {
|
||||
name: "typescript:extends",
|
||||
scoped: false,
|
||||
@@ -4052,4 +4085,16 @@ namespace ts {
|
||||
};
|
||||
})();`
|
||||
};
|
||||
|
||||
const templateObjectHelper: EmitHelper = {
|
||||
name: "typescript:makeTemplateObject",
|
||||
scoped: false,
|
||||
priority: 0,
|
||||
text: `
|
||||
var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
|
||||
if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
|
||||
return cooked;
|
||||
};`
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -363,7 +363,7 @@ namespace ts {
|
||||
function substitutePropertyAccessExpression(node: PropertyAccessExpression) {
|
||||
if (node.expression.kind === SyntaxKind.SuperKeyword) {
|
||||
return createSuperAccessInAsyncMethod(
|
||||
createLiteral(unescapeLeadingUnderscores(node.name.escapedText)),
|
||||
createLiteral(idText(node.name)),
|
||||
node
|
||||
);
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace ts {
|
||||
* @param name An Identifier
|
||||
*/
|
||||
function trySubstituteReservedName(name: Identifier) {
|
||||
const token = name.originalKeywordKind || (nodeIsSynthesized(name) ? stringToToken(unescapeLeadingUnderscores(name.escapedText)) : undefined);
|
||||
const token = name.originalKeywordKind || (nodeIsSynthesized(name) ? stringToToken(idText(name)) : undefined);
|
||||
if (token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord) {
|
||||
return setTextRange(createLiteral(name), name);
|
||||
}
|
||||
|
||||
@@ -378,7 +378,7 @@ namespace ts {
|
||||
const catchVariable = getGeneratedNameForNode(errorRecord);
|
||||
const returnMethod = createTempVariable(/*recordTempVariable*/ undefined);
|
||||
const callValues = createAsyncValuesHelper(context, expression, /*location*/ node.expression);
|
||||
const callNext = createCall(createPropertyAccess(iterator, "next" ), /*typeArguments*/ undefined, []);
|
||||
const callNext = createCall(createPropertyAccess(iterator, "next"), /*typeArguments*/ undefined, []);
|
||||
const getDone = createPropertyAccess(result, "done");
|
||||
const getValue = createPropertyAccess(result, "value");
|
||||
const callReturn = createFunctionCall(returnMethod, iterator, []);
|
||||
@@ -790,7 +790,7 @@ namespace ts {
|
||||
function substitutePropertyAccessExpression(node: PropertyAccessExpression) {
|
||||
if (node.expression.kind === SyntaxKind.SuperKeyword) {
|
||||
return createSuperAccessInAsyncMethod(
|
||||
createLiteral(unescapeLeadingUnderscores(node.name.escapedText)),
|
||||
createLiteral(idText(node.name)),
|
||||
node
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1634,7 +1634,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function transformAndEmitContinueStatement(node: ContinueStatement): void {
|
||||
const label = findContinueTarget(node.label ? unescapeLeadingUnderscores(node.label.escapedText) : undefined);
|
||||
const label = findContinueTarget(node.label ? idText(node.label) : undefined);
|
||||
if (label > 0) {
|
||||
emitBreak(label, /*location*/ node);
|
||||
}
|
||||
@@ -1646,7 +1646,7 @@ namespace ts {
|
||||
|
||||
function visitContinueStatement(node: ContinueStatement): Statement {
|
||||
if (inStatementContainingYield) {
|
||||
const label = findContinueTarget(node.label && unescapeLeadingUnderscores(node.label.escapedText));
|
||||
const label = findContinueTarget(node.label && idText(node.label));
|
||||
if (label > 0) {
|
||||
return createInlineBreak(label, /*location*/ node);
|
||||
}
|
||||
@@ -1656,7 +1656,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function transformAndEmitBreakStatement(node: BreakStatement): void {
|
||||
const label = findBreakTarget(node.label ? unescapeLeadingUnderscores(node.label.escapedText) : undefined);
|
||||
const label = findBreakTarget(node.label ? idText(node.label) : undefined);
|
||||
if (label > 0) {
|
||||
emitBreak(label, /*location*/ node);
|
||||
}
|
||||
@@ -1668,7 +1668,7 @@ namespace ts {
|
||||
|
||||
function visitBreakStatement(node: BreakStatement): Statement {
|
||||
if (inStatementContainingYield) {
|
||||
const label = findBreakTarget(node.label && unescapeLeadingUnderscores(node.label.escapedText));
|
||||
const label = findBreakTarget(node.label && idText(node.label));
|
||||
if (label > 0) {
|
||||
return createInlineBreak(label, /*location*/ node);
|
||||
}
|
||||
@@ -1847,7 +1847,7 @@ namespace ts {
|
||||
// /*body*/
|
||||
// .endlabeled
|
||||
// .mark endLabel
|
||||
beginLabeledBlock(unescapeLeadingUnderscores(node.label.escapedText));
|
||||
beginLabeledBlock(idText(node.label));
|
||||
transformAndEmitEmbeddedStatement(node.statement);
|
||||
endLabeledBlock();
|
||||
}
|
||||
@@ -1858,7 +1858,7 @@ namespace ts {
|
||||
|
||||
function visitLabeledStatement(node: LabeledStatement) {
|
||||
if (inStatementContainingYield) {
|
||||
beginScriptLabeledBlock(unescapeLeadingUnderscores(node.label.escapedText));
|
||||
beginScriptLabeledBlock(idText(node.label));
|
||||
}
|
||||
|
||||
node = visitEachChild(node, visitor, context);
|
||||
@@ -1959,7 +1959,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function substituteExpressionIdentifier(node: Identifier) {
|
||||
if (!isGeneratedIdentifier(node) && renamedCatchVariables && renamedCatchVariables.has(unescapeLeadingUnderscores(node.escapedText))) {
|
||||
if (!isGeneratedIdentifier(node) && renamedCatchVariables && renamedCatchVariables.has(idText(node))) {
|
||||
const original = getOriginalNode(node);
|
||||
if (isIdentifier(original) && original.parent) {
|
||||
const declaration = resolver.getReferencedValueDeclaration(original);
|
||||
@@ -2128,7 +2128,7 @@ namespace ts {
|
||||
hoistVariableDeclaration(variable.name);
|
||||
}
|
||||
else {
|
||||
const text = unescapeLeadingUnderscores((<Identifier>variable.name).escapedText);
|
||||
const text = idText(<Identifier>variable.name);
|
||||
name = declareLocal(text);
|
||||
if (!renamedCatchVariables) {
|
||||
renamedCatchVariables = createMap<boolean>();
|
||||
|
||||
@@ -253,7 +253,7 @@ namespace ts {
|
||||
else {
|
||||
const name = (<JsxOpeningLikeElement>node).tagName;
|
||||
if (isIdentifier(name) && isIntrinsicJsxName(name.escapedText)) {
|
||||
return createLiteral(unescapeLeadingUnderscores(name.escapedText));
|
||||
return createLiteral(idText(name));
|
||||
}
|
||||
else {
|
||||
return createExpressionFromEntityName(name);
|
||||
@@ -268,11 +268,12 @@ namespace ts {
|
||||
*/
|
||||
function getAttributeName(node: JsxAttribute): StringLiteral | Identifier {
|
||||
const name = node.name;
|
||||
if (/^[A-Za-z_]\w*$/.test(unescapeLeadingUnderscores(name.escapedText))) {
|
||||
const text = idText(name);
|
||||
if (/^[A-Za-z_]\w*$/.test(text)) {
|
||||
return name;
|
||||
}
|
||||
else {
|
||||
return createLiteral(unescapeLeadingUnderscores(name.escapedText));
|
||||
return createLiteral(text);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -861,10 +861,10 @@ namespace ts {
|
||||
if (original && hasAssociatedEndOfDeclarationMarker(original)) {
|
||||
// Defer exports until we encounter an EndOfDeclarationMarker node
|
||||
const id = getOriginalNodeId(node);
|
||||
deferredExports[id] = appendExportStatement(deferredExports[id], createIdentifier("default"), node.expression, /*location*/ node, /*allowComments*/ true);
|
||||
deferredExports[id] = appendExportStatement(deferredExports[id], createIdentifier("default"), visitNode(node.expression, importCallExpressionVisitor), /*location*/ node, /*allowComments*/ true);
|
||||
}
|
||||
else {
|
||||
statements = appendExportStatement(statements, createIdentifier("default"), node.expression, /*location*/ node, /*allowComments*/ true);
|
||||
statements = appendExportStatement(statements, createIdentifier("default"), visitNode(node.expression, importCallExpressionVisitor), /*location*/ node, /*allowComments*/ true);
|
||||
}
|
||||
|
||||
return singleOrMany(statements);
|
||||
@@ -1231,7 +1231,7 @@ namespace ts {
|
||||
*/
|
||||
function appendExportsOfDeclaration(statements: Statement[] | undefined, decl: Declaration): Statement[] | undefined {
|
||||
const name = getDeclarationName(decl);
|
||||
const exportSpecifiers = currentModuleInfo.exportSpecifiers.get(unescapeLeadingUnderscores(name.escapedText));
|
||||
const exportSpecifiers = currentModuleInfo.exportSpecifiers.get(idText(name));
|
||||
if (exportSpecifiers) {
|
||||
for (const exportSpecifier of exportSpecifiers) {
|
||||
statements = appendExportStatement(statements, exportSpecifier.name, name, /*location*/ exportSpecifier.name);
|
||||
|
||||
@@ -353,7 +353,7 @@ namespace ts {
|
||||
// write name of indirectly exported entry, i.e. 'export {x} from ...'
|
||||
exportedNames.push(
|
||||
createPropertyAssignment(
|
||||
createLiteral(unescapeLeadingUnderscores((element.name || element.propertyName).escapedText)),
|
||||
createLiteral(idText(element.name || element.propertyName)),
|
||||
createTrue()
|
||||
)
|
||||
);
|
||||
@@ -504,10 +504,10 @@ namespace ts {
|
||||
for (const e of (<ExportDeclaration>entry).exportClause.elements) {
|
||||
properties.push(
|
||||
createPropertyAssignment(
|
||||
createLiteral(unescapeLeadingUnderscores(e.name.escapedText)),
|
||||
createLiteral(idText(e.name)),
|
||||
createElementAccess(
|
||||
parameterName,
|
||||
createLiteral(unescapeLeadingUnderscores((e.propertyName || e.name).escapedText))
|
||||
createLiteral(idText(e.propertyName || e.name))
|
||||
)
|
||||
)
|
||||
);
|
||||
@@ -1028,7 +1028,7 @@ namespace ts {
|
||||
let excludeName: string;
|
||||
if (exportSelf) {
|
||||
statements = appendExportStatement(statements, decl.name, getLocalName(decl));
|
||||
excludeName = unescapeLeadingUnderscores(decl.name.escapedText);
|
||||
excludeName = idText(decl.name);
|
||||
}
|
||||
|
||||
statements = appendExportsOfDeclaration(statements, decl, excludeName);
|
||||
@@ -1080,7 +1080,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
const name = getDeclarationName(decl);
|
||||
const exportSpecifiers = moduleInfo.exportSpecifiers.get(unescapeLeadingUnderscores(name.escapedText));
|
||||
const exportSpecifiers = moduleInfo.exportSpecifiers.get(idText(name));
|
||||
if (exportSpecifiers) {
|
||||
for (const exportSpecifier of exportSpecifiers) {
|
||||
if (exportSpecifier.name.escapedText !== excludeName) {
|
||||
|
||||
@@ -2038,7 +2038,7 @@ namespace ts {
|
||||
: (<ComputedPropertyName>name).expression;
|
||||
}
|
||||
else if (isIdentifier(name)) {
|
||||
return createLiteral(unescapeLeadingUnderscores(name.escapedText));
|
||||
return createLiteral(idText(name));
|
||||
}
|
||||
else {
|
||||
return getSynthesizedClone(name);
|
||||
@@ -3240,7 +3240,7 @@ namespace ts {
|
||||
function getClassAliasIfNeeded(node: ClassDeclaration) {
|
||||
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference) {
|
||||
enableSubstitutionForClassAliases();
|
||||
const classAlias = createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? unescapeLeadingUnderscores(node.name.escapedText) : "default");
|
||||
const classAlias = createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? idText(node.name) : "default");
|
||||
classAliases[getOriginalNodeId(node)] = classAlias;
|
||||
hoistVariableDeclaration(classAlias);
|
||||
return classAlias;
|
||||
|
||||
@@ -58,9 +58,9 @@ namespace ts {
|
||||
else {
|
||||
// export { x, y }
|
||||
for (const specifier of (<ExportDeclaration>node).exportClause.elements) {
|
||||
if (!uniqueExports.get(unescapeLeadingUnderscores(specifier.name.escapedText))) {
|
||||
if (!uniqueExports.get(idText(specifier.name))) {
|
||||
const name = specifier.propertyName || specifier.name;
|
||||
exportSpecifiers.add(unescapeLeadingUnderscores(name.escapedText), specifier);
|
||||
exportSpecifiers.add(idText(name), specifier);
|
||||
|
||||
const decl = resolver.getReferencedImportDeclaration(name)
|
||||
|| resolver.getReferencedValueDeclaration(name);
|
||||
@@ -69,7 +69,7 @@ namespace ts {
|
||||
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(decl), specifier.name);
|
||||
}
|
||||
|
||||
uniqueExports.set(unescapeLeadingUnderscores(specifier.name.escapedText), true);
|
||||
uniqueExports.set(idText(specifier.name), true);
|
||||
exportedNames = append(exportedNames, specifier.name);
|
||||
}
|
||||
}
|
||||
@@ -103,9 +103,9 @@ namespace ts {
|
||||
else {
|
||||
// export function x() { }
|
||||
const name = (<FunctionDeclaration>node).name;
|
||||
if (!uniqueExports.get(unescapeLeadingUnderscores(name.escapedText))) {
|
||||
if (!uniqueExports.get(idText(name))) {
|
||||
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name);
|
||||
uniqueExports.set(unescapeLeadingUnderscores(name.escapedText), true);
|
||||
uniqueExports.set(idText(name), true);
|
||||
exportedNames = append(exportedNames, name);
|
||||
}
|
||||
}
|
||||
@@ -124,9 +124,9 @@ namespace ts {
|
||||
else {
|
||||
// export class x { }
|
||||
const name = (<ClassDeclaration>node).name;
|
||||
if (name && !uniqueExports.get(unescapeLeadingUnderscores(name.escapedText))) {
|
||||
if (name && !uniqueExports.get(idText(name))) {
|
||||
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name);
|
||||
uniqueExports.set(unescapeLeadingUnderscores(name.escapedText), true);
|
||||
uniqueExports.set(idText(name), true);
|
||||
exportedNames = append(exportedNames, name);
|
||||
}
|
||||
}
|
||||
@@ -158,8 +158,9 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else if (!isGeneratedIdentifier(decl.name)) {
|
||||
if (!uniqueExports.get(unescapeLeadingUnderscores(decl.name.escapedText))) {
|
||||
uniqueExports.set(unescapeLeadingUnderscores(decl.name.escapedText), true);
|
||||
const text = idText(decl.name);
|
||||
if (!uniqueExports.get(text)) {
|
||||
uniqueExports.set(text, true);
|
||||
exportedNames = append(exportedNames, decl.name);
|
||||
}
|
||||
}
|
||||
|
||||
+92
-350
@@ -1,48 +1,13 @@
|
||||
/// <reference path="program.ts"/>
|
||||
/// <reference path="watch.ts"/>
|
||||
/// <reference path="commandLineParser.ts"/>
|
||||
|
||||
namespace ts {
|
||||
export interface SourceFile {
|
||||
fileWatcher?: FileWatcher;
|
||||
}
|
||||
|
||||
interface Statistic {
|
||||
name: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
const defaultFormatDiagnosticsHost: FormatDiagnosticsHost = {
|
||||
getCurrentDirectory: () => sys.getCurrentDirectory(),
|
||||
getNewLine: () => sys.newLine,
|
||||
getCanonicalFileName: createGetCanonicalFileName(sys.useCaseSensitiveFileNames)
|
||||
};
|
||||
|
||||
let reportDiagnosticWorker = reportDiagnosticSimply;
|
||||
|
||||
function reportDiagnostic(diagnostic: Diagnostic, host: FormatDiagnosticsHost) {
|
||||
reportDiagnosticWorker(diagnostic, host || defaultFormatDiagnosticsHost);
|
||||
}
|
||||
|
||||
function reportDiagnostics(diagnostics: Diagnostic[], host: FormatDiagnosticsHost): void {
|
||||
for (const diagnostic of diagnostics) {
|
||||
reportDiagnostic(diagnostic, host);
|
||||
}
|
||||
}
|
||||
|
||||
function reportEmittedFiles(files: string[]): void {
|
||||
if (!files || files.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentDir = sys.getCurrentDirectory();
|
||||
|
||||
for (const file of files) {
|
||||
const filepath = getNormalizedAbsolutePath(file, currentDir);
|
||||
|
||||
sys.write(`TSFILE: ${filepath}${sys.newLine}`);
|
||||
}
|
||||
}
|
||||
|
||||
function countLines(program: Program): number {
|
||||
let count = 0;
|
||||
forEach(program.getSourceFiles(), file => {
|
||||
@@ -56,25 +21,11 @@ namespace ts {
|
||||
return <string>diagnostic.messageText;
|
||||
}
|
||||
|
||||
function reportDiagnosticSimply(diagnostic: Diagnostic, host: FormatDiagnosticsHost): void {
|
||||
sys.write(ts.formatDiagnostics([diagnostic], host));
|
||||
}
|
||||
|
||||
function reportDiagnosticWithColorAndContext(diagnostic: Diagnostic, host: FormatDiagnosticsHost): void {
|
||||
sys.write(ts.formatDiagnosticsWithColorAndContext([diagnostic], host) + sys.newLine);
|
||||
}
|
||||
|
||||
function reportWatchDiagnostic(diagnostic: Diagnostic) {
|
||||
let output = new Date().toLocaleTimeString() + " - ";
|
||||
|
||||
if (diagnostic.file) {
|
||||
const loc = getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start);
|
||||
output += `${ diagnostic.file.fileName }(${ loc.line + 1 },${ loc.character + 1 }): `;
|
||||
let reportDiagnostic = createDiagnosticReporter(sys, reportDiagnosticSimply);
|
||||
function udpateReportDiagnostic(options: CompilerOptions) {
|
||||
if (options.pretty) {
|
||||
reportDiagnostic = createDiagnosticReporter(sys, reportDiagnosticWithColorAndContext);
|
||||
}
|
||||
|
||||
output += `${ flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine) }${ sys.newLine + sys.newLine + sys.newLine }`;
|
||||
|
||||
sys.write(output);
|
||||
}
|
||||
|
||||
function padLeft(s: string, length: number) {
|
||||
@@ -98,25 +49,12 @@ namespace ts {
|
||||
|
||||
export function executeCommandLine(args: string[]): void {
|
||||
const commandLine = parseCommandLine(args);
|
||||
let configFileName: string; // Configuration file name (if any)
|
||||
let cachedConfigFileText: string; // Cached configuration file text, used for reparsing (if any)
|
||||
let directoryWatcher: FileWatcher; // Directory watcher to monitor source file addition/removal
|
||||
let cachedProgram: Program; // Program cached from last compilation
|
||||
let rootFileNames: string[]; // Root fileNames for compilation
|
||||
let compilerOptions: CompilerOptions; // Compiler options for compilation
|
||||
let compilerHost: CompilerHost; // Compiler host
|
||||
let hostGetSourceFile: typeof compilerHost.getSourceFile; // getSourceFile method from default host
|
||||
let timerHandleForRecompilation: any; // Handle for 0.25s wait timer to trigger recompilation
|
||||
let timerHandleForDirectoryChanges: any; // Handle for 0.25s wait timer to trigger directory change handler
|
||||
|
||||
// This map stores and reuses results of fileExists check that happen inside 'createProgram'
|
||||
// This allows to save time in module resolution heavy scenarios when existence of the same file might be checked multiple times.
|
||||
let cachedExistingFiles: Map<boolean>;
|
||||
let hostFileExists: typeof compilerHost.fileExists;
|
||||
|
||||
// Configuration file name (if any)
|
||||
let configFileName: string;
|
||||
if (commandLine.options.locale) {
|
||||
if (!isJSONSupported()) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--locale"), /* host */ undefined);
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--locale"));
|
||||
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
}
|
||||
validateLocaleAndSetLanguage(commandLine.options.locale, sys, commandLine.errors);
|
||||
@@ -125,7 +63,7 @@ namespace ts {
|
||||
// If there are any errors due to command line parsing and/or
|
||||
// setting up localization, report them and quit.
|
||||
if (commandLine.errors.length > 0) {
|
||||
reportDiagnostics(commandLine.errors, compilerHost);
|
||||
reportDiagnostics(commandLine.errors, reportDiagnostic);
|
||||
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
}
|
||||
|
||||
@@ -147,11 +85,11 @@ namespace ts {
|
||||
|
||||
if (commandLine.options.project) {
|
||||
if (!isJSONSupported()) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--project"), /* host */ undefined);
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--project"));
|
||||
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
}
|
||||
if (commandLine.fileNames.length !== 0) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Option_project_cannot_be_mixed_with_source_files_on_a_command_line), /* host */ undefined);
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Option_project_cannot_be_mixed_with_source_files_on_a_command_line));
|
||||
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
}
|
||||
|
||||
@@ -159,14 +97,14 @@ namespace ts {
|
||||
if (!fileOrDirectory /* current directory "." */ || sys.directoryExists(fileOrDirectory)) {
|
||||
configFileName = combinePaths(fileOrDirectory, "tsconfig.json");
|
||||
if (!sys.fileExists(configFileName)) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Cannot_find_a_tsconfig_json_file_at_the_specified_directory_Colon_0, commandLine.options.project), /* host */ undefined);
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Cannot_find_a_tsconfig_json_file_at_the_specified_directory_Colon_0, commandLine.options.project));
|
||||
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
}
|
||||
}
|
||||
else {
|
||||
configFileName = fileOrDirectory;
|
||||
if (!sys.fileExists(configFileName)) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_specified_path_does_not_exist_Colon_0, commandLine.options.project), /* host */ undefined);
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_specified_path_does_not_exist_Colon_0, commandLine.options.project));
|
||||
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
}
|
||||
}
|
||||
@@ -182,249 +120,94 @@ namespace ts {
|
||||
return sys.exit(ExitStatus.Success);
|
||||
}
|
||||
|
||||
if (isWatchSet(commandLine.options)) {
|
||||
if (!sys.watchFile) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch"), /* host */ undefined);
|
||||
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
}
|
||||
if (configFileName) {
|
||||
sys.watchFile(configFileName, configFileChanged);
|
||||
}
|
||||
if (sys.watchDirectory && configFileName) {
|
||||
const directory = ts.getDirectoryPath(configFileName);
|
||||
directoryWatcher = sys.watchDirectory(
|
||||
// When the configFileName is just "tsconfig.json", the watched directory should be
|
||||
// the current directory; if there is a given "project" parameter, then the configFileName
|
||||
// is an absolute file name.
|
||||
directory === "" ? "." : directory,
|
||||
watchedDirectoryChanged, /*recursive*/ true);
|
||||
}
|
||||
}
|
||||
|
||||
performCompilation();
|
||||
|
||||
function parseConfigFile(): ParsedCommandLine {
|
||||
if (!cachedConfigFileText) {
|
||||
try {
|
||||
cachedConfigFileText = sys.readFile(configFileName);
|
||||
}
|
||||
catch (e) {
|
||||
const error = createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, configFileName, e.message);
|
||||
reportWatchDiagnostic(error);
|
||||
sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!cachedConfigFileText) {
|
||||
const error = createCompilerDiagnostic(Diagnostics.File_0_not_found, configFileName);
|
||||
reportDiagnostics([error], /* compilerHost */ undefined);
|
||||
sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
return;
|
||||
}
|
||||
|
||||
const result = parseJsonText(configFileName, cachedConfigFileText);
|
||||
reportDiagnostics(result.parseDiagnostics, /* compilerHost */ undefined);
|
||||
|
||||
const cwd = sys.getCurrentDirectory();
|
||||
const configParseResult = parseJsonSourceFileConfigFileContent(result, sys, getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd), commandLine.options, getNormalizedAbsolutePath(configFileName, cwd));
|
||||
reportDiagnostics(configParseResult.errors, /* compilerHost */ undefined);
|
||||
|
||||
const commandLineOptions = commandLine.options;
|
||||
if (configFileName) {
|
||||
const reportWatchDiagnostic = createWatchDiagnosticReporter();
|
||||
const configParseResult = parseConfigFile(configFileName, commandLineOptions, sys, reportDiagnostic, reportWatchDiagnostic);
|
||||
udpateReportDiagnostic(configParseResult.options);
|
||||
if (isWatchSet(configParseResult.options)) {
|
||||
if (!sys.watchFile) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch"), /* host */ undefined);
|
||||
sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
}
|
||||
|
||||
if (!directoryWatcher && sys.watchDirectory && configFileName) {
|
||||
const directory = ts.getDirectoryPath(configFileName);
|
||||
directoryWatcher = sys.watchDirectory(
|
||||
// When the configFileName is just "tsconfig.json", the watched directory should be
|
||||
// the current directory; if there is a given "project" parameter, then the configFileName
|
||||
// is an absolute file name.
|
||||
directory === "" ? "." : directory,
|
||||
watchedDirectoryChanged, /*recursive*/ true);
|
||||
}
|
||||
reportWatchModeWithoutSysSupport();
|
||||
createWatchModeWithConfigFile(configParseResult, commandLineOptions, createWatchingSystemHost(reportWatchDiagnostic));
|
||||
}
|
||||
return configParseResult;
|
||||
}
|
||||
|
||||
// Invoked to perform initial compilation or re-compilation in watch mode
|
||||
function performCompilation() {
|
||||
|
||||
if (!cachedProgram) {
|
||||
if (configFileName) {
|
||||
const configParseResult = parseConfigFile();
|
||||
rootFileNames = configParseResult.fileNames;
|
||||
compilerOptions = configParseResult.options;
|
||||
}
|
||||
else {
|
||||
rootFileNames = commandLine.fileNames;
|
||||
compilerOptions = commandLine.options;
|
||||
}
|
||||
compilerHost = createCompilerHost(compilerOptions);
|
||||
hostGetSourceFile = compilerHost.getSourceFile;
|
||||
compilerHost.getSourceFile = getSourceFile;
|
||||
|
||||
hostFileExists = compilerHost.fileExists;
|
||||
compilerHost.fileExists = cachedFileExists;
|
||||
}
|
||||
|
||||
if (compilerOptions.pretty) {
|
||||
reportDiagnosticWorker = reportDiagnosticWithColorAndContext;
|
||||
}
|
||||
|
||||
// reset the cache of existing files
|
||||
cachedExistingFiles = createMap<boolean>();
|
||||
|
||||
const compileResult = compile(rootFileNames, compilerOptions, compilerHost);
|
||||
|
||||
if (!isWatchSet(compilerOptions)) {
|
||||
return sys.exit(compileResult.exitStatus);
|
||||
}
|
||||
|
||||
setCachedProgram(compileResult.program);
|
||||
reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.Compilation_complete_Watching_for_file_changes));
|
||||
|
||||
const missingPaths = compileResult.program.getMissingFilePaths();
|
||||
missingPaths.forEach(path => {
|
||||
const fileWatcher = sys.watchFile(path, (_fileName, eventKind) => {
|
||||
if (eventKind === FileWatcherEventKind.Created) {
|
||||
fileWatcher.close();
|
||||
startTimerForRecompilation();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function cachedFileExists(fileName: string): boolean {
|
||||
let fileExists = cachedExistingFiles.get(fileName);
|
||||
if (fileExists === undefined) {
|
||||
cachedExistingFiles.set(fileName, fileExists = hostFileExists(fileName));
|
||||
}
|
||||
return fileExists;
|
||||
}
|
||||
|
||||
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void) {
|
||||
// Return existing SourceFile object if one is available
|
||||
if (cachedProgram) {
|
||||
const sourceFile = cachedProgram.getSourceFile(fileName);
|
||||
// A modified source file has no watcher and should not be reused
|
||||
if (sourceFile && sourceFile.fileWatcher) {
|
||||
return sourceFile;
|
||||
}
|
||||
}
|
||||
// Use default host function
|
||||
const sourceFile = hostGetSourceFile(fileName, languageVersion, onError);
|
||||
if (sourceFile && isWatchSet(compilerOptions) && sys.watchFile) {
|
||||
// Attach a file watcher
|
||||
sourceFile.fileWatcher = sys.watchFile(sourceFile.fileName, (_fileName, eventKind) => sourceFileChanged(sourceFile, eventKind));
|
||||
}
|
||||
return sourceFile;
|
||||
}
|
||||
|
||||
// Change cached program to the given program
|
||||
function setCachedProgram(program: Program) {
|
||||
if (cachedProgram) {
|
||||
const newSourceFiles = program ? program.getSourceFiles() : undefined;
|
||||
forEach(cachedProgram.getSourceFiles(), sourceFile => {
|
||||
if (!(newSourceFiles && contains(newSourceFiles, sourceFile))) {
|
||||
if (sourceFile.fileWatcher) {
|
||||
sourceFile.fileWatcher.close();
|
||||
sourceFile.fileWatcher = undefined;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
cachedProgram = program;
|
||||
}
|
||||
|
||||
// If a source file changes, mark it as unwatched and start the recompilation timer
|
||||
function sourceFileChanged(sourceFile: SourceFile, eventKind: FileWatcherEventKind) {
|
||||
sourceFile.fileWatcher.close();
|
||||
sourceFile.fileWatcher = undefined;
|
||||
if (eventKind === FileWatcherEventKind.Deleted) {
|
||||
unorderedRemoveItem(rootFileNames, sourceFile.fileName);
|
||||
}
|
||||
startTimerForRecompilation();
|
||||
}
|
||||
|
||||
// If the configuration file changes, forget cached program and start the recompilation timer
|
||||
function configFileChanged() {
|
||||
setCachedProgram(undefined);
|
||||
cachedConfigFileText = undefined;
|
||||
startTimerForRecompilation();
|
||||
}
|
||||
|
||||
function watchedDirectoryChanged(fileName: string) {
|
||||
if (fileName && !ts.isSupportedSourceFileName(fileName, compilerOptions)) {
|
||||
return;
|
||||
}
|
||||
|
||||
startTimerForHandlingDirectoryChanges();
|
||||
}
|
||||
|
||||
function startTimerForHandlingDirectoryChanges() {
|
||||
if (!sys.setTimeout || !sys.clearTimeout) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (timerHandleForDirectoryChanges) {
|
||||
sys.clearTimeout(timerHandleForDirectoryChanges);
|
||||
}
|
||||
timerHandleForDirectoryChanges = sys.setTimeout(directoryChangeHandler, 250);
|
||||
}
|
||||
|
||||
function directoryChangeHandler() {
|
||||
const parsedCommandLine = parseConfigFile();
|
||||
const newFileNames = ts.map(parsedCommandLine.fileNames, compilerHost.getCanonicalFileName);
|
||||
const canonicalRootFileNames = ts.map(rootFileNames, compilerHost.getCanonicalFileName);
|
||||
|
||||
// We check if the project file list has changed. If so, we just throw away the old program and start fresh.
|
||||
if (!arrayIsEqualTo(newFileNames && newFileNames.sort(), canonicalRootFileNames && canonicalRootFileNames.sort())) {
|
||||
setCachedProgram(undefined);
|
||||
startTimerForRecompilation();
|
||||
else {
|
||||
performCompilation(configParseResult.fileNames, configParseResult.options);
|
||||
}
|
||||
}
|
||||
|
||||
// Upon detecting a file change, wait for 250ms and then perform a recompilation. This gives batch
|
||||
// operations (such as saving all modified files in an editor) a chance to complete before we kick
|
||||
// off a new compilation.
|
||||
function startTimerForRecompilation() {
|
||||
if (!sys.setTimeout || !sys.clearTimeout) {
|
||||
return;
|
||||
else {
|
||||
udpateReportDiagnostic(commandLineOptions);
|
||||
if (isWatchSet(commandLineOptions)) {
|
||||
reportWatchModeWithoutSysSupport();
|
||||
createWatchModeWithoutConfigFile(commandLine.fileNames, commandLineOptions, createWatchingSystemHost());
|
||||
}
|
||||
|
||||
if (timerHandleForRecompilation) {
|
||||
sys.clearTimeout(timerHandleForRecompilation);
|
||||
else {
|
||||
performCompilation(commandLine.fileNames, commandLineOptions);
|
||||
}
|
||||
timerHandleForRecompilation = sys.setTimeout(recompile, 250);
|
||||
}
|
||||
|
||||
function recompile() {
|
||||
timerHandleForRecompilation = undefined;
|
||||
reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation));
|
||||
performCompilation();
|
||||
}
|
||||
}
|
||||
|
||||
function compile(fileNames: string[], compilerOptions: CompilerOptions, compilerHost: CompilerHost) {
|
||||
const hasDiagnostics = compilerOptions.diagnostics || compilerOptions.extendedDiagnostics;
|
||||
let statistics: Statistic[];
|
||||
if (hasDiagnostics) {
|
||||
function reportWatchModeWithoutSysSupport() {
|
||||
if (!sys.watchFile || !sys.watchDirectory) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch"));
|
||||
sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
}
|
||||
}
|
||||
|
||||
function performCompilation(rootFileNames: string[], compilerOptions: CompilerOptions) {
|
||||
const compilerHost = createCompilerHost(compilerOptions);
|
||||
enableStatistics(compilerOptions);
|
||||
|
||||
const program = createProgram(rootFileNames, compilerOptions, compilerHost);
|
||||
const exitStatus = compileProgram(program);
|
||||
|
||||
reportStatistics(program);
|
||||
return sys.exit(exitStatus);
|
||||
}
|
||||
|
||||
function createWatchingSystemHost(reportWatchDiagnostic?: DiagnosticReporter) {
|
||||
const watchingHost = ts.createWatchingSystemHost(/*pretty*/ undefined, sys, parseConfigFile, reportDiagnostic, reportWatchDiagnostic);
|
||||
watchingHost.beforeCompile = enableStatistics;
|
||||
const afterCompile = watchingHost.afterCompile;
|
||||
watchingHost.afterCompile = (host, program, builder) => {
|
||||
afterCompile(host, program, builder);
|
||||
reportStatistics(program);
|
||||
};
|
||||
return watchingHost;
|
||||
}
|
||||
|
||||
function compileProgram(program: Program): ExitStatus {
|
||||
let diagnostics: Diagnostic[];
|
||||
|
||||
// First get and report any syntactic errors.
|
||||
diagnostics = program.getSyntacticDiagnostics().slice();
|
||||
|
||||
// If we didn't have any syntactic errors, then also try getting the global and
|
||||
// semantic errors.
|
||||
if (diagnostics.length === 0) {
|
||||
diagnostics = program.getOptionsDiagnostics().concat(program.getGlobalDiagnostics());
|
||||
|
||||
if (diagnostics.length === 0) {
|
||||
diagnostics = program.getSemanticDiagnostics().slice();
|
||||
}
|
||||
}
|
||||
|
||||
// Emit and report any errors we ran into.
|
||||
const { emittedFiles, emitSkipped, diagnostics: emitDiagnostics } = program.emit();
|
||||
addRange(diagnostics, emitDiagnostics);
|
||||
|
||||
return handleEmitOutputAndReportErrors(sys, program, emittedFiles, emitSkipped, diagnostics, reportDiagnostic);
|
||||
}
|
||||
|
||||
function enableStatistics(compilerOptions: CompilerOptions) {
|
||||
if (compilerOptions.diagnostics || compilerOptions.extendedDiagnostics) {
|
||||
performance.enable();
|
||||
}
|
||||
}
|
||||
|
||||
function reportStatistics(program: Program) {
|
||||
let statistics: Statistic[];
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
if (compilerOptions.diagnostics || compilerOptions.extendedDiagnostics) {
|
||||
statistics = [];
|
||||
}
|
||||
|
||||
const program = createProgram(fileNames, compilerOptions, compilerHost);
|
||||
const exitStatus = compileProgram();
|
||||
|
||||
if (compilerOptions.listFiles) {
|
||||
forEach(program.getSourceFiles(), file => {
|
||||
sys.write(file.fileName + sys.newLine);
|
||||
});
|
||||
}
|
||||
|
||||
if (hasDiagnostics) {
|
||||
const memoryUsed = sys.getMemoryUsage ? sys.getMemoryUsage() : -1;
|
||||
reportCountStatistic("Files", program.getSourceFiles().length);
|
||||
reportCountStatistic("Lines", countLines(program));
|
||||
@@ -462,44 +245,6 @@ namespace ts {
|
||||
performance.disable();
|
||||
}
|
||||
|
||||
return { program, exitStatus };
|
||||
|
||||
function compileProgram(): ExitStatus {
|
||||
let diagnostics: Diagnostic[];
|
||||
|
||||
// First get and report any syntactic errors.
|
||||
diagnostics = program.getSyntacticDiagnostics().slice();
|
||||
|
||||
// If we didn't have any syntactic errors, then also try getting the global and
|
||||
// semantic errors.
|
||||
if (diagnostics.length === 0) {
|
||||
diagnostics = program.getOptionsDiagnostics().concat(program.getGlobalDiagnostics());
|
||||
|
||||
if (diagnostics.length === 0) {
|
||||
diagnostics = program.getSemanticDiagnostics().slice();
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, emit and report any errors we ran into.
|
||||
const emitOutput = program.emit();
|
||||
addRange(diagnostics, emitOutput.diagnostics);
|
||||
|
||||
reportDiagnostics(sortAndDeduplicateDiagnostics(diagnostics), compilerHost);
|
||||
|
||||
reportEmittedFiles(emitOutput.emittedFiles);
|
||||
|
||||
if (emitOutput.emitSkipped && diagnostics.length > 0) {
|
||||
// If the emitter didn't emit anything, then pass that value along.
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
else if (diagnostics.length > 0) {
|
||||
// The emitter emitted something, inform the caller if that happened in the presence
|
||||
// of diagnostics or not.
|
||||
return ExitStatus.DiagnosticsPresent_OutputsGenerated;
|
||||
}
|
||||
return ExitStatus.Success;
|
||||
}
|
||||
|
||||
function reportStatistics() {
|
||||
let nameSize = 0;
|
||||
let valueSize = 0;
|
||||
@@ -653,19 +398,17 @@ namespace ts {
|
||||
const currentDirectory = sys.getCurrentDirectory();
|
||||
const file = normalizePath(combinePaths(currentDirectory, "tsconfig.json"));
|
||||
if (sys.fileExists(file)) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.A_tsconfig_json_file_is_already_defined_at_Colon_0, file), /* host */ undefined);
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.A_tsconfig_json_file_is_already_defined_at_Colon_0, file));
|
||||
}
|
||||
else {
|
||||
sys.writeFile(file, generateTSConfig(options, fileNames, sys.newLine));
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Successfully_created_a_tsconfig_json_file), /* host */ undefined);
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Successfully_created_a_tsconfig_json_file));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ts.setStackTraceLimit();
|
||||
|
||||
if (ts.Debug.isDebugging) {
|
||||
ts.Debug.enableDebugInfo();
|
||||
}
|
||||
@@ -673,5 +416,4 @@ if (ts.Debug.isDebugging) {
|
||||
if (ts.sys.tryEnableSourceMapsForHost && /^development$/i.test(ts.sys.getEnvironmentVariable("NODE_ENV"))) {
|
||||
ts.sys.tryEnableSourceMapsForHost();
|
||||
}
|
||||
|
||||
ts.executeCommandLine(ts.sys.args);
|
||||
|
||||
@@ -36,7 +36,11 @@
|
||||
"sourcemap.ts",
|
||||
"declarationEmitter.ts",
|
||||
"emitter.ts",
|
||||
"watchUtilities.ts",
|
||||
"program.ts",
|
||||
"builder.ts",
|
||||
"resolutionCache.ts",
|
||||
"watch.ts",
|
||||
"commandLineParser.ts",
|
||||
"tsc.ts",
|
||||
"diagnosticInformationMap.generated.ts"
|
||||
|
||||
+85
-40
@@ -363,8 +363,7 @@ namespace ts {
|
||||
JSDocVariadicType,
|
||||
JSDocComment,
|
||||
JSDocTag,
|
||||
JSDocAugmentsOrExtendsTag,
|
||||
JSDocExtendsTag,
|
||||
JSDocAugmentsTag,
|
||||
JSDocClassTag,
|
||||
JSDocParameterTag,
|
||||
JSDocReturnTag,
|
||||
@@ -2162,11 +2161,11 @@ namespace ts {
|
||||
|
||||
/**
|
||||
* Note that `@extends` is a synonym of `@augments`.
|
||||
* Both are covered by this interface.
|
||||
* Both tags are represented by this interface.
|
||||
*/
|
||||
export interface JSDocAugmentsOrExtendsTag extends JSDocTag {
|
||||
kind: SyntaxKind.JSDocAugmentsOrExtendsTag;
|
||||
typeExpression: JSDocTypeExpression;
|
||||
export interface JSDocAugmentsTag extends JSDocTag {
|
||||
kind: SyntaxKind.JSDocAugmentsTag;
|
||||
class: ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression };
|
||||
}
|
||||
|
||||
export interface JSDocClassTag extends JSDocTag {
|
||||
@@ -2413,6 +2412,7 @@ namespace ts {
|
||||
/* @internal */ patternAmbientModules?: PatternAmbientModule[];
|
||||
/* @internal */ ambientModuleNames: ReadonlyArray<string>;
|
||||
/* @internal */ checkJsDirective: CheckJsDirective | undefined;
|
||||
/* @internal */ version: string;
|
||||
}
|
||||
|
||||
export interface Bundle extends Node {
|
||||
@@ -2447,7 +2447,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export interface WriteFileCallback {
|
||||
(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void, sourceFiles?: ReadonlyArray<SourceFile>): void;
|
||||
(fileName: string, data: string, writeByteOrderMark: boolean, onError: ((message: string) => void) | undefined, sourceFiles: ReadonlyArray<SourceFile>): void;
|
||||
}
|
||||
|
||||
export class OperationCanceledException { }
|
||||
@@ -2529,6 +2529,8 @@ namespace ts {
|
||||
/* @internal */ sourceFileToPackageName: Map<string>;
|
||||
/** Set of all source files that some other source file redirects to. */
|
||||
/* @internal */ redirectTargetsSet: Map<true>;
|
||||
/** Returns true when file in the program had invalidated resolution at the time of program creation. */
|
||||
/* @internal */ hasInvalidatedResolution: HasInvalidatedResolution;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -2657,10 +2659,10 @@ namespace ts {
|
||||
getRootSymbols(symbol: Symbol): Symbol[];
|
||||
getContextualType(node: Expression): Type | undefined;
|
||||
/**
|
||||
* returns unknownSignature in the case of an error. Don't know when it returns undefined.
|
||||
* returns unknownSignature in the case of an error.
|
||||
* @param argumentCount Apparent number of arguments, passed in case of a possibly incomplete call. This should come from an ArgumentListInfo. See `signatureHelp.ts`.
|
||||
*/
|
||||
getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[], argumentCount?: number): Signature | undefined;
|
||||
getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[], argumentCount?: number): Signature;
|
||||
getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature | undefined;
|
||||
isImplementationOfOverload(node: FunctionLike): boolean | undefined;
|
||||
isUndefinedSymbol(symbol: Symbol): boolean;
|
||||
@@ -3220,6 +3222,7 @@ namespace ts {
|
||||
NonPrimitive = 1 << 24, // intrinsic object type
|
||||
/* @internal */
|
||||
JsxAttributes = 1 << 25, // Jsx attributes type
|
||||
MarkerType = 1 << 26, // Marker type used for variance probing
|
||||
|
||||
/* @internal */
|
||||
Nullable = Undefined | Null,
|
||||
@@ -3348,10 +3351,21 @@ namespace ts {
|
||||
typeArguments?: Type[]; // Type reference type arguments (undefined if none)
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export const enum Variance {
|
||||
Invariant = 0, // Neither covariant nor contravariant
|
||||
Covariant = 1, // Covariant
|
||||
Contravariant = 2, // Contravariant
|
||||
Bivariant = 3, // Both covariant and contravariant
|
||||
Independent = 4, // Unwitnessed type parameter
|
||||
}
|
||||
|
||||
// Generic class and interface types
|
||||
export interface GenericType extends InterfaceType, TypeReference {
|
||||
/* @internal */
|
||||
instantiations: Map<TypeReference>; // Generic instantiation cache
|
||||
instantiations: Map<TypeReference>; // Generic instantiation cache
|
||||
/* @internal */
|
||||
variances?: Variance[]; // Variance of each type parameter
|
||||
}
|
||||
|
||||
export interface UnionOrIntersectionType extends Type {
|
||||
@@ -3527,9 +3541,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
export const enum InferencePriority {
|
||||
NakedTypeVariable = 1 << 0, // Naked type variable in union or intersection type
|
||||
MappedType = 1 << 1, // Reverse inference for mapped type
|
||||
ReturnType = 1 << 2, // Inference made from return type of generic function
|
||||
Contravariant = 1 << 0, // Inference from contravariant position
|
||||
NakedTypeVariable = 1 << 1, // Naked type variable in union or intersection type
|
||||
MappedType = 1 << 2, // Reverse inference for mapped type
|
||||
ReturnType = 1 << 3, // Inference made from return type of generic function
|
||||
}
|
||||
|
||||
export interface InferenceInfo {
|
||||
@@ -3651,6 +3666,7 @@ namespace ts {
|
||||
charset?: string;
|
||||
checkJs?: boolean;
|
||||
/* @internal */ configFilePath?: string;
|
||||
/** configFile is set as non enumerable property so as to avoid checking of json source files */
|
||||
/* @internal */ readonly configFile?: JsonSourceFile;
|
||||
declaration?: boolean;
|
||||
declarationDir?: string;
|
||||
@@ -3712,6 +3728,7 @@ namespace ts {
|
||||
sourceMap?: boolean;
|
||||
sourceRoot?: string;
|
||||
strict?: boolean;
|
||||
strictFunctionTypes?: boolean; // Always combine with strict property
|
||||
strictNullChecks?: boolean; // Always combine with strict property
|
||||
/* @internal */ stripInternal?: boolean;
|
||||
suppressExcessPropertyErrors?: boolean;
|
||||
@@ -3819,6 +3836,7 @@ namespace ts {
|
||||
errors: Diagnostic[];
|
||||
wildcardDirectories?: MapLike<WatchDirectoryFlags>;
|
||||
compileOnSave?: boolean;
|
||||
/* @internal */ configFileSpecs?: ConfigFileSpecs;
|
||||
}
|
||||
|
||||
export const enum WatchDirectoryFlags {
|
||||
@@ -3826,9 +3844,26 @@ namespace ts {
|
||||
Recursive = 1 << 0,
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface ConfigFileSpecs {
|
||||
filesSpecs: ReadonlyArray<string>;
|
||||
/**
|
||||
* Present to report errors (user specified specs), validatedIncludeSpecs are used for file name matching
|
||||
*/
|
||||
includeSpecs: ReadonlyArray<string>;
|
||||
/**
|
||||
* Present to report errors (user specified specs), validatedExcludeSpecs are used for file name matching
|
||||
*/
|
||||
excludeSpecs: ReadonlyArray<string>;
|
||||
validatedIncludeSpecs: ReadonlyArray<string>;
|
||||
validatedExcludeSpecs: ReadonlyArray<string>;
|
||||
wildcardDirectories: MapLike<WatchDirectoryFlags>;
|
||||
}
|
||||
|
||||
export interface ExpandResult {
|
||||
fileNames: string[];
|
||||
wildcardDirectories: MapLike<WatchDirectoryFlags>;
|
||||
/* @internal */ spec: ConfigFileSpecs;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -4077,31 +4112,37 @@ namespace ts {
|
||||
Tsx = ".tsx",
|
||||
Dts = ".d.ts",
|
||||
Js = ".js",
|
||||
Jsx = ".jsx"
|
||||
Jsx = ".jsx",
|
||||
Json = ".json"
|
||||
}
|
||||
|
||||
export interface ResolvedModuleWithFailedLookupLocations {
|
||||
resolvedModule: ResolvedModuleFull | undefined;
|
||||
readonly resolvedModule: ResolvedModuleFull | undefined;
|
||||
/* @internal */
|
||||
failedLookupLocations: string[];
|
||||
readonly failedLookupLocations: ReadonlyArray<string>;
|
||||
}
|
||||
|
||||
export interface ResolvedTypeReferenceDirective {
|
||||
// True if the type declaration file was found in a primary lookup location
|
||||
primary: boolean;
|
||||
// The location of the .d.ts file we located, or undefined if resolution failed
|
||||
resolvedFileName?: string;
|
||||
resolvedFileName: string | undefined;
|
||||
packageId?: PackageId;
|
||||
}
|
||||
|
||||
export interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
|
||||
resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective;
|
||||
failedLookupLocations: string[];
|
||||
readonly resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective;
|
||||
readonly failedLookupLocations: ReadonlyArray<string>;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface HasInvalidatedResolution {
|
||||
(sourceFile: Path): boolean;
|
||||
}
|
||||
|
||||
export interface CompilerHost extends ModuleResolutionHost {
|
||||
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile | undefined;
|
||||
getSourceFileByPath?(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile | undefined;
|
||||
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined;
|
||||
getSourceFileByPath?(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined;
|
||||
getCancellationToken?(): CancellationToken;
|
||||
getDefaultLibFileName(options: CompilerOptions): string;
|
||||
getDefaultLibLocation?(): string;
|
||||
@@ -4119,12 +4160,15 @@ namespace ts {
|
||||
* If resolveModuleNames is implemented then implementation for members from ModuleResolutionHost can be just
|
||||
* 'throw new Error("NotImplemented")'
|
||||
*/
|
||||
resolveModuleNames?(moduleNames: string[], containingFile: string): ResolvedModule[];
|
||||
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[];
|
||||
/**
|
||||
* This method is a companion for 'resolveModuleNames' and is used to resolve 'types' references to actual type declaration files
|
||||
*/
|
||||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
getEnvironmentVariable?(name: string): string;
|
||||
/* @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions): void;
|
||||
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
|
||||
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -4276,22 +4320,25 @@ namespace ts {
|
||||
*/
|
||||
/* @internal */
|
||||
export const enum ExternalEmitHelpers {
|
||||
Extends = 1 << 0, // __extends (used by the ES2015 class transformation)
|
||||
Assign = 1 << 1, // __assign (used by Jsx and ESNext object spread transformations)
|
||||
Rest = 1 << 2, // __rest (used by ESNext object rest transformation)
|
||||
Decorate = 1 << 3, // __decorate (used by TypeScript decorators transformation)
|
||||
Metadata = 1 << 4, // __metadata (used by TypeScript decorators transformation)
|
||||
Param = 1 << 5, // __param (used by TypeScript decorators transformation)
|
||||
Awaiter = 1 << 6, // __awaiter (used by ES2017 async functions transformation)
|
||||
Generator = 1 << 7, // __generator (used by ES2015 generator transformation)
|
||||
Values = 1 << 8, // __values (used by ES2015 for..of and yield* transformations)
|
||||
Read = 1 << 9, // __read (used by ES2015 iterator destructuring transformation)
|
||||
Spread = 1 << 10, // __spread (used by ES2015 array spread and argument list spread transformations)
|
||||
Await = 1 << 11, // __await (used by ES2017 async generator transformation)
|
||||
AsyncGenerator = 1 << 12, // __asyncGenerator (used by ES2017 async generator transformation)
|
||||
AsyncDelegator = 1 << 13, // __asyncDelegator (used by ES2017 async generator yield* transformation)
|
||||
AsyncValues = 1 << 14, // __asyncValues (used by ES2017 for..await..of transformation)
|
||||
ExportStar = 1 << 15, // __exportStar (used by CommonJS/AMD/UMD module transformation)
|
||||
Extends = 1 << 0, // __extends (used by the ES2015 class transformation)
|
||||
Assign = 1 << 1, // __assign (used by Jsx and ESNext object spread transformations)
|
||||
Rest = 1 << 2, // __rest (used by ESNext object rest transformation)
|
||||
Decorate = 1 << 3, // __decorate (used by TypeScript decorators transformation)
|
||||
Metadata = 1 << 4, // __metadata (used by TypeScript decorators transformation)
|
||||
Param = 1 << 5, // __param (used by TypeScript decorators transformation)
|
||||
Awaiter = 1 << 6, // __awaiter (used by ES2017 async functions transformation)
|
||||
Generator = 1 << 7, // __generator (used by ES2015 generator transformation)
|
||||
Values = 1 << 8, // __values (used by ES2015 for..of and yield* transformations)
|
||||
Read = 1 << 9, // __read (used by ES2015 iterator destructuring transformation)
|
||||
Spread = 1 << 10, // __spread (used by ES2015 array spread and argument list spread transformations)
|
||||
Await = 1 << 11, // __await (used by ES2017 async generator transformation)
|
||||
AsyncGenerator = 1 << 12, // __asyncGenerator (used by ES2017 async generator transformation)
|
||||
AsyncDelegator = 1 << 13, // __asyncDelegator (used by ES2017 async generator yield* transformation)
|
||||
AsyncValues = 1 << 14, // __asyncValues (used by ES2017 for..await..of transformation)
|
||||
ExportStar = 1 << 15, // __exportStar (used by CommonJS/AMD/UMD module transformation)
|
||||
MakeTemplateObject = 1 << 16, // __makeTemplateObject (used for constructing template string array objects)
|
||||
FirstEmitHelper = Extends,
|
||||
LastEmitHelper = MakeTemplateObject,
|
||||
|
||||
// Helpers included by ES2015 for..of
|
||||
ForOfIncludes = Values,
|
||||
@@ -4308,8 +4355,6 @@ namespace ts {
|
||||
// Helpers included by ES2015 spread
|
||||
SpreadIncludes = Read | Spread,
|
||||
|
||||
FirstEmitHelper = Extends,
|
||||
LastEmitHelper = ExportStar
|
||||
}
|
||||
|
||||
export const enum EmitHint {
|
||||
|
||||
+119
-23
@@ -377,7 +377,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function getTextOfConstantValue(value: string | number) {
|
||||
return typeof value === "string" ? '"' + escapeNonAsciiString(value) + '"' : "" + value;
|
||||
return isString(value) ? '"' + escapeNonAsciiString(value) + '"' : "" + value;
|
||||
}
|
||||
|
||||
// Add an extra underscore to identifiers that start with two underscores to avoid issues with magic names like '__proto__'
|
||||
@@ -414,7 +414,10 @@ namespace ts {
|
||||
((<ModuleDeclaration>node).name.kind === SyntaxKind.StringLiteral || isGlobalScopeAugmentation(<ModuleDeclaration>node));
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function isModuleWithStringLiteralName(node: Node): node is ModuleDeclaration {
|
||||
return isModuleDeclaration(node) && node.name.kind === SyntaxKind.StringLiteral;
|
||||
}
|
||||
|
||||
export function isNonGlobalAmbientModule(node: Node): node is ModuleDeclaration & { name: StringLiteral } {
|
||||
return isModuleDeclaration(node) && isStringLiteral(node.name);
|
||||
}
|
||||
@@ -560,7 +563,7 @@ namespace ts {
|
||||
export function entityNameToString(name: EntityNameOrEntityNameExpression): string {
|
||||
switch (name.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
return getFullWidth(name) === 0 ? unescapeLeadingUnderscores(name.escapedText) : getTextOfNode(name);
|
||||
return getFullWidth(name) === 0 ? idText(name) : getTextOfNode(name);
|
||||
case SyntaxKind.QualifiedName:
|
||||
return entityNameToString(name.left) + "." + entityNameToString(name.right);
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
@@ -1401,11 +1404,10 @@ namespace ts {
|
||||
|
||||
/// Given a BinaryExpression, returns SpecialPropertyAssignmentKind for the various kinds of property
|
||||
/// assignments we treat as special in the binder
|
||||
export function getSpecialPropertyAssignmentKind(expression: ts.BinaryExpression): SpecialPropertyAssignmentKind {
|
||||
if (!isInJavaScriptFile(expression)) {
|
||||
export function getSpecialPropertyAssignmentKind(expr: ts.BinaryExpression): SpecialPropertyAssignmentKind {
|
||||
if (!isInJavaScriptFile(expr)) {
|
||||
return SpecialPropertyAssignmentKind.None;
|
||||
}
|
||||
const expr = <BinaryExpression>expression;
|
||||
if (expr.operatorToken.kind !== SyntaxKind.EqualsToken || expr.left.kind !== SyntaxKind.PropertyAccessExpression) {
|
||||
return SpecialPropertyAssignmentKind.None;
|
||||
}
|
||||
@@ -1460,8 +1462,8 @@ namespace ts {
|
||||
if (node.kind === SyntaxKind.ExportDeclaration) {
|
||||
return (<ExportDeclaration>node).moduleSpecifier;
|
||||
}
|
||||
if (node.kind === SyntaxKind.ModuleDeclaration && (<ModuleDeclaration>node).name.kind === SyntaxKind.StringLiteral) {
|
||||
return (<ModuleDeclaration>node).name;
|
||||
if (isModuleWithStringLiteralName(node)) {
|
||||
return node.name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1514,7 +1516,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function getJSDocCommentsAndTags(node: Node): (JSDoc | JSDocTag)[] {
|
||||
let result: Array<JSDoc | JSDocTag> | undefined;
|
||||
let result: (JSDoc | JSDocTag)[] | undefined;
|
||||
getJSDocCommentsAndTagsWorker(node);
|
||||
return result || emptyArray;
|
||||
|
||||
@@ -1581,8 +1583,7 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
const name = node.name.escapedText;
|
||||
Debug.assert(node.parent!.kind === SyntaxKind.JSDocComment);
|
||||
const func = node.parent!.parent!;
|
||||
const func = getJSDocHost(node);
|
||||
if (!isFunctionLike(func)) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -1591,6 +1592,11 @@ namespace ts {
|
||||
return parameter && parameter.symbol;
|
||||
}
|
||||
|
||||
export function getJSDocHost(node: JSDocTag): HasJSDoc {
|
||||
Debug.assert(node.parent!.kind === SyntaxKind.JSDocComment);
|
||||
return node.parent!.parent!;
|
||||
}
|
||||
|
||||
export function getTypeParameterFromJsDoc(node: TypeParameterDeclaration & { parent: JSDocTemplateTag }): TypeParameterDeclaration | undefined {
|
||||
const name = node.name.escapedText;
|
||||
const { typeParameters } = (node.parent.parent.parent as ts.SignatureDeclaration | ts.InterfaceDeclaration | ts.ClassDeclaration);
|
||||
@@ -1973,8 +1979,7 @@ namespace ts {
|
||||
if (name.kind === SyntaxKind.ComputedPropertyName) {
|
||||
const nameExpression = name.expression;
|
||||
if (isWellKnownSymbolSyntactically(nameExpression)) {
|
||||
const rightHandSideName = (<PropertyAccessExpression>nameExpression).name.escapedText;
|
||||
return getPropertyNameForKnownSymbolName(unescapeLeadingUnderscores(rightHandSideName));
|
||||
return getPropertyNameForKnownSymbolName(idText((<PropertyAccessExpression>nameExpression).name));
|
||||
}
|
||||
else if (nameExpression.kind === SyntaxKind.StringLiteral || nameExpression.kind === SyntaxKind.NumericLiteral) {
|
||||
return escapeLeadingUnderscores((<LiteralExpression>nameExpression).text);
|
||||
@@ -1987,7 +1992,7 @@ namespace ts {
|
||||
export function getTextOfIdentifierOrLiteral(node: Identifier | LiteralLikeNode) {
|
||||
if (node) {
|
||||
if (node.kind === SyntaxKind.Identifier) {
|
||||
return unescapeLeadingUnderscores((node as Identifier).escapedText);
|
||||
return idText(node as Identifier);
|
||||
}
|
||||
if (node.kind === SyntaxKind.StringLiteral ||
|
||||
node.kind === SyntaxKind.NumericLiteral) {
|
||||
@@ -3193,17 +3198,14 @@ namespace ts {
|
||||
|
||||
const carriageReturnLineFeed = "\r\n";
|
||||
const lineFeed = "\n";
|
||||
export function getNewLineCharacter(options: CompilerOptions | PrinterOptions): string {
|
||||
export function getNewLineCharacter(options: CompilerOptions | PrinterOptions, system?: System): string {
|
||||
switch (options.newLine) {
|
||||
case NewLineKind.CarriageReturnLineFeed:
|
||||
return carriageReturnLineFeed;
|
||||
case NewLineKind.LineFeed:
|
||||
return lineFeed;
|
||||
}
|
||||
if (sys) {
|
||||
return sys.newLine;
|
||||
}
|
||||
return carriageReturnLineFeed;
|
||||
return system ? system.newLine : sys ? sys.newLine : carriageReturnLineFeed;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3497,6 +3499,93 @@ namespace ts {
|
||||
return parent.parent && parent.parent.kind === SyntaxKind.ExpressionStatement ? AccessKind.Write : AccessKind.ReadWrite;
|
||||
}
|
||||
}
|
||||
|
||||
export function compareDataObjects(dst: any, src: any): boolean {
|
||||
if (!dst || !src || Object.keys(dst).length !== Object.keys(src).length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const e in dst) {
|
||||
if (typeof dst[e] === "object") {
|
||||
if (!compareDataObjects(dst[e], src[e])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (typeof dst[e] !== "function") {
|
||||
if (dst[e] !== src[e]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* clears already present map by calling onDeleteExistingValue callback before deleting that key/value
|
||||
*/
|
||||
export function clearMap<T>(map: Map<T>, onDeleteValue: (valueInMap: T, key: string) => void) {
|
||||
// Remove all
|
||||
map.forEach(onDeleteValue);
|
||||
map.clear();
|
||||
}
|
||||
|
||||
export interface MutateMapOptions<T, U> {
|
||||
createNewValue(key: string, valueInNewMap: U): T;
|
||||
onDeleteValue(existingValue: T, key: string): void;
|
||||
|
||||
/**
|
||||
* If present this is called with the key when there is value for that key both in new map as well as existing map provided
|
||||
* Caller can then decide to update or remove this key.
|
||||
* If the key is removed, caller will get callback of createNewValue for that key.
|
||||
* If this callback is not provided, the value of such keys is not updated.
|
||||
*/
|
||||
onExistingValue?(existingValue: T, valueInNewMap: U, key: string): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutates the map with newMap such that keys in map will be same as newMap.
|
||||
*/
|
||||
export function mutateMap<T, U>(map: Map<T>, newMap: ReadonlyMap<U>, options: MutateMapOptions<T, U>) {
|
||||
const { createNewValue, onDeleteValue, onExistingValue } = options;
|
||||
// Needs update
|
||||
map.forEach((existingValue, key) => {
|
||||
const valueInNewMap = newMap.get(key);
|
||||
// Not present any more in new map, remove it
|
||||
if (valueInNewMap === undefined) {
|
||||
map.delete(key);
|
||||
onDeleteValue(existingValue, key);
|
||||
}
|
||||
// If present notify about existing values
|
||||
else if (onExistingValue) {
|
||||
onExistingValue(existingValue, valueInNewMap, key);
|
||||
}
|
||||
});
|
||||
|
||||
// Add new values that are not already present
|
||||
newMap.forEach((valueInNewMap, key) => {
|
||||
if (!map.has(key)) {
|
||||
// New values
|
||||
map.set(key, createNewValue(key, valueInNewMap));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Calls `callback` on `directory` and every ancestor directory it has, returning the first defined result. */
|
||||
export function forEachAncestorDirectory<T>(directory: string, callback: (directory: string) => T): T {
|
||||
while (true) {
|
||||
const result = callback(directory);
|
||||
if (result !== undefined) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const parentPath = getDirectoryPath(directory);
|
||||
if (parentPath === directory) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
directory = parentPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace ts {
|
||||
@@ -3943,6 +4032,13 @@ namespace ts {
|
||||
return id.length >= 3 && id.charCodeAt(0) === CharacterCodes._ && id.charCodeAt(1) === CharacterCodes._ && id.charCodeAt(2) === CharacterCodes._ ? id.substr(1) : id;
|
||||
}
|
||||
|
||||
export function idText(identifier: Identifier): string {
|
||||
return unescapeLeadingUnderscores(identifier.escapedText);
|
||||
}
|
||||
export function symbolName(symbol: Symbol): string {
|
||||
return unescapeLeadingUnderscores(symbol.escapedName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove extra underscore from escaped identifier text content.
|
||||
* @deprecated Use `id.text` for the unescaped text.
|
||||
@@ -4072,8 +4168,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** Gets the JSDoc augments tag for the node if present */
|
||||
export function getJSDocAugmentsOrExtendsTag(node: Node): JSDocAugmentsOrExtendsTag | undefined {
|
||||
return getFirstJSDocTag(node, SyntaxKind.JSDocAugmentsOrExtendsTag) as JSDocAugmentsOrExtendsTag;
|
||||
export function getJSDocAugmentsTag(node: Node): JSDocAugmentsTag | undefined {
|
||||
return getFirstJSDocTag(node, SyntaxKind.JSDocAugmentsTag) as JSDocAugmentsTag;
|
||||
}
|
||||
|
||||
/** Gets the JSDoc class tag for the node if present */
|
||||
@@ -4765,8 +4861,8 @@ namespace ts {
|
||||
return node.kind === SyntaxKind.JSDocComment;
|
||||
}
|
||||
|
||||
export function isJSDocAugmentsOrExtendsTag(node: Node): node is JSDocAugmentsOrExtendsTag {
|
||||
return node.kind === SyntaxKind.JSDocAugmentsOrExtendsTag;
|
||||
export function isJSDocAugmentsTag(node: Node): node is JSDocAugmentsTag {
|
||||
return node.kind === SyntaxKind.JSDocAugmentsTag;
|
||||
}
|
||||
|
||||
export function isJSDocParameterTag(node: Node): node is JSDocParameterTag {
|
||||
|
||||
@@ -0,0 +1,638 @@
|
||||
/// <reference path="program.ts" />
|
||||
/// <reference path="builder.ts" />
|
||||
/// <reference path="resolutionCache.ts"/>
|
||||
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export type DiagnosticReporter = (diagnostic: Diagnostic) => void;
|
||||
export type ParseConfigFile = (configFileName: string, optionsToExtend: CompilerOptions, system: DirectoryStructureHost, reportDiagnostic: DiagnosticReporter, reportWatchDiagnostic: DiagnosticReporter) => ParsedCommandLine;
|
||||
export interface WatchingSystemHost {
|
||||
// FS system to use
|
||||
system: System;
|
||||
|
||||
// parse config file
|
||||
parseConfigFile: ParseConfigFile;
|
||||
|
||||
// Reporting errors
|
||||
reportDiagnostic: DiagnosticReporter;
|
||||
reportWatchDiagnostic: DiagnosticReporter;
|
||||
|
||||
// Callbacks to do custom action before creating program and after creating program
|
||||
beforeCompile(compilerOptions: CompilerOptions): void;
|
||||
afterCompile(host: DirectoryStructureHost, program: Program, builder: Builder): void;
|
||||
}
|
||||
|
||||
const defaultFormatDiagnosticsHost: FormatDiagnosticsHost = sys ? {
|
||||
getCurrentDirectory: () => sys.getCurrentDirectory(),
|
||||
getNewLine: () => sys.newLine,
|
||||
getCanonicalFileName: createGetCanonicalFileName(sys.useCaseSensitiveFileNames)
|
||||
} : undefined;
|
||||
|
||||
export function createDiagnosticReporter(system = sys, worker = reportDiagnosticSimply, formatDiagnosticsHost?: FormatDiagnosticsHost): DiagnosticReporter {
|
||||
return diagnostic => worker(diagnostic, getFormatDiagnosticsHost(), system);
|
||||
|
||||
function getFormatDiagnosticsHost() {
|
||||
return formatDiagnosticsHost || (formatDiagnosticsHost = system === sys ? defaultFormatDiagnosticsHost : {
|
||||
getCurrentDirectory: () => system.getCurrentDirectory(),
|
||||
getNewLine: () => system.newLine,
|
||||
getCanonicalFileName: createGetCanonicalFileName(system.useCaseSensitiveFileNames),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function createWatchDiagnosticReporter(system = sys): DiagnosticReporter {
|
||||
return diagnostic => {
|
||||
let output = new Date().toLocaleTimeString() + " - ";
|
||||
output += `${flattenDiagnosticMessageText(diagnostic.messageText, system.newLine)}${system.newLine + system.newLine + system.newLine}`;
|
||||
system.write(output);
|
||||
};
|
||||
}
|
||||
|
||||
export function reportDiagnostics(diagnostics: Diagnostic[], reportDiagnostic: DiagnosticReporter): void {
|
||||
for (const diagnostic of diagnostics) {
|
||||
reportDiagnostic(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
export function reportDiagnosticSimply(diagnostic: Diagnostic, host: FormatDiagnosticsHost, system: System): void {
|
||||
system.write(ts.formatDiagnostic(diagnostic, host));
|
||||
}
|
||||
|
||||
export function reportDiagnosticWithColorAndContext(diagnostic: Diagnostic, host: FormatDiagnosticsHost, system: System): void {
|
||||
system.write(ts.formatDiagnosticsWithColorAndContext([diagnostic], host) + host.getNewLine());
|
||||
}
|
||||
|
||||
export function parseConfigFile(configFileName: string, optionsToExtend: CompilerOptions, system: DirectoryStructureHost, reportDiagnostic: DiagnosticReporter, reportWatchDiagnostic: DiagnosticReporter): ParsedCommandLine {
|
||||
let configFileText: string;
|
||||
try {
|
||||
configFileText = system.readFile(configFileName);
|
||||
}
|
||||
catch (e) {
|
||||
const error = createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, configFileName, e.message);
|
||||
reportWatchDiagnostic(error);
|
||||
system.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
return;
|
||||
}
|
||||
if (!configFileText) {
|
||||
const error = createCompilerDiagnostic(Diagnostics.File_0_not_found, configFileName);
|
||||
reportDiagnostics([error], reportDiagnostic);
|
||||
system.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
return;
|
||||
}
|
||||
|
||||
const result = parseJsonText(configFileName, configFileText);
|
||||
reportDiagnostics(result.parseDiagnostics, reportDiagnostic);
|
||||
|
||||
const cwd = system.getCurrentDirectory();
|
||||
const configParseResult = parseJsonSourceFileConfigFileContent(result, system, getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd), optionsToExtend, getNormalizedAbsolutePath(configFileName, cwd));
|
||||
reportDiagnostics(configParseResult.errors, reportDiagnostic);
|
||||
|
||||
return configParseResult;
|
||||
}
|
||||
|
||||
function reportEmittedFiles(files: string[], system: DirectoryStructureHost): void {
|
||||
if (!files || files.length === 0) {
|
||||
return;
|
||||
}
|
||||
const currentDir = system.getCurrentDirectory();
|
||||
for (const file of files) {
|
||||
const filepath = getNormalizedAbsolutePath(file, currentDir);
|
||||
system.write(`TSFILE: ${filepath}${system.newLine}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function handleEmitOutputAndReportErrors(system: DirectoryStructureHost, program: Program,
|
||||
emittedFiles: string[], emitSkipped: boolean,
|
||||
diagnostics: Diagnostic[], reportDiagnostic: DiagnosticReporter
|
||||
): ExitStatus {
|
||||
reportDiagnostics(sortAndDeduplicateDiagnostics(diagnostics), reportDiagnostic);
|
||||
reportEmittedFiles(emittedFiles, system);
|
||||
|
||||
if (program.getCompilerOptions().listFiles) {
|
||||
forEach(program.getSourceFiles(), file => {
|
||||
system.write(file.fileName + system.newLine);
|
||||
});
|
||||
}
|
||||
|
||||
if (emitSkipped && diagnostics.length > 0) {
|
||||
// If the emitter didn't emit anything, then pass that value along.
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
else if (diagnostics.length > 0) {
|
||||
// The emitter emitted something, inform the caller if that happened in the presence
|
||||
// of diagnostics or not.
|
||||
return ExitStatus.DiagnosticsPresent_OutputsGenerated;
|
||||
}
|
||||
return ExitStatus.Success;
|
||||
}
|
||||
|
||||
export function createWatchingSystemHost(pretty?: DiagnosticStyle, system = sys,
|
||||
parseConfigFile?: ParseConfigFile, reportDiagnostic?: DiagnosticReporter,
|
||||
reportWatchDiagnostic?: DiagnosticReporter
|
||||
): WatchingSystemHost {
|
||||
reportDiagnostic = reportDiagnostic || createDiagnosticReporter(system, pretty ? reportDiagnosticWithColorAndContext : reportDiagnosticSimply);
|
||||
reportWatchDiagnostic = reportWatchDiagnostic || createWatchDiagnosticReporter(system);
|
||||
parseConfigFile = parseConfigFile || ts.parseConfigFile;
|
||||
return {
|
||||
system,
|
||||
parseConfigFile,
|
||||
reportDiagnostic,
|
||||
reportWatchDiagnostic,
|
||||
beforeCompile: noop,
|
||||
afterCompile: compileWatchedProgram,
|
||||
};
|
||||
|
||||
function compileWatchedProgram(host: DirectoryStructureHost, program: Program, builder: Builder) {
|
||||
// First get and report any syntactic errors.
|
||||
let diagnostics = program.getSyntacticDiagnostics().slice();
|
||||
let reportSemanticDiagnostics = false;
|
||||
|
||||
// If we didn't have any syntactic errors, then also try getting the global and
|
||||
// semantic errors.
|
||||
if (diagnostics.length === 0) {
|
||||
diagnostics = program.getOptionsDiagnostics().concat(program.getGlobalDiagnostics());
|
||||
|
||||
if (diagnostics.length === 0) {
|
||||
reportSemanticDiagnostics = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Emit and report any errors we ran into.
|
||||
const emittedFiles: string[] = program.getCompilerOptions().listEmittedFiles ? [] : undefined;
|
||||
let sourceMaps: SourceMapData[];
|
||||
let emitSkipped: boolean;
|
||||
|
||||
const result = builder.emitChangedFiles(program);
|
||||
if (result.length === 0) {
|
||||
emitSkipped = true;
|
||||
}
|
||||
else {
|
||||
for (const emitOutput of result) {
|
||||
if (emitOutput.emitSkipped) {
|
||||
emitSkipped = true;
|
||||
}
|
||||
diagnostics = concatenate(diagnostics, emitOutput.diagnostics);
|
||||
sourceMaps = concatenate(sourceMaps, emitOutput.sourceMaps);
|
||||
writeOutputFiles(emitOutput.outputFiles);
|
||||
}
|
||||
}
|
||||
|
||||
if (reportSemanticDiagnostics) {
|
||||
diagnostics = diagnostics.concat(builder.getSemanticDiagnostics(program));
|
||||
}
|
||||
return handleEmitOutputAndReportErrors(host, program, emittedFiles, emitSkipped,
|
||||
diagnostics, reportDiagnostic);
|
||||
|
||||
function ensureDirectoriesExist(directoryPath: string) {
|
||||
if (directoryPath.length > getRootLength(directoryPath) && !host.directoryExists(directoryPath)) {
|
||||
const parentDirectory = getDirectoryPath(directoryPath);
|
||||
ensureDirectoriesExist(parentDirectory);
|
||||
host.createDirectory(directoryPath);
|
||||
}
|
||||
}
|
||||
|
||||
function writeFile(fileName: string, data: string, writeByteOrderMark: boolean) {
|
||||
try {
|
||||
performance.mark("beforeIOWrite");
|
||||
ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName)));
|
||||
|
||||
host.writeFile(fileName, data, writeByteOrderMark);
|
||||
|
||||
performance.mark("afterIOWrite");
|
||||
performance.measure("I/O Write", "beforeIOWrite", "afterIOWrite");
|
||||
}
|
||||
catch (e) {
|
||||
return createCompilerDiagnostic(Diagnostics.Could_not_write_file_0_Colon_1, fileName, e);
|
||||
}
|
||||
}
|
||||
|
||||
function writeOutputFiles(outputFiles: OutputFile[]) {
|
||||
if (outputFiles) {
|
||||
for (const outputFile of outputFiles) {
|
||||
const error = writeFile(outputFile.name, outputFile.text, outputFile.writeByteOrderMark);
|
||||
if (error) {
|
||||
diagnostics.push(error);
|
||||
}
|
||||
if (emittedFiles) {
|
||||
emittedFiles.push(outputFile.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function createWatchModeWithConfigFile(configParseResult: ParsedCommandLine, optionsToExtend: CompilerOptions = {}, watchingHost?: WatchingSystemHost) {
|
||||
return createWatchMode(configParseResult.fileNames, configParseResult.options, watchingHost, configParseResult.options.configFilePath, configParseResult.configFileSpecs, configParseResult.wildcardDirectories, optionsToExtend);
|
||||
}
|
||||
|
||||
export function createWatchModeWithoutConfigFile(rootFileNames: string[], compilerOptions: CompilerOptions, watchingHost?: WatchingSystemHost) {
|
||||
return createWatchMode(rootFileNames, compilerOptions, watchingHost);
|
||||
}
|
||||
|
||||
interface HostFileInfo {
|
||||
version: number;
|
||||
sourceFile: SourceFile;
|
||||
fileWatcher: FileWatcher;
|
||||
}
|
||||
|
||||
function createWatchMode(rootFileNames: string[], compilerOptions: CompilerOptions, watchingHost?: WatchingSystemHost, configFileName?: string, configFileSpecs?: ConfigFileSpecs, configFileWildCardDirectories?: MapLike<WatchDirectoryFlags>, optionsToExtendForConfigFile?: CompilerOptions) {
|
||||
let program: Program;
|
||||
let needsReload: boolean; // true if the config file changed and needs to reload it from the disk
|
||||
let missingFilesMap: Map<FileWatcher>; // Map of file watchers for the missing files
|
||||
let watchedWildcardDirectories: Map<WildcardDirectoryWatcher>; // map of watchers for the wild card directories in the config file
|
||||
let timerToUpdateProgram: any; // timer callback to recompile the program
|
||||
|
||||
const sourceFilesCache = createMap<HostFileInfo | string>(); // Cache that stores the source file and version info
|
||||
let missingFilePathsRequestedForRelease: Path[]; // These paths are held temparirly so that we can remove the entry from source file cache if the file is not tracked by missing files
|
||||
let hasChangedCompilerOptions = false; // True if the compiler options have changed between compilations
|
||||
let hasChangedAutomaticTypeDirectiveNames = false; // True if the automatic type directives have changed
|
||||
|
||||
const loggingEnabled = compilerOptions.diagnostics || compilerOptions.extendedDiagnostics;
|
||||
const writeLog: (s: string) => void = loggingEnabled ? s => system.write(s) : noop;
|
||||
const watchFile = loggingEnabled ? ts.addFileWatcherWithLogging : ts.addFileWatcher;
|
||||
const watchFilePath = loggingEnabled ? ts.addFilePathWatcherWithLogging : ts.addFilePathWatcher;
|
||||
const watchDirectoryWorker = loggingEnabled ? ts.addDirectoryWatcherWithLogging : ts.addDirectoryWatcher;
|
||||
|
||||
watchingHost = watchingHost || createWatchingSystemHost(compilerOptions.pretty);
|
||||
const { system, parseConfigFile, reportDiagnostic, reportWatchDiagnostic, beforeCompile, afterCompile } = watchingHost;
|
||||
|
||||
const directoryStructureHost = configFileName ? createCachedDirectoryStructureHost(system) : system;
|
||||
if (configFileName) {
|
||||
watchFile(system, configFileName, scheduleProgramReload, writeLog);
|
||||
}
|
||||
|
||||
const getCurrentDirectory = memoize(() => directoryStructureHost.getCurrentDirectory());
|
||||
const realpath = system.realpath && ((path: string) => system.realpath(path));
|
||||
const getCachedDirectoryStructureHost = configFileName && (() => directoryStructureHost as CachedDirectoryStructureHost);
|
||||
const getCanonicalFileName = createGetCanonicalFileName(system.useCaseSensitiveFileNames);
|
||||
let newLine = getNewLineCharacter(compilerOptions, system);
|
||||
|
||||
const compilerHost: CompilerHost & ResolutionCacheHost = {
|
||||
// Members for CompilerHost
|
||||
getSourceFile: (fileName, languageVersion, onError?, shouldCreateNewSourceFile?) => getVersionedSourceFileByPath(fileName, toPath(fileName), languageVersion, onError, shouldCreateNewSourceFile),
|
||||
getSourceFileByPath: getVersionedSourceFileByPath,
|
||||
getDefaultLibLocation,
|
||||
getDefaultLibFileName: options => combinePaths(getDefaultLibLocation(), getDefaultLibFileName(options)),
|
||||
writeFile: notImplemented,
|
||||
getCurrentDirectory,
|
||||
useCaseSensitiveFileNames: () => system.useCaseSensitiveFileNames,
|
||||
getCanonicalFileName,
|
||||
getNewLine: () => newLine,
|
||||
fileExists,
|
||||
readFile: fileName => system.readFile(fileName),
|
||||
trace: s => system.write(s + newLine),
|
||||
directoryExists: directoryName => directoryStructureHost.directoryExists(directoryName),
|
||||
getEnvironmentVariable: name => system.getEnvironmentVariable ? system.getEnvironmentVariable(name) : "",
|
||||
getDirectories: path => directoryStructureHost.getDirectories(path),
|
||||
realpath,
|
||||
resolveTypeReferenceDirectives: (typeDirectiveNames, containingFile) => resolutionCache.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile),
|
||||
resolveModuleNames: (moduleNames, containingFile, reusedNames?) => resolutionCache.resolveModuleNames(moduleNames, containingFile, reusedNames, /*logChanges*/ false),
|
||||
onReleaseOldSourceFile,
|
||||
// Members for ResolutionCacheHost
|
||||
toPath,
|
||||
getCompilationSettings: () => compilerOptions,
|
||||
watchDirectoryOfFailedLookupLocation: watchDirectory,
|
||||
watchTypeRootsDirectory: watchDirectory,
|
||||
getCachedDirectoryStructureHost,
|
||||
onInvalidatedResolution: scheduleProgramUpdate,
|
||||
onChangedAutomaticTypeDirectiveNames: () => {
|
||||
hasChangedAutomaticTypeDirectiveNames = true;
|
||||
scheduleProgramUpdate();
|
||||
},
|
||||
writeLog
|
||||
};
|
||||
// Cache for the module resolution
|
||||
const resolutionCache = createResolutionCache(compilerHost, configFileName ?
|
||||
getDirectoryPath(getNormalizedAbsolutePath(configFileName, getCurrentDirectory())) :
|
||||
getCurrentDirectory()
|
||||
);
|
||||
// There is no extra check needed since we can just rely on the program to decide emit
|
||||
const builder = createBuilder({ getCanonicalFileName, getEmitOutput: getFileEmitOutput, computeHash, shouldEmitFile: () => true });
|
||||
|
||||
synchronizeProgram();
|
||||
|
||||
// Update the wild card directory watch
|
||||
watchConfigFileWildCardDirectories();
|
||||
|
||||
return () => program;
|
||||
|
||||
function synchronizeProgram() {
|
||||
writeLog(`Synchronizing program`);
|
||||
|
||||
if (hasChangedCompilerOptions) {
|
||||
newLine = getNewLineCharacter(compilerOptions, system);
|
||||
}
|
||||
|
||||
const hasInvalidatedResolution = resolutionCache.createHasInvalidatedResolution();
|
||||
if (isProgramUptoDate(program, rootFileNames, compilerOptions, getSourceVersion, fileExists, hasInvalidatedResolution, hasChangedAutomaticTypeDirectiveNames)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasChangedCompilerOptions && changesAffectModuleResolution(program && program.getCompilerOptions(), compilerOptions)) {
|
||||
resolutionCache.clear();
|
||||
}
|
||||
const needsUpdateInTypeRootWatch = hasChangedCompilerOptions || !program;
|
||||
hasChangedCompilerOptions = false;
|
||||
beforeCompile(compilerOptions);
|
||||
|
||||
// Compile the program
|
||||
resolutionCache.startCachingPerDirectoryResolution();
|
||||
compilerHost.hasInvalidatedResolution = hasInvalidatedResolution;
|
||||
compilerHost.hasChangedAutomaticTypeDirectiveNames = hasChangedAutomaticTypeDirectiveNames;
|
||||
program = createProgram(rootFileNames, compilerOptions, compilerHost, program);
|
||||
resolutionCache.finishCachingPerDirectoryResolution();
|
||||
builder.updateProgram(program);
|
||||
|
||||
// Update watches
|
||||
updateMissingFilePathsWatch(program, missingFilesMap || (missingFilesMap = createMap()), watchMissingFilePath);
|
||||
if (needsUpdateInTypeRootWatch) {
|
||||
resolutionCache.updateTypeRootsWatch();
|
||||
}
|
||||
|
||||
if (missingFilePathsRequestedForRelease) {
|
||||
// These are the paths that program creater told us as not in use any more but were missing on the disk.
|
||||
// We didnt remove the entry for them from sourceFiles cache so that we dont have to do File IO,
|
||||
// if there is already watcher for it (for missing files)
|
||||
// At this point our watches were updated, hence now we know that these paths are not tracked and need to be removed
|
||||
// so that at later time we have correct result of their presence
|
||||
for (const missingFilePath of missingFilePathsRequestedForRelease) {
|
||||
if (!missingFilesMap.has(missingFilePath)) {
|
||||
sourceFilesCache.delete(missingFilePath);
|
||||
}
|
||||
}
|
||||
missingFilePathsRequestedForRelease = undefined;
|
||||
}
|
||||
|
||||
afterCompile(directoryStructureHost, program, builder);
|
||||
reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.Compilation_complete_Watching_for_file_changes));
|
||||
}
|
||||
|
||||
function toPath(fileName: string) {
|
||||
return ts.toPath(fileName, getCurrentDirectory(), getCanonicalFileName);
|
||||
}
|
||||
|
||||
function fileExists(fileName: string) {
|
||||
const path = toPath(fileName);
|
||||
const hostSourceFileInfo = sourceFilesCache.get(path);
|
||||
if (hostSourceFileInfo !== undefined) {
|
||||
return !isString(hostSourceFileInfo);
|
||||
}
|
||||
|
||||
return directoryStructureHost.fileExists(fileName);
|
||||
}
|
||||
|
||||
function getDefaultLibLocation(): string {
|
||||
return getDirectoryPath(normalizePath(system.getExecutingFilePath()));
|
||||
}
|
||||
|
||||
function getVersionedSourceFileByPath(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile {
|
||||
const hostSourceFile = sourceFilesCache.get(path);
|
||||
// No source file on the host
|
||||
if (isString(hostSourceFile)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Create new source file if requested or the versions dont match
|
||||
if (!hostSourceFile || shouldCreateNewSourceFile || hostSourceFile.version.toString() !== hostSourceFile.sourceFile.version) {
|
||||
const sourceFile = getNewSourceFile();
|
||||
if (hostSourceFile) {
|
||||
if (shouldCreateNewSourceFile) {
|
||||
hostSourceFile.version++;
|
||||
}
|
||||
if (sourceFile) {
|
||||
hostSourceFile.sourceFile = sourceFile;
|
||||
sourceFile.version = hostSourceFile.version.toString();
|
||||
if (!hostSourceFile.fileWatcher) {
|
||||
hostSourceFile.fileWatcher = watchFilePath(system, fileName, onSourceFileChange, path, writeLog);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// There is no source file on host any more, close the watch, missing file paths will track it
|
||||
hostSourceFile.fileWatcher.close();
|
||||
sourceFilesCache.set(path, hostSourceFile.version.toString());
|
||||
}
|
||||
}
|
||||
else {
|
||||
let fileWatcher: FileWatcher;
|
||||
if (sourceFile) {
|
||||
sourceFile.version = "0";
|
||||
fileWatcher = watchFilePath(system, fileName, onSourceFileChange, path, writeLog);
|
||||
sourceFilesCache.set(path, { sourceFile, version: 0, fileWatcher });
|
||||
}
|
||||
else {
|
||||
sourceFilesCache.set(path, "0");
|
||||
}
|
||||
}
|
||||
return sourceFile;
|
||||
}
|
||||
return hostSourceFile.sourceFile;
|
||||
|
||||
function getNewSourceFile() {
|
||||
let text: string;
|
||||
try {
|
||||
performance.mark("beforeIORead");
|
||||
text = system.readFile(fileName, compilerOptions.charset);
|
||||
performance.mark("afterIORead");
|
||||
performance.measure("I/O Read", "beforeIORead", "afterIORead");
|
||||
}
|
||||
catch (e) {
|
||||
if (onError) {
|
||||
onError(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
return text !== undefined ? createSourceFile(fileName, text, languageVersion) : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function removeSourceFile(path: Path) {
|
||||
const hostSourceFile = sourceFilesCache.get(path);
|
||||
if (hostSourceFile !== undefined) {
|
||||
if (!isString(hostSourceFile)) {
|
||||
hostSourceFile.fileWatcher.close();
|
||||
resolutionCache.invalidateResolutionOfFile(path);
|
||||
}
|
||||
sourceFilesCache.delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
function getSourceVersion(path: Path): string {
|
||||
const hostSourceFile = sourceFilesCache.get(path);
|
||||
return !hostSourceFile || isString(hostSourceFile) ? undefined : hostSourceFile.version.toString();
|
||||
}
|
||||
|
||||
function onReleaseOldSourceFile(oldSourceFile: SourceFile, _oldOptions: CompilerOptions) {
|
||||
const hostSourceFileInfo = sourceFilesCache.get(oldSourceFile.path);
|
||||
// If this is the source file thats in the cache and new program doesnt need it,
|
||||
// remove the cached entry.
|
||||
// Note we arent deleting entry if file became missing in new program or
|
||||
// there was version update and new source file was created.
|
||||
if (hostSourceFileInfo) {
|
||||
// record the missing file paths so they can be removed later if watchers arent tracking them
|
||||
if (isString(hostSourceFileInfo)) {
|
||||
(missingFilePathsRequestedForRelease || (missingFilePathsRequestedForRelease = [])).push(oldSourceFile.path);
|
||||
}
|
||||
else if (hostSourceFileInfo.sourceFile === oldSourceFile) {
|
||||
sourceFilesCache.delete(oldSourceFile.path);
|
||||
resolutionCache.removeResolutionsOfFile(oldSourceFile.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Upon detecting a file change, wait for 250ms and then perform a recompilation. This gives batch
|
||||
// operations (such as saving all modified files in an editor) a chance to complete before we kick
|
||||
// off a new compilation.
|
||||
function scheduleProgramUpdate() {
|
||||
if (!system.setTimeout || !system.clearTimeout) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (timerToUpdateProgram) {
|
||||
system.clearTimeout(timerToUpdateProgram);
|
||||
}
|
||||
timerToUpdateProgram = system.setTimeout(updateProgram, 250);
|
||||
}
|
||||
|
||||
function scheduleProgramReload() {
|
||||
Debug.assert(!!configFileName);
|
||||
needsReload = true;
|
||||
scheduleProgramUpdate();
|
||||
}
|
||||
|
||||
function updateProgram() {
|
||||
timerToUpdateProgram = undefined;
|
||||
reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation));
|
||||
|
||||
if (needsReload) {
|
||||
reloadConfigFile();
|
||||
}
|
||||
else {
|
||||
synchronizeProgram();
|
||||
}
|
||||
}
|
||||
|
||||
function reloadConfigFile() {
|
||||
writeLog(`Reloading config file: ${configFileName}`);
|
||||
needsReload = false;
|
||||
|
||||
const cachedHost = directoryStructureHost as CachedDirectoryStructureHost;
|
||||
cachedHost.clearCache();
|
||||
const configParseResult = parseConfigFile(configFileName, optionsToExtendForConfigFile, cachedHost, reportDiagnostic, reportWatchDiagnostic);
|
||||
rootFileNames = configParseResult.fileNames;
|
||||
compilerOptions = configParseResult.options;
|
||||
hasChangedCompilerOptions = true;
|
||||
configFileSpecs = configParseResult.configFileSpecs;
|
||||
configFileWildCardDirectories = configParseResult.wildcardDirectories;
|
||||
|
||||
synchronizeProgram();
|
||||
|
||||
// Update the wild card directory watch
|
||||
watchConfigFileWildCardDirectories();
|
||||
}
|
||||
|
||||
function onSourceFileChange(fileName: string, eventKind: FileWatcherEventKind, path: Path) {
|
||||
updateCachedSystemWithFile(fileName, path, eventKind);
|
||||
const hostSourceFile = sourceFilesCache.get(path);
|
||||
if (hostSourceFile) {
|
||||
// Update the cache
|
||||
if (eventKind === FileWatcherEventKind.Deleted) {
|
||||
resolutionCache.invalidateResolutionOfFile(path);
|
||||
if (!isString(hostSourceFile)) {
|
||||
hostSourceFile.fileWatcher.close();
|
||||
sourceFilesCache.set(path, (hostSourceFile.version++).toString());
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Deleted file created
|
||||
if (isString(hostSourceFile)) {
|
||||
sourceFilesCache.delete(path);
|
||||
}
|
||||
else {
|
||||
// file changed - just update the version
|
||||
hostSourceFile.version++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the program
|
||||
scheduleProgramUpdate();
|
||||
}
|
||||
|
||||
function updateCachedSystemWithFile(fileName: string, path: Path, eventKind: FileWatcherEventKind) {
|
||||
if (configFileName) {
|
||||
(directoryStructureHost as CachedDirectoryStructureHost).addOrDeleteFile(fileName, path, eventKind);
|
||||
}
|
||||
}
|
||||
|
||||
function watchDirectory(directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags) {
|
||||
return watchDirectoryWorker(system, directory, cb, flags, writeLog);
|
||||
}
|
||||
|
||||
function watchMissingFilePath(missingFilePath: Path) {
|
||||
return watchFilePath(system, missingFilePath, onMissingFileChange, missingFilePath, writeLog);
|
||||
}
|
||||
|
||||
function onMissingFileChange(fileName: string, eventKind: FileWatcherEventKind, missingFilePath: Path) {
|
||||
updateCachedSystemWithFile(fileName, missingFilePath, eventKind);
|
||||
|
||||
if (eventKind === FileWatcherEventKind.Created && missingFilesMap.has(missingFilePath)) {
|
||||
missingFilesMap.get(missingFilePath).close();
|
||||
missingFilesMap.delete(missingFilePath);
|
||||
|
||||
// Delete the entry in the source files cache so that new source file is created
|
||||
removeSourceFile(missingFilePath);
|
||||
|
||||
// When a missing file is created, we should update the graph.
|
||||
scheduleProgramUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
function watchConfigFileWildCardDirectories() {
|
||||
updateWatchingWildcardDirectories(
|
||||
watchedWildcardDirectories || (watchedWildcardDirectories = createMap()),
|
||||
createMapFromTemplate(configFileWildCardDirectories),
|
||||
watchWildcardDirectory
|
||||
);
|
||||
}
|
||||
|
||||
function watchWildcardDirectory(directory: string, flags: WatchDirectoryFlags) {
|
||||
return watchDirectory(
|
||||
directory,
|
||||
fileOrDirectory => {
|
||||
Debug.assert(!!configFileName);
|
||||
|
||||
const fileOrDirectoryPath = toPath(fileOrDirectory);
|
||||
|
||||
// Since the file existance changed, update the sourceFiles cache
|
||||
(directoryStructureHost as CachedDirectoryStructureHost).addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath);
|
||||
removeSourceFile(fileOrDirectoryPath);
|
||||
|
||||
// If the the added or created file or directory is not supported file name, ignore the file
|
||||
// But when watched directory is added/removed, we need to reload the file list
|
||||
if (fileOrDirectoryPath !== directory && !isSupportedSourceFileName(fileOrDirectory, compilerOptions)) {
|
||||
writeLog(`Project: ${configFileName} Detected file add/remove of non supported extension: ${fileOrDirectory}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Reload is pending, do the reload
|
||||
if (!needsReload) {
|
||||
const result = getFileNamesFromConfigSpecs(configFileSpecs, getDirectoryPath(configFileName), compilerOptions, directoryStructureHost);
|
||||
if (!configFileSpecs.filesSpecs && result.fileNames.length === 0) {
|
||||
reportDiagnostic(getErrorForNoInputFiles(configFileSpecs, configFileName));
|
||||
}
|
||||
rootFileNames = result.fileNames;
|
||||
|
||||
// Schedule Update the program
|
||||
scheduleProgramUpdate();
|
||||
}
|
||||
},
|
||||
flags
|
||||
);
|
||||
}
|
||||
|
||||
function computeHash(data: string) {
|
||||
return system.createHash ? system.createHash(data) : data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/// <reference path="core.ts" />
|
||||
|
||||
namespace ts {
|
||||
/**
|
||||
* Updates the existing missing file watches with the new set of missing files after new program is created
|
||||
*/
|
||||
export function updateMissingFilePathsWatch(
|
||||
program: Program,
|
||||
missingFileWatches: Map<FileWatcher>,
|
||||
createMissingFileWatch: (missingFilePath: Path) => FileWatcher,
|
||||
) {
|
||||
const missingFilePaths = program.getMissingFilePaths();
|
||||
const newMissingFilePathMap = arrayToSet(missingFilePaths);
|
||||
// Update the missing file paths watcher
|
||||
mutateMap(
|
||||
missingFileWatches,
|
||||
newMissingFilePathMap,
|
||||
{
|
||||
// Watch the missing files
|
||||
createNewValue: createMissingFileWatch,
|
||||
// Files that are no longer missing (e.g. because they are no longer required)
|
||||
// should no longer be watched.
|
||||
onDeleteValue: closeFileWatcher
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export interface WildcardDirectoryWatcher {
|
||||
watcher: FileWatcher;
|
||||
flags: WatchDirectoryFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the existing wild card directory watches with the new set of wild card directories from the config file
|
||||
* after new program is created because the config file was reloaded or program was created first time from the config file
|
||||
* Note that there is no need to call this function when the program is updated with additional files without reloading config files,
|
||||
* as wildcard directories wont change unless reloading config file
|
||||
*/
|
||||
export function updateWatchingWildcardDirectories(
|
||||
existingWatchedForWildcards: Map<WildcardDirectoryWatcher>,
|
||||
wildcardDirectories: Map<WatchDirectoryFlags>,
|
||||
watchDirectory: (directory: string, flags: WatchDirectoryFlags) => FileWatcher
|
||||
) {
|
||||
mutateMap(
|
||||
existingWatchedForWildcards,
|
||||
wildcardDirectories,
|
||||
{
|
||||
// Create new watch and recursive info
|
||||
createNewValue: createWildcardDirectoryWatcher,
|
||||
// Close existing watch thats not needed any more
|
||||
onDeleteValue: closeFileWatcherOf,
|
||||
// Close existing watch that doesnt match in the flags
|
||||
onExistingValue: updateWildcardDirectoryWatcher
|
||||
}
|
||||
);
|
||||
|
||||
function createWildcardDirectoryWatcher(directory: string, flags: WatchDirectoryFlags): WildcardDirectoryWatcher {
|
||||
// Create new watch and recursive info
|
||||
return {
|
||||
watcher: watchDirectory(directory, flags),
|
||||
flags
|
||||
};
|
||||
}
|
||||
|
||||
function updateWildcardDirectoryWatcher(existingWatcher: WildcardDirectoryWatcher, flags: WatchDirectoryFlags, directory: string) {
|
||||
// Watcher needs to be updated if the recursive flags dont match
|
||||
if (existingWatcher.flags === flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
existingWatcher.watcher.close();
|
||||
existingWatchedForWildcards.set(directory, createWildcardDirectoryWatcher(directory, flags));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export function addFileWatcher(host: System, file: string, cb: FileWatcherCallback): FileWatcher {
|
||||
return host.watchFile(file, cb);
|
||||
}
|
||||
|
||||
export function addFileWatcherWithLogging(host: System, file: string, cb: FileWatcherCallback, log: (s: string) => void): FileWatcher {
|
||||
const watcherCaption = `FileWatcher:: `;
|
||||
return createWatcherWithLogging(addFileWatcher, watcherCaption, log, host, file, cb);
|
||||
}
|
||||
|
||||
export type FilePathWatcherCallback = (fileName: string, eventKind: FileWatcherEventKind, filePath: Path) => void;
|
||||
export function addFilePathWatcher(host: System, file: string, cb: FilePathWatcherCallback, path: Path): FileWatcher {
|
||||
return host.watchFile(file, (fileName, eventKind) => cb(fileName, eventKind, path));
|
||||
}
|
||||
|
||||
export function addFilePathWatcherWithLogging(host: System, file: string, cb: FilePathWatcherCallback, path: Path, log: (s: string) => void): FileWatcher {
|
||||
const watcherCaption = `FileWatcher:: `;
|
||||
return createWatcherWithLogging(addFileWatcher, watcherCaption, log, host, file, cb, path);
|
||||
}
|
||||
|
||||
export function addDirectoryWatcher(host: System, directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags): FileWatcher {
|
||||
const recursive = (flags & WatchDirectoryFlags.Recursive) !== 0;
|
||||
return host.watchDirectory(directory, cb, recursive);
|
||||
}
|
||||
|
||||
export function addDirectoryWatcherWithLogging(host: System, directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags, log: (s: string) => void): FileWatcher {
|
||||
const watcherCaption = `DirectoryWatcher ${(flags & WatchDirectoryFlags.Recursive) !== 0 ? "recursive" : ""}:: `;
|
||||
return createWatcherWithLogging(addDirectoryWatcher, watcherCaption, log, host, directory, cb, flags);
|
||||
}
|
||||
|
||||
type WatchCallback<T, U> = (fileName: string, cbOptional1?: T, optional?: U) => void;
|
||||
type AddWatch<T, U> = (host: System, file: string, cb: WatchCallback<T, U>, optional?: U) => FileWatcher;
|
||||
function createWatcherWithLogging<T, U>(addWatch: AddWatch<T, U>, watcherCaption: string, log: (s: string) => void, host: System, file: string, cb: WatchCallback<T, U>, optional?: U): FileWatcher {
|
||||
const info = `PathInfo: ${file}`;
|
||||
log(`${watcherCaption}Added: ${info}`);
|
||||
const watcher = addWatch(host, file, (fileName, cbOptional1?) => {
|
||||
const optionalInfo = cbOptional1 !== undefined ? ` ${cbOptional1}` : "";
|
||||
log(`${watcherCaption}Trigger: ${fileName}${optionalInfo} ${info}`);
|
||||
const start = timestamp();
|
||||
cb(fileName, cbOptional1, optional);
|
||||
const elapsed = timestamp() - start;
|
||||
log(`${watcherCaption}Elapsed: ${elapsed}ms Trigger: ${fileName}${optionalInfo} ${info}`);
|
||||
}, optional);
|
||||
return {
|
||||
close: () => {
|
||||
log(`${watcherCaption}Close: ${info}`);
|
||||
watcher.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function closeFileWatcher(watcher: FileWatcher) {
|
||||
watcher.close();
|
||||
}
|
||||
|
||||
export function closeFileWatcherOf<T extends { watcher: FileWatcher; }>(objWithWatcher: T) {
|
||||
objWithWatcher.watcher.close();
|
||||
}
|
||||
}
|
||||
@@ -177,7 +177,7 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
return;
|
||||
}
|
||||
|
||||
Harness.Compiler.doTypeAndSymbolBaseline(justName, result, toBeCompiled.concat(otherFiles).filter(file => !!result.program.getSourceFile(file.unitName)));
|
||||
Harness.Compiler.doTypeAndSymbolBaseline(justName, result.program, toBeCompiled.concat(otherFiles).filter(file => !!result.program.getSourceFile(file.unitName)));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
+66
-16
@@ -390,7 +390,7 @@ namespace FourSlash {
|
||||
|
||||
// Entry points from fourslash.ts
|
||||
public goToMarker(name: string | Marker = "") {
|
||||
const marker = typeof name === "string" ? this.getMarkerByName(name) : name;
|
||||
const marker = ts.isString(name) ? this.getMarkerByName(name) : name;
|
||||
if (this.activeFile.fileName !== marker.fileName) {
|
||||
this.openFile(marker.fileName);
|
||||
}
|
||||
@@ -399,7 +399,7 @@ namespace FourSlash {
|
||||
if (marker.position === -1 || marker.position > content.length) {
|
||||
throw new Error(`Marker "${name}" has been invalidated by unrecoverable edits to the file.`);
|
||||
}
|
||||
const mName = typeof name === "string" ? name : this.markerName(marker);
|
||||
const mName = ts.isString(name) ? name : this.markerName(marker);
|
||||
this.lastKnownMarker = mName;
|
||||
this.goToPosition(marker.position);
|
||||
}
|
||||
@@ -1003,7 +1003,7 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public verifyReferenceGroups(startRanges: Range | Range[], parts: Array<{ definition: string, ranges: Range[] }>): void {
|
||||
public verifyReferenceGroups(startRanges: Range | Range[], parts: FourSlashInterface.ReferenceGroup[]): void {
|
||||
const fullExpected = ts.map(parts, ({ definition, ranges }) => ({ definition, ranges: ranges.map(rangeToReferenceEntry) }));
|
||||
|
||||
for (const startRange of toArray(startRanges)) {
|
||||
@@ -1027,7 +1027,7 @@ namespace FourSlash {
|
||||
|
||||
public verifyNoReferences(markerNameOrRange?: string | Range) {
|
||||
if (markerNameOrRange) {
|
||||
if (typeof markerNameOrRange === "string") {
|
||||
if (ts.isString(markerNameOrRange)) {
|
||||
this.goToMarker(markerNameOrRange);
|
||||
}
|
||||
else {
|
||||
@@ -1037,8 +1037,7 @@ namespace FourSlash {
|
||||
|
||||
const refs = this.getReferencesAtCaret();
|
||||
if (refs && refs.length) {
|
||||
console.log(refs);
|
||||
this.raiseError("Expected getReferences to fail");
|
||||
this.raiseError(`Expected getReferences to fail, but saw references: ${stringify(refs)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1050,9 +1049,9 @@ namespace FourSlash {
|
||||
private assertObjectsEqual<T>(fullActual: T, fullExpected: T, msgPrefix = ""): void {
|
||||
const recur = <U>(actual: U, expected: U, path: string) => {
|
||||
const fail = (msg: string) => {
|
||||
console.log("Expected:", stringify(fullExpected));
|
||||
console.log("Actual: ", stringify(fullActual));
|
||||
this.raiseError(`${msgPrefix}At ${path}: ${msg}`);
|
||||
this.raiseError(`${msgPrefix} At ${path}: ${msg}
|
||||
Expected: ${stringify(fullExpected)}
|
||||
Actual: ${stringify(fullActual)}`);
|
||||
};
|
||||
|
||||
if ((actual === undefined) !== (expected === undefined)) {
|
||||
@@ -1084,9 +1083,9 @@ namespace FourSlash {
|
||||
if (fullActual === fullExpected) {
|
||||
return;
|
||||
}
|
||||
console.log("Expected:", stringify(fullExpected));
|
||||
console.log("Actual: ", stringify(fullActual));
|
||||
this.raiseError(msgPrefix);
|
||||
this.raiseError(`${msgPrefix}
|
||||
Expected: ${stringify(fullExpected)}
|
||||
Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
recur(fullActual, fullExpected, "");
|
||||
|
||||
@@ -1523,7 +1522,7 @@ namespace FourSlash {
|
||||
resultString += "Diagnostics:" + Harness.IO.newLine();
|
||||
const diagnostics = ts.getPreEmitDiagnostics(this.languageService.getProgram());
|
||||
for (const diagnostic of diagnostics) {
|
||||
if (typeof diagnostic.messageText !== "string") {
|
||||
if (!ts.isString(diagnostic.messageText)) {
|
||||
let chainedMessage = <ts.DiagnosticMessageChain>diagnostic.messageText;
|
||||
let indentation = " ";
|
||||
while (chainedMessage) {
|
||||
@@ -2337,6 +2336,39 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public verifyCodeFix(options: FourSlashInterface.VerifyCodeFixOptions) {
|
||||
const fileName = this.activeFile.fileName;
|
||||
const actions = this.getCodeFixActions(fileName, options.errorCode);
|
||||
let index = options.index;
|
||||
if (index === undefined) {
|
||||
if (!(actions && actions.length === 1)) {
|
||||
this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found. ${actions ? actions.map(a => `${Harness.IO.newLine()} "${a.description}"`) : ""}`);
|
||||
}
|
||||
index = 0;
|
||||
}
|
||||
else {
|
||||
if (!(actions && actions.length >= index + 1)) {
|
||||
this.raiseError(`Should find at least ${index + 1} codefix(es), but ${actions ? actions.length : "none"} found.`);
|
||||
}
|
||||
}
|
||||
|
||||
const action = actions[index];
|
||||
|
||||
assert.equal(action.description, options.description);
|
||||
|
||||
for (const change of action.changes) {
|
||||
this.applyEdits(change.fileName, change.textChanges, /*isFormattingEdit*/ false);
|
||||
}
|
||||
|
||||
if (options.newFileContent) {
|
||||
assert(!options.newRangeContent);
|
||||
this.verifyCurrentFileContent(options.newFileContent);
|
||||
}
|
||||
else {
|
||||
this.verifyRangeIs(options.newRangeContent, /*includeWhitespace*/ true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rerieves a codefix satisfying the parameters, or undefined if no such codefix is found.
|
||||
* @param fileName Path to file where error should be retrieved from.
|
||||
@@ -2792,7 +2824,7 @@ namespace FourSlash {
|
||||
const refactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, range);
|
||||
const refactor = refactors.find(r => r.name === refactorName);
|
||||
if (!refactor) {
|
||||
this.raiseError(`The expected refactor: ${refactorName} is not available at the marker location.`);
|
||||
this.raiseError(`The expected refactor: ${refactorName} is not available at the marker location.\nAvailable refactors: ${refactors.map(r => r.name)}`);
|
||||
}
|
||||
|
||||
const action = refactor.actions.find(a => a.name === actionName);
|
||||
@@ -2944,7 +2976,7 @@ namespace FourSlash {
|
||||
result = this.testData.files[index];
|
||||
}
|
||||
}
|
||||
else if (typeof indexOrName === "string") {
|
||||
else if (ts.isString(indexOrName)) {
|
||||
let name = <string>indexOrName;
|
||||
|
||||
// names are stored in the compiler with this relative path, this allows people to use goTo.file on just the fileName
|
||||
@@ -3716,6 +3748,10 @@ namespace FourSlashInterface {
|
||||
this.state.verifySpanOfEnclosingComment(this.negative, onlyMultiLineDiverges);
|
||||
}
|
||||
|
||||
public codeFix(options: FourSlashInterface.VerifyCodeFixOptions) {
|
||||
this.state.verifyCodeFix(options);
|
||||
}
|
||||
|
||||
public codeFixAvailable() {
|
||||
this.state.verifyCodeFixAvailable(this.negative);
|
||||
}
|
||||
@@ -3833,7 +3869,7 @@ namespace FourSlashInterface {
|
||||
this.state.verifyReferencesOf(start, references);
|
||||
}
|
||||
|
||||
public referenceGroups(startRanges: FourSlash.Range[], parts: Array<{ definition: string, ranges: FourSlash.Range[] }>) {
|
||||
public referenceGroups(startRanges: FourSlash.Range[], parts: ReferenceGroup[]) {
|
||||
this.state.verifyReferenceGroups(startRanges, parts);
|
||||
}
|
||||
|
||||
@@ -4344,6 +4380,11 @@ namespace FourSlashInterface {
|
||||
}
|
||||
}
|
||||
|
||||
export interface ReferenceGroup {
|
||||
definition: string;
|
||||
ranges: FourSlash.Range[];
|
||||
}
|
||||
|
||||
export interface ApplyRefactorOptions {
|
||||
refactorName: string;
|
||||
actionName: string;
|
||||
@@ -4354,4 +4395,13 @@ namespace FourSlashInterface {
|
||||
export interface CompletionsAtOptions {
|
||||
isNewIdentifierLocation?: boolean;
|
||||
}
|
||||
|
||||
export interface VerifyCodeFixOptions {
|
||||
description: string;
|
||||
// One of these should be defined.
|
||||
newFileContent?: string;
|
||||
newRangeContent?: string;
|
||||
errorCode?: number;
|
||||
index?: number;
|
||||
}
|
||||
}
|
||||
|
||||
+65
-67
@@ -148,6 +148,8 @@ namespace Utils {
|
||||
});
|
||||
}
|
||||
|
||||
export const canonicalizeForHarness = ts.createGetCanonicalFileName(/*caseSensitive*/ false); // This is done so tests work on windows _and_ linux
|
||||
|
||||
export function assertInvariants(node: ts.Node, parent: ts.Node): void {
|
||||
if (node) {
|
||||
assert.isFalse(node.pos < 0, "node.pos < 0");
|
||||
@@ -225,7 +227,7 @@ namespace Utils {
|
||||
return JSON.stringify(file, (_, v) => isNodeOrArray(v) ? serializeNode(v) : v, " ");
|
||||
|
||||
function getKindName(k: number | string): string {
|
||||
if (typeof k === "string") {
|
||||
if (ts.isString(k)) {
|
||||
return k;
|
||||
}
|
||||
|
||||
@@ -755,6 +757,10 @@ namespace Harness {
|
||||
}
|
||||
}
|
||||
|
||||
export function mockHash(s: string): string {
|
||||
return `hash-${s}`;
|
||||
}
|
||||
|
||||
const environment = Utils.getExecutionEnvironment();
|
||||
switch (environment) {
|
||||
case Utils.ExecutionEnvironment.Node:
|
||||
@@ -1446,10 +1452,7 @@ namespace Harness {
|
||||
});
|
||||
}
|
||||
|
||||
export function doTypeAndSymbolBaseline(baselinePath: string, result: CompilerResult, allFiles: {unitName: string, content: string}[], opts?: Harness.Baseline.BaselineOptions, multifile?: boolean) {
|
||||
if (result.errors.length !== 0) {
|
||||
return;
|
||||
}
|
||||
export function doTypeAndSymbolBaseline(baselinePath: string, program: ts.Program, allFiles: {unitName: string, content: string}[], opts?: Harness.Baseline.BaselineOptions, multifile?: boolean, skipTypeAndSymbolbaselines?: boolean) {
|
||||
// The full walker simulates the types that you would get from doing a full
|
||||
// compile. The pull walker simulates the types you get when you just do
|
||||
// a type query for a random node (like how the LS would do it). Most of the
|
||||
@@ -1465,16 +1468,8 @@ namespace Harness {
|
||||
// These types are equivalent, but depend on what order the compiler observed
|
||||
// certain parts of the program.
|
||||
|
||||
const program = result.program;
|
||||
|
||||
const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true);
|
||||
|
||||
const fullResults = ts.createMap<TypeWriterResult[]>();
|
||||
|
||||
for (const sourceFile of allFiles) {
|
||||
fullResults.set(sourceFile.unitName, fullWalker.getTypeAndSymbols(sourceFile.unitName));
|
||||
}
|
||||
|
||||
// Produce baselines. The first gives the types for all expressions.
|
||||
// The second gives symbols for all identifiers.
|
||||
let typesError: Error, symbolsError: Error;
|
||||
@@ -1515,76 +1510,77 @@ namespace Harness {
|
||||
baselinePath.replace(/\.tsx?/, "") : baselinePath;
|
||||
|
||||
if (!multifile) {
|
||||
const fullBaseLine = generateBaseLine(fullResults, isSymbolBaseLine);
|
||||
const fullBaseLine = generateBaseLine(isSymbolBaseLine, skipTypeAndSymbolbaselines);
|
||||
Harness.Baseline.runBaseline(outputFileName + fullExtension, () => fullBaseLine, opts);
|
||||
}
|
||||
else {
|
||||
Harness.Baseline.runMultifileBaseline(outputFileName, fullExtension, () => {
|
||||
return iterateBaseLine(fullResults, isSymbolBaseLine);
|
||||
return iterateBaseLine(isSymbolBaseLine, skipTypeAndSymbolbaselines);
|
||||
}, opts);
|
||||
}
|
||||
}
|
||||
|
||||
function generateBaseLine(typeWriterResults: ts.Map<TypeWriterResult[]>, isSymbolBaseline: boolean): string {
|
||||
function generateBaseLine(isSymbolBaseline: boolean, skipTypeAndSymbolbaselines?: boolean): string {
|
||||
let result = "";
|
||||
const gen = iterateBaseLine(typeWriterResults, isSymbolBaseline);
|
||||
const gen = iterateBaseLine(isSymbolBaseline, skipTypeAndSymbolbaselines);
|
||||
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
|
||||
const [, content] = value;
|
||||
result += content;
|
||||
}
|
||||
return result;
|
||||
/* tslint:disable:no-null-keyword */
|
||||
return result || null;
|
||||
/* tslint:enable:no-null-keyword */
|
||||
}
|
||||
|
||||
function *iterateBaseLine(typeWriterResults: ts.Map<TypeWriterResult[]>, isSymbolBaseline: boolean): IterableIterator<[string, string]> {
|
||||
let typeLines = "";
|
||||
const typeMap: { [fileName: string]: { [lineNum: number]: string[]; } } = {};
|
||||
function *iterateBaseLine(isSymbolBaseline: boolean, skipTypeAndSymbolbaselines?: boolean): IterableIterator<[string, string]> {
|
||||
if (skipTypeAndSymbolbaselines) {
|
||||
return;
|
||||
}
|
||||
const dupeCase = ts.createMap<number>();
|
||||
|
||||
for (const file of allFiles) {
|
||||
const codeLines = file.content.split("\n");
|
||||
const key = file.unitName;
|
||||
typeWriterResults.get(file.unitName).forEach(result => {
|
||||
const { unitName } = file;
|
||||
let typeLines = "=== " + unitName + " ===\r\n";
|
||||
const codeLines = ts.flatMap(file.content.split(/\r?\n/g), e => e.split(/[\r\u2028\u2029]/g));
|
||||
const gen: IterableIterator<TypeWriterResult> = isSymbolBaseline ? fullWalker.getSymbols(unitName) : fullWalker.getTypes(unitName);
|
||||
let lastIndexWritten: number | undefined;
|
||||
for (let {done, value: result} = gen.next(); !done; { done, value: result } = gen.next()) {
|
||||
if (isSymbolBaseline && !result.symbol) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastIndexWritten === undefined) {
|
||||
typeLines += codeLines.slice(0, result.line + 1).join("\r\n") + "\r\n";
|
||||
}
|
||||
else if (result.line !== lastIndexWritten) {
|
||||
if (!((lastIndexWritten + 1 < codeLines.length) && (codeLines[lastIndexWritten + 1].match(/^\s*[{|}]\s*$/) || codeLines[lastIndexWritten + 1].trim() === ""))) {
|
||||
typeLines += "\r\n";
|
||||
}
|
||||
typeLines += codeLines.slice(lastIndexWritten + 1, result.line + 1).join("\r\n") + "\r\n";
|
||||
}
|
||||
lastIndexWritten = result.line;
|
||||
const typeOrSymbolString = isSymbolBaseline ? result.symbol : result.type;
|
||||
const formattedLine = result.sourceText.replace(/\r?\n/g, "") + " : " + typeOrSymbolString;
|
||||
if (!typeMap[key]) {
|
||||
typeMap[key] = {};
|
||||
}
|
||||
typeLines += ">" + formattedLine + "\r\n";
|
||||
}
|
||||
|
||||
let typeInfo = [formattedLine];
|
||||
const existingTypeInfo = typeMap[key][result.line];
|
||||
if (existingTypeInfo) {
|
||||
typeInfo = existingTypeInfo.concat(typeInfo);
|
||||
}
|
||||
typeMap[key][result.line] = typeInfo;
|
||||
});
|
||||
|
||||
typeLines += "=== " + file.unitName + " ===\r\n";
|
||||
for (let i = 0; i < codeLines.length; i++) {
|
||||
const currentCodeLine = codeLines[i];
|
||||
typeLines += currentCodeLine + "\r\n";
|
||||
if (typeMap[key]) {
|
||||
const typeInfo = typeMap[key][i];
|
||||
if (typeInfo) {
|
||||
typeInfo.forEach(ty => {
|
||||
typeLines += ">" + ty + "\r\n";
|
||||
});
|
||||
if (i + 1 < codeLines.length && (codeLines[i + 1].match(/^\s*[{|}]\s*$/) || codeLines[i + 1].trim() === "")) {
|
||||
}
|
||||
else {
|
||||
typeLines += "\r\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Preserve legacy behavior
|
||||
if (lastIndexWritten === undefined) {
|
||||
for (let i = 0; i < codeLines.length; i++) {
|
||||
const currentCodeLine = codeLines[i];
|
||||
typeLines += currentCodeLine + "\r\n";
|
||||
typeLines += "No type information for this code.";
|
||||
}
|
||||
}
|
||||
yield [checkDuplicatedFileName(file.unitName, dupeCase), typeLines];
|
||||
typeLines = "";
|
||||
else {
|
||||
if (lastIndexWritten + 1 < codeLines.length) {
|
||||
if (!((lastIndexWritten + 1 < codeLines.length) && (codeLines[lastIndexWritten + 1].match(/^\s*[{|}]\s*$/) || codeLines[lastIndexWritten + 1].trim() === ""))) {
|
||||
typeLines += "\r\n";
|
||||
}
|
||||
typeLines += codeLines.slice(lastIndexWritten + 1).join("\r\n");
|
||||
}
|
||||
typeLines += "\r\n";
|
||||
}
|
||||
yield [checkDuplicatedFileName(unitName, dupeCase), typeLines];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1725,8 +1721,12 @@ namespace Harness {
|
||||
return resultName;
|
||||
}
|
||||
|
||||
function sanitizeTestFilePath(name: string) {
|
||||
return ts.normalizeSlashes(name.replace(/[\^<>:"|?*%]/g, "_")).replace(/\.\.\//g, "__dotdot/").toLowerCase();
|
||||
export function sanitizeTestFilePath(name: string) {
|
||||
const path = ts.toPath(ts.normalizeSlashes(name.replace(/[\^<>:"|?*%]/g, "_")).replace(/\.\.\//g, "__dotdot/"), "", Utils.canonicalizeForHarness);
|
||||
if (ts.startsWith(path, "/")) {
|
||||
return path.substring(1);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
// This does not need to exist strictly speaking, but many tests will need to be updated if it's removed
|
||||
@@ -2070,14 +2070,13 @@ namespace Harness {
|
||||
export function runMultifileBaseline(relativeFileBase: string, extension: string, generateContent: () => IterableIterator<[string, string, number]> | IterableIterator<[string, string]>, opts?: BaselineOptions, referencedExtensions?: string[]): void {
|
||||
const gen = generateContent();
|
||||
const writtenFiles = ts.createMap<true>();
|
||||
const canonicalize = ts.createGetCanonicalFileName(/*caseSensitive*/ false); // This is done so tests work on windows _and_ linux
|
||||
/* tslint:disable-next-line:no-null-keyword */
|
||||
const errors: Error[] = [];
|
||||
// tslint:disable-next-line:no-null-keyword
|
||||
if (gen !== null) {
|
||||
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
|
||||
const [name, content, count] = value as [string, string, number | undefined];
|
||||
if (count === 0) continue; // Allow error reporter to skip writing files without errors
|
||||
const relativeFileName = relativeFileBase + (ts.startsWith(name, "/") ? "" : "/") + name + extension;
|
||||
const relativeFileName = relativeFileBase + "/" + name + extension;
|
||||
const actualFileName = localPath(relativeFileName, opts && opts.Baselinefolder, opts && opts.Subfolder);
|
||||
const comparison = compareToBaseline(content, relativeFileName, opts);
|
||||
try {
|
||||
@@ -2086,8 +2085,7 @@ namespace Harness {
|
||||
catch (e) {
|
||||
errors.push(e);
|
||||
}
|
||||
const path = ts.toPath(relativeFileName, "", canonicalize);
|
||||
writtenFiles.set(path, true);
|
||||
writtenFiles.set(relativeFileName, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2100,8 +2098,7 @@ namespace Harness {
|
||||
const missing: string[] = [];
|
||||
for (const name of existing) {
|
||||
const localCopy = name.substring(referenceDir.length - relativeFileBase.length);
|
||||
const path = ts.toPath(localCopy, "", canonicalize);
|
||||
if (!writtenFiles.has(path)) {
|
||||
if (!writtenFiles.has(localCopy)) {
|
||||
missing.push(localCopy);
|
||||
}
|
||||
}
|
||||
@@ -2114,13 +2111,14 @@ namespace Harness {
|
||||
if (errors.length || missing.length) {
|
||||
let errorMsg = "";
|
||||
if (errors.length) {
|
||||
errorMsg += `The baseline for ${relativeFileBase} has changed:${"\n " + errors.map(e => e.message).join("\n ")}`;
|
||||
errorMsg += `The baseline for ${relativeFileBase} in ${errors.length} files has changed:${"\n " + errors.slice(0, 5).map(e => e.message).join("\n ") + (errors.length > 5 ? "\n" + ` and ${errors.length - 5} more` : "")}`;
|
||||
}
|
||||
if (errors.length && missing.length) {
|
||||
errorMsg += "\n";
|
||||
}
|
||||
if (missing.length) {
|
||||
errorMsg += `Baseline missing files:${"\n " + missing.join("\n ") + "\n"}Written:${"\n " + ts.arrayFrom(writtenFiles.keys()).join("\n ")}`;
|
||||
const writtenFilesArray = ts.arrayFrom(writtenFiles.keys());
|
||||
errorMsg += `Baseline missing ${missing.length} files:${"\n " + missing.slice(0, 5).join("\n ") + (missing.length > 5 ? "\n" + ` and ${missing.length - 5} more` : "") + "\n"}Written ${writtenFiles.size} files:${"\n " + writtenFilesArray.slice(0, 5).join("\n ") + (writtenFilesArray.length > 5 ? "\n" + ` and ${writtenFilesArray.length - 5} more` : "")}`;
|
||||
}
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
|
||||
@@ -855,8 +855,4 @@ namespace Harness.LanguageService {
|
||||
getClassifier(): ts.Classifier { throw new Error("getClassifier is not available using the server interface."); }
|
||||
getPreProcessedFileInfo(): ts.PreProcessedFileInfo { throw new Error("getPreProcessedFileInfo is not available using the server interface."); }
|
||||
}
|
||||
|
||||
export function mockHash(s: string): string {
|
||||
return `hash-${s}`;
|
||||
}
|
||||
}
|
||||
|
||||
+76
-6
@@ -5,8 +5,10 @@
|
||||
/// <reference path="..\..\src\harness\typeWriter.ts" />
|
||||
|
||||
interface FileInformation {
|
||||
contents: string;
|
||||
contents?: string;
|
||||
contentsPath?: string;
|
||||
codepage: number;
|
||||
bom?: string;
|
||||
}
|
||||
|
||||
interface FindFileResult {
|
||||
@@ -27,13 +29,15 @@ interface IOLog {
|
||||
filesRead: IOLogFile[];
|
||||
filesWritten: {
|
||||
path: string;
|
||||
contents: string;
|
||||
contents?: string;
|
||||
contentsPath?: string;
|
||||
bom: boolean;
|
||||
}[];
|
||||
filesDeleted: string[];
|
||||
filesAppended: {
|
||||
path: string;
|
||||
contents: string;
|
||||
contents?: string;
|
||||
contentsPath?: string;
|
||||
}[];
|
||||
fileExists: {
|
||||
path: string;
|
||||
@@ -129,6 +133,72 @@ namespace Playback {
|
||||
};
|
||||
}
|
||||
|
||||
export function newStyleLogIntoOldStyleLog(log: IOLog, host: ts.System | Harness.IO, baseName: string) {
|
||||
for (const file of log.filesAppended) {
|
||||
if (file.contentsPath) {
|
||||
file.contents = host.readFile(ts.combinePaths(baseName, file.contentsPath));
|
||||
delete file.contentsPath;
|
||||
}
|
||||
}
|
||||
for (const file of log.filesWritten) {
|
||||
if (file.contentsPath) {
|
||||
file.contents = host.readFile(ts.combinePaths(baseName, file.contentsPath));
|
||||
delete file.contentsPath;
|
||||
}
|
||||
}
|
||||
for (const file of log.filesRead) {
|
||||
if (file.result.contentsPath) {
|
||||
// `readFile` strips away a BOM (and actually reinerprets the file contents according to the correct encoding)
|
||||
// - but this has the unfortunate sideeffect of removing the BOM from any outputs based on the file, so we readd it here.
|
||||
file.result.contents = (file.result.bom || "") + host.readFile(ts.combinePaths(baseName, file.result.contentsPath));
|
||||
delete file.result.contentsPath;
|
||||
}
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
export function oldStyleLogIntoNewStyleLog(log: IOLog, writeFile: typeof Harness.IO.writeFile, baseTestName: string) {
|
||||
if (log.filesAppended) {
|
||||
for (const file of log.filesAppended) {
|
||||
if (file.contents !== undefined) {
|
||||
file.contentsPath = ts.combinePaths("appended", Harness.Compiler.sanitizeTestFilePath(file.path));
|
||||
writeFile(ts.combinePaths(baseTestName, file.contentsPath), file.contents);
|
||||
delete file.contents;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (log.filesWritten) {
|
||||
for (const file of log.filesWritten) {
|
||||
if (file.contents !== undefined) {
|
||||
file.contentsPath = ts.combinePaths("written", Harness.Compiler.sanitizeTestFilePath(file.path));
|
||||
writeFile(ts.combinePaths(baseTestName, file.contentsPath), file.contents);
|
||||
delete file.contents;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (log.filesRead) {
|
||||
for (const file of log.filesRead) {
|
||||
const { contents } = file.result;
|
||||
if (contents !== undefined) {
|
||||
file.result.contentsPath = ts.combinePaths("read", Harness.Compiler.sanitizeTestFilePath(file.path));
|
||||
writeFile(ts.combinePaths(baseTestName, file.result.contentsPath), contents);
|
||||
const len = contents.length;
|
||||
if (len >= 2 && contents.charCodeAt(0) === 0xfeff) {
|
||||
file.result.bom = "\ufeff";
|
||||
}
|
||||
if (len >= 2 && contents.charCodeAt(0) === 0xfffe) {
|
||||
file.result.bom = "\ufffe";
|
||||
}
|
||||
if (len >= 3 && contents.charCodeAt(0) === 0xefbb && contents.charCodeAt(1) === 0xbf) {
|
||||
file.result.bom = "\uefbb\xbf";
|
||||
}
|
||||
delete file.result.contents;
|
||||
}
|
||||
}
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
function initWrapper(wrapper: PlaybackSystem, underlying: ts.System): void;
|
||||
function initWrapper(wrapper: PlaybackIO, underlying: Harness.IO): void;
|
||||
function initWrapper(wrapper: PlaybackSystem | PlaybackIO, underlying: ts.System | Harness.IO): void {
|
||||
@@ -164,9 +234,9 @@ namespace Playback {
|
||||
wrapper.endRecord = () => {
|
||||
if (recordLog !== undefined) {
|
||||
let i = 0;
|
||||
const fn = () => recordLogFileNameBase + i + ".json";
|
||||
while (underlying.fileExists(fn())) i++;
|
||||
underlying.writeFile(fn(), JSON.stringify(recordLog));
|
||||
const fn = () => recordLogFileNameBase + i;
|
||||
while (underlying.fileExists(fn() + ".json")) i++;
|
||||
underlying.writeFile(ts.combinePaths(fn(), "test.json"), JSON.stringify(oldStyleLogIntoNewStyleLog(recordLog, (path, string) => underlying.writeFile(ts.combinePaths(fn(), path), string), fn()), null, 4)); // tslint:disable-line:no-null-keyword
|
||||
recordLog = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -26,9 +26,12 @@ namespace Harness.Parallel.Host {
|
||||
text?: string;
|
||||
}
|
||||
|
||||
const perfdataFileName = ".parallelperf.json";
|
||||
function readSavedPerfData(): {[testHash: string]: number} {
|
||||
const perfDataContents = Harness.IO.readFile(perfdataFileName);
|
||||
const perfdataFileNameFragment = ".parallelperf";
|
||||
function perfdataFileName(target?: string) {
|
||||
return `${perfdataFileNameFragment}${target ? `.${target}` : ""}.json`;
|
||||
}
|
||||
function readSavedPerfData(target?: string): {[testHash: string]: number} {
|
||||
const perfDataContents = Harness.IO.readFile(perfdataFileName(target));
|
||||
if (perfDataContents) {
|
||||
return JSON.parse(perfDataContents);
|
||||
}
|
||||
@@ -46,7 +49,7 @@ namespace Harness.Parallel.Host {
|
||||
const { statSync }: { statSync(path: string): { size: number }; } = require("fs");
|
||||
let tasks: { runner: TestRunnerKind, file: string, size: number }[] = [];
|
||||
const newTasks: { runner: TestRunnerKind, file: string, size: number }[] = [];
|
||||
const perfData = readSavedPerfData();
|
||||
const perfData = readSavedPerfData(configOption);
|
||||
let totalCost = 0;
|
||||
let unknownValue: string | undefined;
|
||||
for (const runner of runners) {
|
||||
@@ -54,8 +57,19 @@ namespace Harness.Parallel.Host {
|
||||
for (const file of files) {
|
||||
let size: number;
|
||||
if (!perfData) {
|
||||
size = statSync(file).size;
|
||||
|
||||
try {
|
||||
size = statSync(file).size;
|
||||
}
|
||||
catch {
|
||||
// May be a directory
|
||||
try {
|
||||
size = Harness.IO.listFiles(file, /.*/g, { recursive: true }).reduce((acc, elem) => acc + statSync(elem).size, 0);
|
||||
}
|
||||
catch {
|
||||
// Unknown test kind, just return 0 and let the historical analysis take over after one run
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const hashedName = hashName(runner.kind(), file);
|
||||
@@ -117,7 +131,7 @@ namespace Harness.Parallel.Host {
|
||||
child.on("message", (data: ParallelClientMessage) => {
|
||||
switch (data.type) {
|
||||
case "error": {
|
||||
console.error(`Test worker encounted unexpected error and was forced to close:
|
||||
console.error(`Test worker encounted unexpected error${data.payload.name ? ` during the execution of test ${data.payload.name}` : ""} and was forced to close:
|
||||
Message: ${data.payload.error}
|
||||
Stack: ${data.payload.stack}`);
|
||||
return process.exit(2);
|
||||
@@ -290,7 +304,7 @@ namespace Harness.Parallel.Host {
|
||||
reporter.epilogue();
|
||||
}
|
||||
|
||||
Harness.IO.writeFile(perfdataFileName, JSON.stringify(newPerfData, null, 4)); // tslint:disable-line:no-null-keyword
|
||||
Harness.IO.writeFile(perfdataFileName(configOption), JSON.stringify(newPerfData, null, 4)); // tslint:disable-line:no-null-keyword
|
||||
|
||||
process.exit(errorResults.length);
|
||||
}
|
||||
@@ -298,6 +312,9 @@ namespace Harness.Parallel.Host {
|
||||
function makeMochaTest(test: ErrorInfo) {
|
||||
return {
|
||||
fullTitle: () => {
|
||||
return test.name.join(" ");
|
||||
},
|
||||
titlePath: () => {
|
||||
return test.name;
|
||||
},
|
||||
err: {
|
||||
|
||||
@@ -6,8 +6,8 @@ namespace Harness.Parallel {
|
||||
export type ParallelCloseMessage = { type: "close" } | never;
|
||||
export type ParallelHostMessage = ParallelTestMessage | ParallelCloseMessage | ParallelBatchMessage;
|
||||
|
||||
export type ParallelErrorMessage = { type: "error", payload: { error: string, stack: string } } | never;
|
||||
export type ErrorInfo = ParallelErrorMessage["payload"] & { name: string };
|
||||
export type ParallelErrorMessage = { type: "error", payload: { error: string, stack: string, name?: string[] } } | never;
|
||||
export type ErrorInfo = ParallelErrorMessage["payload"] & { name: string[] };
|
||||
export type ParallelResultMessage = { type: "result", payload: { passing: number, errors: ErrorInfo[], duration: number, runner: TestRunnerKind, file: string } } | never;
|
||||
export type ParallelBatchProgressMessage = { type: "progress", payload: ParallelResultMessage["payload"] } | never;
|
||||
export type ParallelClientMessage = ParallelErrorMessage | ParallelResultMessage | ParallelBatchProgressMessage;
|
||||
|
||||
@@ -12,6 +12,11 @@ namespace Harness.Parallel.Worker {
|
||||
testList.length = 0;
|
||||
}
|
||||
reportedUnitTests = true;
|
||||
if (testList.length) {
|
||||
// Execute unit tests
|
||||
testList.forEach(({ name, callback, kind }) => executeCallback(name, callback, kind));
|
||||
testList.length = 0;
|
||||
}
|
||||
const start = +(new Date());
|
||||
runner.initializeTests();
|
||||
testList.forEach(({ name, callback, kind }) => executeCallback(name, callback, kind));
|
||||
@@ -53,17 +58,41 @@ namespace Harness.Parallel.Worker {
|
||||
const savedTestList = testList;
|
||||
|
||||
testList = [];
|
||||
callback.call(fakeContext);
|
||||
beforeFunc && beforeFunc();
|
||||
beforeFunc = undefined;
|
||||
try {
|
||||
callback.call(fakeContext);
|
||||
}
|
||||
catch (e) {
|
||||
errors.push({ error: `Error executing suite: ${e.message}`, stack: e.stack, name: [...namestack] });
|
||||
return cleanup();
|
||||
}
|
||||
try {
|
||||
beforeFunc && beforeFunc();
|
||||
}
|
||||
catch (e) {
|
||||
errors.push({ error: `Error executing before function: ${e.message}`, stack: e.stack, name: [...namestack] });
|
||||
return cleanup();
|
||||
}
|
||||
finally {
|
||||
beforeFunc = undefined;
|
||||
}
|
||||
testList.forEach(({ name, callback, kind }) => executeCallback(name, callback, kind));
|
||||
testList.length = 0;
|
||||
testList = savedTestList;
|
||||
|
||||
afterFunc && afterFunc();
|
||||
afterFunc = undefined;
|
||||
beforeEachFunc = savedBeforeEach;
|
||||
namestack.pop();
|
||||
try {
|
||||
afterFunc && afterFunc();
|
||||
}
|
||||
catch (e) {
|
||||
errors.push({ error: `Error executing after function: ${e.message}`, stack: e.stack, name: [...namestack] });
|
||||
}
|
||||
finally {
|
||||
afterFunc = undefined;
|
||||
cleanup();
|
||||
}
|
||||
function cleanup() {
|
||||
testList.length = 0;
|
||||
testList = savedTestList;
|
||||
beforeEachFunc = savedBeforeEach;
|
||||
namestack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
function executeCallback(name: string, callback: Function, kind: "suite" | "test") {
|
||||
@@ -82,13 +111,14 @@ namespace Harness.Parallel.Worker {
|
||||
retries() { return this; },
|
||||
slow() { return this; },
|
||||
};
|
||||
name = [...namestack, name].join(" ");
|
||||
namestack.push(name);
|
||||
if (beforeEachFunc) {
|
||||
try {
|
||||
beforeEachFunc();
|
||||
}
|
||||
catch (error) {
|
||||
errors.push({ error: error.message, stack: error.stack, name });
|
||||
errors.push({ error: error.message, stack: error.stack, name: [...namestack] });
|
||||
namestack.pop();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -98,9 +128,12 @@ namespace Harness.Parallel.Worker {
|
||||
callback.call(fakeContext);
|
||||
}
|
||||
catch (error) {
|
||||
errors.push({ error: error.message, stack: error.stack, name });
|
||||
errors.push({ error: error.message, stack: error.stack, name: [...namestack] });
|
||||
return;
|
||||
}
|
||||
finally {
|
||||
namestack.pop();
|
||||
}
|
||||
passing++;
|
||||
}
|
||||
else {
|
||||
@@ -112,7 +145,7 @@ namespace Harness.Parallel.Worker {
|
||||
throw new Error(`done() callback called multiple times; ensure it is only called once.`);
|
||||
}
|
||||
if (err) {
|
||||
errors.push({ error: err.toString(), stack: "", name });
|
||||
errors.push({ error: err.toString(), stack: "", name: [...namestack] });
|
||||
}
|
||||
else {
|
||||
passing++;
|
||||
@@ -121,11 +154,14 @@ namespace Harness.Parallel.Worker {
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
errors.push({ error: error.message, stack: error.stack, name });
|
||||
errors.push({ error: error.message, stack: error.stack, name: [...namestack] });
|
||||
return;
|
||||
}
|
||||
finally {
|
||||
namestack.pop();
|
||||
}
|
||||
if (!completed) {
|
||||
errors.push({ error: "Test completes asynchronously, which is unsupported by the parallel harness", stack: "", name });
|
||||
errors.push({ error: "Test completes asynchronously, which is unsupported by the parallel harness", stack: "", name: [...namestack] });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -172,7 +208,7 @@ namespace Harness.Parallel.Worker {
|
||||
}
|
||||
});
|
||||
process.on("uncaughtException", error => {
|
||||
const message: ParallelErrorMessage = { type: "error", payload: { error: error.message, stack: error.stack } };
|
||||
const message: ParallelErrorMessage = { type: "error", payload: { error: error.message, stack: error.stack, name: [...namestack] } };
|
||||
try {
|
||||
process.send(message);
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ class ProjectRunner extends RunnerBase {
|
||||
if (option) {
|
||||
const optType = option.type;
|
||||
let value = <any>testCase[name];
|
||||
if (typeof optType !== "string") {
|
||||
if (!ts.isString(optType)) {
|
||||
const key = value.toLowerCase();
|
||||
const optTypeValue = optType.get(key);
|
||||
if (optTypeValue) {
|
||||
|
||||
@@ -101,6 +101,7 @@ interface TaskSet {
|
||||
files: string[];
|
||||
}
|
||||
|
||||
let configOption: string;
|
||||
function handleTestConfig() {
|
||||
if (testConfigContent !== "") {
|
||||
const testConfig = <TestConfig>JSON.parse(testConfigContent);
|
||||
@@ -136,6 +137,13 @@ function handleTestConfig() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!configOption) {
|
||||
configOption = option;
|
||||
}
|
||||
else {
|
||||
configOption += "+" + option;
|
||||
}
|
||||
|
||||
switch (option) {
|
||||
case "compiler":
|
||||
runners.push(new CompilerBaselineRunner(CompilerTestType.Conformance));
|
||||
|
||||
@@ -36,9 +36,11 @@ namespace RWC {
|
||||
Subfolder: "rwc",
|
||||
Baselinefolder: "internal/baselines"
|
||||
};
|
||||
const baseName = /(.*)\/(.*).json/.exec(ts.normalizeSlashes(jsonPath))[2];
|
||||
const baseName = ts.getBaseFileName(jsonPath);
|
||||
let currentDirectory: string;
|
||||
let useCustomLibraryFile: boolean;
|
||||
let skipTypeAndSymbolbaselines = false;
|
||||
const typeAndSymbolSizeLimit = 10000000;
|
||||
after(() => {
|
||||
// Mocha holds onto the closure environment of the describe callback even after the test is done.
|
||||
// Therefore we have to clean out large objects after the test is done.
|
||||
@@ -52,15 +54,17 @@ namespace RWC {
|
||||
// or to use lib.d.ts inside the json object. If the flag is true, use the lib.d.ts inside json file
|
||||
// otherwise use the lib.d.ts from built/local
|
||||
useCustomLibraryFile = undefined;
|
||||
skipTypeAndSymbolbaselines = false;
|
||||
});
|
||||
|
||||
it("can compile", function(this: Mocha.ITestCallbackContext) {
|
||||
this.timeout(800000); // Allow long timeouts for RWC compilations
|
||||
let opts: ts.ParsedCommandLine;
|
||||
|
||||
const ioLog: IOLog = JSON.parse(Harness.IO.readFile(jsonPath));
|
||||
const ioLog: IOLog = Playback.newStyleLogIntoOldStyleLog(JSON.parse(Harness.IO.readFile(`internal/cases/rwc/${jsonPath}/test.json`)), Harness.IO, `internal/cases/rwc/${baseName}`);
|
||||
currentDirectory = ioLog.currentDirectory;
|
||||
useCustomLibraryFile = ioLog.useCustomLibraryFile;
|
||||
skipTypeAndSymbolbaselines = ioLog.filesRead.reduce((acc, elem) => (elem && elem.result && elem.result.contents) ? acc + elem.result.contents.length : acc, 0) > typeAndSymbolSizeLimit;
|
||||
runWithIOLog(ioLog, () => {
|
||||
opts = ts.parseCommandLine(ioLog.arguments, fileName => Harness.IO.readFile(fileName));
|
||||
assert.equal(opts.errors.length, 0);
|
||||
@@ -217,10 +221,10 @@ namespace RWC {
|
||||
|
||||
it("has the expected types", () => {
|
||||
// We don't need to pass the extension here because "doTypeAndSymbolBaseline" will append appropriate extension of ".types" or ".symbols"
|
||||
Harness.Compiler.doTypeAndSymbolBaseline(baseName, compilerResult, inputFiles
|
||||
Harness.Compiler.doTypeAndSymbolBaseline(baseName, compilerResult.program, inputFiles
|
||||
.concat(otherFiles)
|
||||
.filter(file => !!compilerResult.program.getSourceFile(file.unitName))
|
||||
.filter(e => !Harness.isDefaultLibraryFile(e.unitName)), baselineOpts, /*multifile*/ true);
|
||||
.filter(e => !Harness.isDefaultLibraryFile(e.unitName)), baselineOpts, /*multifile*/ true, skipTypeAndSymbolbaselines);
|
||||
});
|
||||
|
||||
// Ideally, a generated declaration file will have no errors. But we allow generated
|
||||
@@ -249,7 +253,7 @@ namespace RWC {
|
||||
|
||||
class RWCRunner extends RunnerBase {
|
||||
public enumerateTestFiles() {
|
||||
return Harness.IO.listFiles("internal/cases/rwc/", /.+\.json$/);
|
||||
return Harness.IO.getDirectories("internal/cases/rwc/");
|
||||
}
|
||||
|
||||
public kind(): TestRunnerKind {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
{
|
||||
"extends": "../tsconfig-base",
|
||||
"compilerOptions": {
|
||||
"removeComments": false,
|
||||
@@ -45,6 +45,7 @@
|
||||
"../compiler/declarationEmitter.ts",
|
||||
"../compiler/emitter.ts",
|
||||
"../compiler/program.ts",
|
||||
"../compiler/builder.ts",
|
||||
"../compiler/commandLineParser.ts",
|
||||
"../compiler/diagnosticInformationMap.generated.ts",
|
||||
"../services/breakpoints.ts",
|
||||
@@ -96,6 +97,7 @@
|
||||
"./parallel/host.ts",
|
||||
"./parallel/worker.ts",
|
||||
"runner.ts",
|
||||
"virtualFileSystemWithWatch.ts",
|
||||
"../server/protocol.ts",
|
||||
"../server/session.ts",
|
||||
"../server/client.ts",
|
||||
@@ -112,14 +114,15 @@
|
||||
"./unittests/convertToBase64.ts",
|
||||
"./unittests/transpile.ts",
|
||||
"./unittests/reuseProgramStructure.ts",
|
||||
"./unittests/cachingInServerLSHost.ts",
|
||||
"./unittests/moduleResolution.ts",
|
||||
"./unittests/tsconfigParsing.ts",
|
||||
"./unittests/builder.ts",
|
||||
"./unittests/commandLineParsing.ts",
|
||||
"./unittests/configurationExtension.ts",
|
||||
"./unittests/convertCompilerOptionsFromJson.ts",
|
||||
"./unittests/convertTypeAcquisitionFromJson.ts",
|
||||
"./unittests/tsserverProjectSystem.ts",
|
||||
"./unittests/tscWatchMode.ts",
|
||||
"./unittests/matchFiles.ts",
|
||||
"./unittests/initializeTSConfig.ts",
|
||||
"./unittests/compileOnSave.ts",
|
||||
@@ -128,10 +131,14 @@
|
||||
"./unittests/printer.ts",
|
||||
"./unittests/transform.ts",
|
||||
"./unittests/customTransforms.ts",
|
||||
"./unittests/extractMethods.ts",
|
||||
"./unittests/extractConstants.ts",
|
||||
"./unittests/extractFunctions.ts",
|
||||
"./unittests/extractRanges.ts",
|
||||
"./unittests/extractTestHelpers.ts",
|
||||
"./unittests/textChanges.ts",
|
||||
"./unittests/telemetry.ts",
|
||||
"./unittests/languageService.ts",
|
||||
"./unittests/programMissingFiles.ts"
|
||||
"./unittests/programMissingFiles.ts",
|
||||
"./unittests/publicApi.ts"
|
||||
]
|
||||
}
|
||||
|
||||
+84
-35
@@ -1,13 +1,26 @@
|
||||
interface TypeWriterResult {
|
||||
interface TypeWriterTypeResult {
|
||||
line: number;
|
||||
syntaxKind: number;
|
||||
sourceText: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
interface TypeWriterSymbolResult {
|
||||
line: number;
|
||||
syntaxKind: number;
|
||||
sourceText: string;
|
||||
symbol: string;
|
||||
}
|
||||
|
||||
interface TypeWriterResult {
|
||||
line: number;
|
||||
syntaxKind: number;
|
||||
sourceText: string;
|
||||
symbol?: string;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
class TypeWriterWalker {
|
||||
results: TypeWriterResult[];
|
||||
currentSourceFile: ts.SourceFile;
|
||||
|
||||
private checker: ts.TypeChecker;
|
||||
@@ -20,57 +33,93 @@ class TypeWriterWalker {
|
||||
: program.getTypeChecker();
|
||||
}
|
||||
|
||||
public getTypeAndSymbols(fileName: string): TypeWriterResult[] {
|
||||
public *getSymbols(fileName: string): IterableIterator<TypeWriterSymbolResult> {
|
||||
const sourceFile = this.program.getSourceFile(fileName);
|
||||
this.currentSourceFile = sourceFile;
|
||||
this.results = [];
|
||||
this.visitNode(sourceFile);
|
||||
return this.results;
|
||||
const gen = this.visitNode(sourceFile, /*isSymbolWalk*/ true);
|
||||
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
|
||||
yield value as TypeWriterSymbolResult;
|
||||
}
|
||||
}
|
||||
|
||||
private visitNode(node: ts.Node): void {
|
||||
public *getTypes(fileName: string): IterableIterator<TypeWriterTypeResult> {
|
||||
const sourceFile = this.program.getSourceFile(fileName);
|
||||
this.currentSourceFile = sourceFile;
|
||||
const gen = this.visitNode(sourceFile, /*isSymbolWalk*/ false);
|
||||
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
|
||||
yield value as TypeWriterTypeResult;
|
||||
}
|
||||
}
|
||||
|
||||
private *visitNode(node: ts.Node, isSymbolWalk: boolean): IterableIterator<TypeWriterResult> {
|
||||
if (ts.isPartOfExpression(node) || node.kind === ts.SyntaxKind.Identifier) {
|
||||
this.logTypeAndSymbol(node);
|
||||
const result = this.writeTypeOrSymbol(node, isSymbolWalk);
|
||||
if (result) {
|
||||
yield result;
|
||||
}
|
||||
}
|
||||
|
||||
ts.forEachChild(node, child => this.visitNode(child));
|
||||
const children: ts.Node[] = [];
|
||||
ts.forEachChild(node, child => void children.push(child));
|
||||
for (const child of children) {
|
||||
const gen = this.visitNode(child, isSymbolWalk);
|
||||
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
|
||||
yield value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private logTypeAndSymbol(node: ts.Node): void {
|
||||
private writeTypeOrSymbol(node: ts.Node, isSymbolWalk: boolean): TypeWriterResult {
|
||||
const actualPos = ts.skipTrivia(this.currentSourceFile.text, node.pos);
|
||||
const lineAndCharacter = this.currentSourceFile.getLineAndCharacterOfPosition(actualPos);
|
||||
const sourceText = ts.getTextOfNodeFromSourceText(this.currentSourceFile.text, node);
|
||||
|
||||
// Workaround to ensure we output 'C' instead of 'typeof C' for base class expressions
|
||||
// let type = this.checker.getTypeAtLocation(node);
|
||||
const type = node.parent && ts.isExpressionWithTypeArgumentsInClassExtendsClause(node.parent) && this.checker.getTypeAtLocation(node.parent) || this.checker.getTypeAtLocation(node);
|
||||
|
||||
ts.Debug.assert(type !== undefined, "type doesn't exist");
|
||||
const symbol = this.checker.getSymbolAtLocation(node);
|
||||
|
||||
const typeString = this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.NoTruncation);
|
||||
let symbolString: string;
|
||||
if (symbol) {
|
||||
symbolString = "Symbol(" + this.checker.symbolToString(symbol, node.parent);
|
||||
if (symbol.declarations) {
|
||||
for (const declaration of symbol.declarations) {
|
||||
symbolString += ", ";
|
||||
const declSourceFile = declaration.getSourceFile();
|
||||
const declLineAndCharacter = declSourceFile.getLineAndCharacterOfPosition(declaration.pos);
|
||||
const fileName = ts.getBaseFileName(declSourceFile.fileName);
|
||||
const isLibFile = /lib(.*)\.d\.ts/i.test(fileName);
|
||||
symbolString += `Decl(${ fileName }, ${ isLibFile ? "--" : declLineAndCharacter.line }, ${ isLibFile ? "--" : declLineAndCharacter.character })`;
|
||||
}
|
||||
}
|
||||
symbolString += ")";
|
||||
if (!isSymbolWalk) {
|
||||
// Workaround to ensure we output 'C' instead of 'typeof C' for base class expressions
|
||||
// let type = this.checker.getTypeAtLocation(node);
|
||||
const type = node.parent && ts.isExpressionWithTypeArgumentsInClassExtendsClause(node.parent) && this.checker.getTypeAtLocation(node.parent) || this.checker.getTypeAtLocation(node);
|
||||
const typeString = type ? this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.NoTruncation) : "No type information available!";
|
||||
return {
|
||||
line: lineAndCharacter.line,
|
||||
syntaxKind: node.kind,
|
||||
sourceText,
|
||||
type: typeString
|
||||
};
|
||||
}
|
||||
|
||||
this.results.push({
|
||||
const symbol = this.checker.getSymbolAtLocation(node);
|
||||
if (!symbol) {
|
||||
return;
|
||||
}
|
||||
let symbolString = "Symbol(" + this.checker.symbolToString(symbol, node.parent);
|
||||
if (symbol.declarations) {
|
||||
let count = 0;
|
||||
for (const declaration of symbol.declarations) {
|
||||
if (count >= 5) {
|
||||
symbolString += ` ... and ${symbol.declarations.length - count} more`;
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
symbolString += ", ";
|
||||
if ((declaration as any)["__symbolTestOutputCache"]) {
|
||||
symbolString += (declaration as any)["__symbolTestOutputCache"];
|
||||
continue;
|
||||
}
|
||||
const declSourceFile = declaration.getSourceFile();
|
||||
const declLineAndCharacter = declSourceFile.getLineAndCharacterOfPosition(declaration.pos);
|
||||
const fileName = ts.getBaseFileName(declSourceFile.fileName);
|
||||
const isLibFile = /lib(.*)\.d\.ts/i.test(fileName);
|
||||
const declText = `Decl(${ fileName }, ${ isLibFile ? "--" : declLineAndCharacter.line }, ${ isLibFile ? "--" : declLineAndCharacter.character })`;
|
||||
symbolString += declText;
|
||||
(declaration as any)["__symbolTestOutputCache"] = declText;
|
||||
}
|
||||
}
|
||||
symbolString += ")";
|
||||
return {
|
||||
line: lineAndCharacter.line,
|
||||
syntaxKind: node.kind,
|
||||
sourceText,
|
||||
type: typeString,
|
||||
symbol: symbolString
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/// <reference path="reuseProgramStructure.ts" />
|
||||
|
||||
namespace ts {
|
||||
describe("builder", () => {
|
||||
it("emits dependent files", () => {
|
||||
const files: NamedSourceText[] = [
|
||||
{ name: "/a.ts", text: SourceText.New("", 'import { b } from "./b";', "") },
|
||||
{ name: "/b.ts", text: SourceText.New("", ' import { c } from "./c";', "export const b = c;") },
|
||||
{ name: "/c.ts", text: SourceText.New("", "", "export const c = 0;") },
|
||||
];
|
||||
|
||||
let program = newProgram(files, ["/a.ts"], {});
|
||||
const assertChanges = makeAssertChanges(() => program);
|
||||
|
||||
assertChanges(["/c.js", "/b.js", "/a.js"]);
|
||||
|
||||
program = updateProgramFile(program, "/a.ts", "//comment");
|
||||
assertChanges(["/a.js"]);
|
||||
|
||||
program = updateProgramFile(program, "/b.ts", "export const b = c + 1;");
|
||||
assertChanges(["/b.js", "/a.js"]);
|
||||
|
||||
program = updateProgramFile(program, "/c.ts", "export const c = 1;");
|
||||
assertChanges(["/c.js", "/b.js"]);
|
||||
});
|
||||
|
||||
it("if emitting all files, emits the changed file first", () => {
|
||||
const files: NamedSourceText[] = [
|
||||
{ name: "/a.ts", text: SourceText.New("", "", "namespace A { export const x = 0; }") },
|
||||
{ name: "/b.ts", text: SourceText.New("", "", "namespace B { export const x = 0; }") },
|
||||
];
|
||||
|
||||
let program = newProgram(files, ["/a.ts", "/b.ts"], {});
|
||||
const assertChanges = makeAssertChanges(() => program);
|
||||
|
||||
assertChanges(["/a.js", "/b.js"]);
|
||||
|
||||
program = updateProgramFile(program, "/a.ts", "namespace A { export const x = 1; }");
|
||||
assertChanges(["/a.js", "/b.js"]);
|
||||
|
||||
program = updateProgramFile(program, "/b.ts", "namespace B { export const x = 1; }");
|
||||
assertChanges(["/b.js", "/a.js"]);
|
||||
});
|
||||
});
|
||||
|
||||
function makeAssertChanges(getProgram: () => Program): (fileNames: ReadonlyArray<string>) => void {
|
||||
const builder = createBuilder({
|
||||
getCanonicalFileName: identity,
|
||||
getEmitOutput: getFileEmitOutput,
|
||||
computeHash: identity,
|
||||
shouldEmitFile: returnTrue,
|
||||
});
|
||||
return fileNames => {
|
||||
const program = getProgram();
|
||||
builder.updateProgram(program);
|
||||
const changedFiles = builder.emitChangedFiles(program);
|
||||
assert.deepEqual(changedFileNames(changedFiles), fileNames);
|
||||
};
|
||||
}
|
||||
|
||||
function updateProgramFile(program: ProgramWithSourceTexts, fileName: string, fileContent: string): ProgramWithSourceTexts {
|
||||
return updateProgram(program, program.getRootFileNames(), program.getCompilerOptions(), files => {
|
||||
updateProgramText(files, fileName, fileContent);
|
||||
});
|
||||
}
|
||||
|
||||
function changedFileNames(changedFiles: ReadonlyArray<EmitOutputDetailed>): string[] {
|
||||
return changedFiles.map(f => {
|
||||
assert.lengthOf(f.outputFiles, 1);
|
||||
return f.outputFiles[0].name;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
/// <reference path="..\harness.ts" />
|
||||
|
||||
namespace ts {
|
||||
interface File {
|
||||
name: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
function createDefaultServerHost(fileMap: Map<File>): server.ServerHost {
|
||||
const existingDirectories = createMap<boolean>();
|
||||
forEachKey(fileMap, name => {
|
||||
let dir = getDirectoryPath(name);
|
||||
let previous: string;
|
||||
do {
|
||||
existingDirectories.set(dir, true);
|
||||
previous = dir;
|
||||
dir = getDirectoryPath(dir);
|
||||
} while (dir !== previous);
|
||||
});
|
||||
return {
|
||||
args: <string[]>[],
|
||||
newLine: "\r\n",
|
||||
useCaseSensitiveFileNames: false,
|
||||
write: noop,
|
||||
readFile: path => {
|
||||
const file = fileMap.get(path);
|
||||
return file && file.content;
|
||||
},
|
||||
writeFile: notImplemented,
|
||||
resolvePath: notImplemented,
|
||||
fileExists: path => fileMap.has(path),
|
||||
directoryExists: path => existingDirectories.get(path) || false,
|
||||
createDirectory: noop,
|
||||
getExecutingFilePath: () => "",
|
||||
getCurrentDirectory: () => "",
|
||||
getDirectories: () => [],
|
||||
getEnvironmentVariable: () => "",
|
||||
readDirectory: notImplemented,
|
||||
exit: noop,
|
||||
watchFile: () => ({
|
||||
close: noop
|
||||
}),
|
||||
watchDirectory: () => ({
|
||||
close: noop
|
||||
}),
|
||||
setTimeout,
|
||||
clearTimeout,
|
||||
setImmediate: typeof setImmediate !== "undefined" ? setImmediate : action => setTimeout(action, 0),
|
||||
clearImmediate: typeof clearImmediate !== "undefined" ? clearImmediate : clearTimeout,
|
||||
createHash: Harness.LanguageService.mockHash,
|
||||
};
|
||||
}
|
||||
|
||||
function createProject(rootFile: string, serverHost: server.ServerHost): { project: server.Project, rootScriptInfo: server.ScriptInfo } {
|
||||
const svcOpts: server.ProjectServiceOptions = {
|
||||
host: serverHost,
|
||||
logger: projectSystem.nullLogger,
|
||||
cancellationToken: { isCancellationRequested: () => false },
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined
|
||||
};
|
||||
const projectService = new server.ProjectService(svcOpts);
|
||||
const rootScriptInfo = projectService.getOrCreateScriptInfo(rootFile, /* openedByClient */ true, /*containingProject*/ undefined);
|
||||
|
||||
const project = projectService.createInferredProjectWithRootFileIfNecessary(rootScriptInfo);
|
||||
project.setCompilerOptions({ module: ts.ModuleKind.AMD, noLib: true } );
|
||||
return {
|
||||
project,
|
||||
rootScriptInfo
|
||||
};
|
||||
}
|
||||
|
||||
describe("Caching in LSHost", () => {
|
||||
it("works using legacy resolution logic", () => {
|
||||
const root: File = {
|
||||
name: "c:/d/f0.ts",
|
||||
content: `import {x} from "f1"`
|
||||
};
|
||||
|
||||
const imported: File = {
|
||||
name: "c:/f1.ts",
|
||||
content: `foo()`
|
||||
};
|
||||
|
||||
const serverHost = createDefaultServerHost(createMapFromTemplate({ [root.name]: root, [imported.name]: imported }));
|
||||
const { project, rootScriptInfo } = createProject(root.name, serverHost);
|
||||
|
||||
// ensure that imported file was found
|
||||
let diags = project.getLanguageService().getSemanticDiagnostics(imported.name);
|
||||
assert.equal(diags.length, 1);
|
||||
|
||||
|
||||
const originalFileExists = serverHost.fileExists;
|
||||
{
|
||||
// patch fileExists to make sure that disk is not touched
|
||||
serverHost.fileExists = notImplemented;
|
||||
|
||||
const newContent = `import {x} from "f1"
|
||||
var x: string = 1;`;
|
||||
rootScriptInfo.editContent(0, root.content.length, newContent);
|
||||
// trigger synchronization to make sure that import will be fetched from the cache
|
||||
diags = project.getLanguageService().getSemanticDiagnostics(imported.name);
|
||||
// ensure file has correct number of errors after edit
|
||||
assert.equal(diags.length, 1);
|
||||
}
|
||||
{
|
||||
let fileExistsIsCalled = false;
|
||||
serverHost.fileExists = (fileName): boolean => {
|
||||
if (fileName === "lib.d.ts") {
|
||||
return false;
|
||||
}
|
||||
fileExistsIsCalled = true;
|
||||
assert.isTrue(fileName.indexOf("/f2.") !== -1);
|
||||
return originalFileExists.call(serverHost, fileName);
|
||||
};
|
||||
const newContent = `import {x} from "f2"`;
|
||||
rootScriptInfo.editContent(0, root.content.length, newContent);
|
||||
|
||||
try {
|
||||
// trigger synchronization to make sure that LSHost will try to find 'f2' module on disk
|
||||
project.getLanguageService().getSemanticDiagnostics(imported.name);
|
||||
assert.isTrue(false, `should not find file '${imported.name}'`);
|
||||
}
|
||||
catch (e) {
|
||||
assert.isTrue(e.message.indexOf(`Could not find file: '${imported.name}'.`) === 0);
|
||||
}
|
||||
|
||||
assert.isTrue(fileExistsIsCalled);
|
||||
}
|
||||
{
|
||||
let fileExistsCalled = false;
|
||||
serverHost.fileExists = (fileName): boolean => {
|
||||
if (fileName === "lib.d.ts") {
|
||||
return false;
|
||||
}
|
||||
fileExistsCalled = true;
|
||||
assert.isTrue(fileName.indexOf("/f1.") !== -1);
|
||||
return originalFileExists.call(serverHost, fileName);
|
||||
};
|
||||
|
||||
const newContent = `import {x} from "f1"`;
|
||||
rootScriptInfo.editContent(0, root.content.length, newContent);
|
||||
project.getLanguageService().getSemanticDiagnostics(imported.name);
|
||||
assert.isTrue(fileExistsCalled);
|
||||
|
||||
// setting compiler options discards module resolution cache
|
||||
fileExistsCalled = false;
|
||||
|
||||
const compilerOptions = ts.cloneCompilerOptions(project.getCompilerOptions());
|
||||
compilerOptions.target = ts.ScriptTarget.ES5;
|
||||
project.setCompilerOptions(compilerOptions);
|
||||
|
||||
project.getLanguageService().getSemanticDiagnostics(imported.name);
|
||||
assert.isTrue(fileExistsCalled);
|
||||
}
|
||||
});
|
||||
|
||||
it("loads missing files from disk", () => {
|
||||
const root: File = {
|
||||
name: `c:/foo.ts`,
|
||||
content: `import {x} from "bar"`
|
||||
};
|
||||
|
||||
const imported: File = {
|
||||
name: `c:/bar.d.ts`,
|
||||
content: `export var y = 1`
|
||||
};
|
||||
|
||||
const fileMap = createMapFromTemplate({ [root.name]: root });
|
||||
const serverHost = createDefaultServerHost(fileMap);
|
||||
const originalFileExists = serverHost.fileExists;
|
||||
|
||||
let fileExistsCalledForBar = false;
|
||||
serverHost.fileExists = fileName => {
|
||||
if (fileName === "lib.d.ts") {
|
||||
return false;
|
||||
}
|
||||
if (!fileExistsCalledForBar) {
|
||||
fileExistsCalledForBar = fileName.indexOf("/bar.") !== -1;
|
||||
}
|
||||
|
||||
return originalFileExists.call(serverHost, fileName);
|
||||
};
|
||||
|
||||
const { project, rootScriptInfo } = createProject(root.name, serverHost);
|
||||
|
||||
let diags = project.getLanguageService().getSemanticDiagnostics(root.name);
|
||||
assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called");
|
||||
assert.isTrue(diags.length === 1, "one diagnostic expected");
|
||||
assert.isTrue(typeof diags[0].messageText === "string" && ((<string>diags[0].messageText).indexOf("Cannot find module") === 0), "should be 'cannot find module' message");
|
||||
|
||||
fileMap.set(imported.name, imported);
|
||||
fileExistsCalledForBar = false;
|
||||
rootScriptInfo.editContent(0, root.content.length, `import {y} from "bar"`);
|
||||
|
||||
diags = project.getLanguageService().getSemanticDiagnostics(root.name);
|
||||
assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called.");
|
||||
assert.isTrue(diags.length === 0, "The import should succeed once the imported file appears on disk.");
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -198,7 +198,6 @@ namespace ts.projectSystem {
|
||||
|
||||
file1Consumer1.content = `let y = 10;`;
|
||||
host.reloadFS([moduleFile1, file1Consumer1, file1Consumer2, configFile, libFile]);
|
||||
host.triggerFileWatcherCallback(file1Consumer1.path, FileWatcherEventKind.Changed);
|
||||
|
||||
session.executeCommand(changeModuleFile1ShapeRequest1);
|
||||
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer2] }]);
|
||||
@@ -215,7 +214,6 @@ namespace ts.projectSystem {
|
||||
session.executeCommand(changeModuleFile1ShapeRequest1);
|
||||
// Delete file1Consumer2
|
||||
host.reloadFS([moduleFile1, file1Consumer1, configFile, libFile]);
|
||||
host.triggerFileWatcherCallback(file1Consumer2.path, FileWatcherEventKind.Deleted);
|
||||
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1] }]);
|
||||
});
|
||||
|
||||
@@ -232,7 +230,6 @@ namespace ts.projectSystem {
|
||||
content: `import {Foo} from "./moduleFile1"; let y = Foo();`
|
||||
};
|
||||
host.reloadFS([moduleFile1, file1Consumer1, file1Consumer2, file1Consumer3, globalFile3, configFile, libFile]);
|
||||
host.triggerDirectoryWatcherCallback(ts.getDirectoryPath(file1Consumer3.path), file1Consumer3.path);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
session.executeCommand(changeModuleFile1ShapeRequest1);
|
||||
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2, file1Consumer3] }]);
|
||||
@@ -465,7 +462,6 @@ namespace ts.projectSystem {
|
||||
|
||||
openFilesForSession([referenceFile1], session);
|
||||
host.reloadFS([referenceFile1, configFile]);
|
||||
host.triggerFileWatcherCallback(moduleFile1.path, FileWatcherEventKind.Deleted);
|
||||
|
||||
const request = makeSessionRequest<server.protocol.FileRequestArgs>(CommandNames.CompileOnSaveAffectedFileList, { file: referenceFile1.path });
|
||||
sendAffectedFileRequestAndCheckResult(session, request, [
|
||||
@@ -593,4 +589,4 @@ namespace ts.projectSystem {
|
||||
assert.isTrue(outFileContent.indexOf(file3.content) === -1);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace ts {
|
||||
"/dev/tests/scenarios/first.json": "",
|
||||
"/dev/tests/baselines/first/output.ts": ""
|
||||
});
|
||||
const testContents = mapEntries(testContentsJson, (k, v) => [k, typeof v === "string" ? v : JSON.stringify(v)]);
|
||||
const testContents = mapEntries(testContentsJson, (k, v) => [k, isString(v) ? v : JSON.stringify(v)]);
|
||||
|
||||
const caseInsensitiveBasePath = "c:/dev/";
|
||||
const caseInsensitiveHost = new Utils.MockParseConfigHost(caseInsensitiveBasePath, /*useCaseSensitiveFileNames*/ false, mapEntries(testContents, (key, content) => [`c:${key}`, content]));
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
/// <reference path="extractTestHelpers.ts" />
|
||||
|
||||
namespace ts {
|
||||
describe("extractConstants", () => {
|
||||
testExtractConstant("extractConstant_TopLevel",
|
||||
`let x = [#|1|];`);
|
||||
|
||||
testExtractConstant("extractConstant_Namespace",
|
||||
`namespace N {
|
||||
let x = [#|1|];
|
||||
}`);
|
||||
|
||||
testExtractConstant("extractConstant_Class",
|
||||
`class C {
|
||||
x = [#|1|];
|
||||
}`);
|
||||
|
||||
testExtractConstant("extractConstant_Method",
|
||||
`class C {
|
||||
M() {
|
||||
let x = [#|1|];
|
||||
}
|
||||
}`);
|
||||
|
||||
testExtractConstant("extractConstant_Function",
|
||||
`function F() {
|
||||
let x = [#|1|];
|
||||
}`);
|
||||
|
||||
testExtractConstant("extractConstant_ExpressionStatement",
|
||||
`[#|"hello";|]`);
|
||||
|
||||
testExtractConstant("extractConstant_ExpressionStatementExpression",
|
||||
`[#|"hello"|];`);
|
||||
|
||||
testExtractConstant("extractConstant_ExpressionStatementInNestedScope", `
|
||||
let i = 0;
|
||||
function F() {
|
||||
[#|i++|];
|
||||
}
|
||||
`);
|
||||
|
||||
testExtractConstant("extractConstant_ExpressionStatementConsumesLocal", `
|
||||
function F() {
|
||||
let i = 0;
|
||||
[#|i++|];
|
||||
}
|
||||
`);
|
||||
|
||||
testExtractConstant("extractConstant_BlockScopes_NoDependencies",
|
||||
`for (let i = 0; i < 10; i++) {
|
||||
for (let j = 0; j < 10; j++) {
|
||||
let x = [#|1|];
|
||||
}
|
||||
}`);
|
||||
|
||||
testExtractConstant("extractConstant_ClassInsertionPosition1",
|
||||
`class C {
|
||||
a = 1;
|
||||
b = 2;
|
||||
M1() { }
|
||||
M2() { }
|
||||
M3() {
|
||||
let x = [#|1|];
|
||||
}
|
||||
}`);
|
||||
|
||||
testExtractConstant("extractConstant_ClassInsertionPosition2",
|
||||
`class C {
|
||||
a = 1;
|
||||
M1() { }
|
||||
b = 2;
|
||||
M2() { }
|
||||
M3() {
|
||||
let x = [#|1|];
|
||||
}
|
||||
}`);
|
||||
|
||||
testExtractConstant("extractConstant_ClassInsertionPosition3",
|
||||
`class C {
|
||||
M1() { }
|
||||
a = 1;
|
||||
b = 2;
|
||||
M2() { }
|
||||
M3() {
|
||||
let x = [#|1|];
|
||||
}
|
||||
}`);
|
||||
|
||||
testExtractConstant("extractConstant_Parameters",
|
||||
`function F() {
|
||||
let w = 1;
|
||||
let x = [#|w + 1|];
|
||||
}`);
|
||||
|
||||
testExtractConstant("extractConstant_TypeParameters",
|
||||
`function F<T>(t: T) {
|
||||
let x = [#|t + 1|];
|
||||
}`);
|
||||
|
||||
testExtractConstant("extractConstant_RepeatedSubstitution",
|
||||
`namespace X {
|
||||
export const j = 10;
|
||||
export const y = [#|j * j|];
|
||||
}`);
|
||||
|
||||
testExtractConstant("extractConstant_VariableList_const",
|
||||
`const a = 1, b = [#|a + 1|];`);
|
||||
|
||||
// NOTE: this test isn't normative - it just documents our sub-optimal behavior.
|
||||
testExtractConstant("extractConstant_VariableList_let",
|
||||
`let a = 1, b = [#|a + 1|];`);
|
||||
|
||||
// NOTE: this test isn't normative - it just documents our sub-optimal behavior.
|
||||
testExtractConstant("extractConstant_VariableList_MultipleLines",
|
||||
`const /*About A*/a = 1,
|
||||
/*About B*/b = [#|a + 1|];`);
|
||||
|
||||
testExtractConstant("extractConstant_BlockScopeMismatch", `
|
||||
for (let i = 0; i < 10; i++) {
|
||||
for (let j = 0; j < 10; j++) {
|
||||
const x = [#|i + 1|];
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
testExtractConstant("extractConstant_StatementInsertionPosition1", `
|
||||
const i = 0;
|
||||
for (let j = 0; j < 10; j++) {
|
||||
const x = [#|i + 1|];
|
||||
}
|
||||
`);
|
||||
|
||||
testExtractConstant("extractConstant_StatementInsertionPosition2", `
|
||||
const i = 0;
|
||||
function F() {
|
||||
for (let j = 0; j < 10; j++) {
|
||||
const x = [#|i + 1|];
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
testExtractConstant("extractConstant_StatementInsertionPosition3", `
|
||||
for (let j = 0; j < 10; j++) {
|
||||
const x = [#|2 + 1|];
|
||||
}
|
||||
`);
|
||||
|
||||
testExtractConstant("extractConstant_StatementInsertionPosition4", `
|
||||
function F() {
|
||||
for (let j = 0; j < 10; j++) {
|
||||
const x = [#|2 + 1|];
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
testExtractConstant("extractConstant_StatementInsertionPosition5", `
|
||||
function F0() {
|
||||
function F1() {
|
||||
function F2(x = [#|2 + 1|]) {
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
testExtractConstant("extractConstant_StatementInsertionPosition6", `
|
||||
class C {
|
||||
x = [#|2 + 1|];
|
||||
}
|
||||
`);
|
||||
|
||||
testExtractConstant("extractConstant_StatementInsertionPosition7", `
|
||||
const i = 0;
|
||||
class C {
|
||||
M() {
|
||||
for (let j = 0; j < 10; j++) {
|
||||
x = [#|i + 1|];
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
testExtractConstant("extractConstant_TripleSlash", `
|
||||
/// <reference path="path.js"/>
|
||||
|
||||
const x = [#|2 + 1|];
|
||||
`);
|
||||
|
||||
testExtractConstant("extractConstant_PinnedComment", `
|
||||
/*! Copyright */
|
||||
|
||||
const x = [#|2 + 1|];
|
||||
`);
|
||||
|
||||
testExtractConstant("extractConstant_Directive", `
|
||||
"strict";
|
||||
|
||||
const x = [#|2 + 1|];
|
||||
`);
|
||||
|
||||
testExtractConstant("extractConstant_MultipleHeaders", `
|
||||
/*! Copyright */
|
||||
|
||||
/// <reference path="path.js"/>
|
||||
|
||||
"strict";
|
||||
|
||||
const x = [#|2 + 1|];
|
||||
`);
|
||||
|
||||
testExtractConstant("extractConstant_PinnedCommentAndDocComment", `
|
||||
/*! Copyright */
|
||||
|
||||
/* About x */
|
||||
const x = [#|2 + 1|];
|
||||
`);
|
||||
|
||||
testExtractConstant("extractConstant_ArrowFunction_Block", `
|
||||
const f = () => {
|
||||
return [#|2 + 1|];
|
||||
};`);
|
||||
|
||||
testExtractConstant("extractConstant_ArrowFunction_Expression",
|
||||
`const f = () => [#|2 + 1|];`);
|
||||
|
||||
testExtractConstantFailed("extractConstant_Void", `
|
||||
function f(): void { }
|
||||
[#|f();|]`);
|
||||
|
||||
testExtractConstantFailed("extractConstant_Never", `
|
||||
function f(): never { }
|
||||
[#|f();|]`);
|
||||
});
|
||||
|
||||
function testExtractConstant(caption: string, text: string) {
|
||||
testExtractSymbol(caption, text, "extractConstant", Diagnostics.Extract_constant);
|
||||
}
|
||||
|
||||
function testExtractConstantFailed(caption: string, text: string) {
|
||||
testExtractSymbolFailed(caption, text, Diagnostics.Extract_constant);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,368 @@
|
||||
/// <reference path="extractTestHelpers.ts" />
|
||||
|
||||
namespace ts {
|
||||
describe("extractFunctions", () => {
|
||||
testExtractFunction("extractFunction1",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractFunction("extractFunction2",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractFunction("extractFunction3",
|
||||
`namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function* a(z: number) {
|
||||
[#|
|
||||
let y = 5;
|
||||
yield z;
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractFunction("extractFunction4",
|
||||
`namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
async function a(z: number, z1: any) {
|
||||
[#|
|
||||
let y = 5;
|
||||
if (z) {
|
||||
await z1;
|
||||
}
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractFunction("extractFunction5",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractFunction("extractFunction6",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractFunction("extractFunction7",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
export namespace C {
|
||||
export function foo() {
|
||||
}
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return C.foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractFunction("extractFunction9",
|
||||
`namespace A {
|
||||
export interface I { x: number };
|
||||
namespace B {
|
||||
function a() {
|
||||
[#|let a1: I = { x: 1 };
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractFunction("extractFunction10",
|
||||
`namespace A {
|
||||
export interface I { x: number };
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
[#|let a1: I = { x: 1 };
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractFunction("extractFunction11",
|
||||
`namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
[#|let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractFunction("extractFunction12",
|
||||
`namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
b() {}
|
||||
a() {
|
||||
let z = 1;
|
||||
[#|let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
this.b();
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
// The "b" type parameters aren't used and shouldn't be passed to the extracted function.
|
||||
// Type parameters should be in syntactic order (i.e. in order or character offset from BOF).
|
||||
// In all cases, we could use type inference, rather than passing explicit type arguments.
|
||||
// Note the inclusion of arrow functions to ensure that some type parameters are not from
|
||||
// targetable scopes.
|
||||
testExtractFunction("extractFunction13",
|
||||
`<U1a, U1b>(u1a: U1a, u1b: U1b) => {
|
||||
function F1<T1a, T1b>(t1a: T1a, t1b: T1b) {
|
||||
<U2a, U2b>(u2a: U2a, u2b: U2b) => {
|
||||
function F2<T2a, T2b>(t2a: T2a, t2b: T2b) {
|
||||
<U3a, U3b>(u3a: U3a, u3b: U3b) => {
|
||||
[#|t1a.toString();
|
||||
t2a.toString();
|
||||
u1a.toString();
|
||||
u2a.toString();
|
||||
u3a.toString();|]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`);
|
||||
// This test is descriptive, rather than normative. The current implementation
|
||||
// doesn't handle type parameter shadowing.
|
||||
testExtractFunction("extractFunction14",
|
||||
`function F<T>(t1: T) {
|
||||
function G<T>(t2: T) {
|
||||
[#|t1.toString();
|
||||
t2.toString();|]
|
||||
}
|
||||
}`);
|
||||
// Confirm that the constraint is preserved.
|
||||
testExtractFunction("extractFunction15",
|
||||
`function F<T>(t1: T) {
|
||||
function G<U extends T[]>(t2: U) {
|
||||
[#|t2.toString();|]
|
||||
}
|
||||
}`);
|
||||
// Confirm that the contextual type of an extracted expression counts as a use.
|
||||
testExtractFunction("extractFunction16",
|
||||
`function F<T>() {
|
||||
const array: T[] = [#|[]|];
|
||||
}`);
|
||||
// Class type parameter
|
||||
testExtractFunction("extractFunction17",
|
||||
`class C<T1, T2> {
|
||||
M(t1: T1, t2: T2) {
|
||||
[#|t1.toString()|];
|
||||
}
|
||||
}`);
|
||||
// Function type parameter
|
||||
testExtractFunction("extractFunction18",
|
||||
`class C {
|
||||
M<T1, T2>(t1: T1, t2: T2) {
|
||||
[#|t1.toString()|];
|
||||
}
|
||||
}`);
|
||||
// Coupled constraints
|
||||
testExtractFunction("extractFunction19",
|
||||
`function F<T, U extends T[], V extends U[]>(v: V) {
|
||||
[#|v.toString()|];
|
||||
}`);
|
||||
|
||||
testExtractFunction("extractFunction20",
|
||||
`const _ = class {
|
||||
a() {
|
||||
[#|let a1 = { x: 1 };
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}`);
|
||||
// Write + void return
|
||||
testExtractFunction("extractFunction21",
|
||||
`function foo() {
|
||||
let x = 10;
|
||||
[#|x++;
|
||||
return;|]
|
||||
}`);
|
||||
// Return in finally block
|
||||
testExtractFunction("extractFunction22",
|
||||
`function test() {
|
||||
try {
|
||||
}
|
||||
finally {
|
||||
[#|return 1;|]
|
||||
}
|
||||
}`);
|
||||
// Extraction position - namespace
|
||||
testExtractFunction("extractFunction23",
|
||||
`namespace NS {
|
||||
function M1() { }
|
||||
function M2() {
|
||||
[#|return 1;|]
|
||||
}
|
||||
function M3() { }
|
||||
}`);
|
||||
// Extraction position - function
|
||||
testExtractFunction("extractFunction24",
|
||||
`function Outer() {
|
||||
function M1() { }
|
||||
function M2() {
|
||||
[#|return 1;|]
|
||||
}
|
||||
function M3() { }
|
||||
}`);
|
||||
// Extraction position - file
|
||||
testExtractFunction("extractFunction25",
|
||||
`function M1() { }
|
||||
function M2() {
|
||||
[#|return 1;|]
|
||||
}
|
||||
function M3() { }`);
|
||||
// Extraction position - class without ctor
|
||||
testExtractFunction("extractFunction26",
|
||||
`class C {
|
||||
M1() { }
|
||||
M2() {
|
||||
[#|return 1;|]
|
||||
}
|
||||
M3() { }
|
||||
}`);
|
||||
// Extraction position - class with ctor in middle
|
||||
testExtractFunction("extractFunction27",
|
||||
`class C {
|
||||
M1() { }
|
||||
M2() {
|
||||
[#|return 1;|]
|
||||
}
|
||||
constructor() { }
|
||||
M3() { }
|
||||
}`);
|
||||
// Extraction position - class with ctor at end
|
||||
testExtractFunction("extractFunction28",
|
||||
`class C {
|
||||
M1() { }
|
||||
M2() {
|
||||
[#|return 1;|]
|
||||
}
|
||||
M3() { }
|
||||
constructor() { }
|
||||
}`);
|
||||
// Shorthand property names
|
||||
testExtractFunction("extractFunction29",
|
||||
`interface UnaryExpression {
|
||||
kind: "Unary";
|
||||
operator: string;
|
||||
operand: any;
|
||||
}
|
||||
|
||||
function parseUnaryExpression(operator: string): UnaryExpression {
|
||||
[#|return {
|
||||
kind: "Unary",
|
||||
operator,
|
||||
operand: parsePrimaryExpression(),
|
||||
};|]
|
||||
}
|
||||
|
||||
function parsePrimaryExpression(): any {
|
||||
throw "Not implemented";
|
||||
}`);
|
||||
// Type parameter as declared type
|
||||
testExtractFunction("extractFunction30",
|
||||
`function F<T>() {
|
||||
[#|let t: T;|]
|
||||
}`);
|
||||
// Return in nested function
|
||||
testExtractFunction("extractFunction31",
|
||||
`namespace N {
|
||||
|
||||
export const value = 1;
|
||||
|
||||
() => {
|
||||
var f: () => number;
|
||||
[#|f = function (): number {
|
||||
return value;
|
||||
}|]
|
||||
}
|
||||
}`);
|
||||
// Return in nested class
|
||||
testExtractFunction("extractFunction32",
|
||||
`namespace N {
|
||||
|
||||
export const value = 1;
|
||||
|
||||
() => {
|
||||
[#|var c = class {
|
||||
M() {
|
||||
return value;
|
||||
}
|
||||
}|]
|
||||
}
|
||||
}`);
|
||||
// Selection excludes leading trivia of declaration
|
||||
testExtractFunction("extractFunction33",
|
||||
`function F() {
|
||||
[#|function G() { }|]
|
||||
}`);
|
||||
|
||||
testExtractFunction("extractFunction_RepeatedSubstitution",
|
||||
`namespace X {
|
||||
export const j = 10;
|
||||
export const y = [#|j * j|];
|
||||
}`);
|
||||
});
|
||||
|
||||
function testExtractFunction(caption: string, text: string) {
|
||||
testExtractSymbol(caption, text, "extractFunction", Diagnostics.Extract_function);
|
||||
}
|
||||
}
|
||||
@@ -1,823 +0,0 @@
|
||||
/// <reference path="..\harness.ts" />
|
||||
/// <reference path="tsserverProjectSystem.ts" />
|
||||
|
||||
namespace ts {
|
||||
interface Range {
|
||||
start: number;
|
||||
end: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface Test {
|
||||
source: string;
|
||||
ranges: Map<Range>;
|
||||
}
|
||||
|
||||
function extractTest(source: string): Test {
|
||||
const activeRanges: Range[] = [];
|
||||
let text = "";
|
||||
let lastPos = 0;
|
||||
let pos = 0;
|
||||
const ranges = createMap<Range>();
|
||||
|
||||
while (pos < source.length) {
|
||||
if (source.charCodeAt(pos) === CharacterCodes.openBracket &&
|
||||
(source.charCodeAt(pos + 1) === CharacterCodes.hash || source.charCodeAt(pos + 1) === CharacterCodes.$)) {
|
||||
const saved = pos;
|
||||
pos += 2;
|
||||
const s = pos;
|
||||
consumeIdentifier();
|
||||
const e = pos;
|
||||
if (source.charCodeAt(pos) === CharacterCodes.bar) {
|
||||
pos++;
|
||||
text += source.substring(lastPos, saved);
|
||||
const name = s === e
|
||||
? source.charCodeAt(saved + 1) === CharacterCodes.hash ? "selection" : "extracted"
|
||||
: source.substring(s, e);
|
||||
activeRanges.push({ name, start: text.length, end: undefined });
|
||||
lastPos = pos;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
pos = saved;
|
||||
}
|
||||
}
|
||||
else if (source.charCodeAt(pos) === CharacterCodes.bar && source.charCodeAt(pos + 1) === CharacterCodes.closeBracket) {
|
||||
text += source.substring(lastPos, pos);
|
||||
activeRanges[activeRanges.length - 1].end = text.length;
|
||||
const range = activeRanges.pop();
|
||||
if (range.name in ranges) {
|
||||
throw new Error(`Duplicate name of range ${range.name}`);
|
||||
}
|
||||
ranges.set(range.name, range);
|
||||
pos += 2;
|
||||
lastPos = pos;
|
||||
continue;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
text += source.substring(lastPos, pos);
|
||||
|
||||
function consumeIdentifier() {
|
||||
while (isIdentifierPart(source.charCodeAt(pos), ScriptTarget.Latest)) {
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
return { source: text, ranges };
|
||||
}
|
||||
|
||||
const newLineCharacter = "\n";
|
||||
function getRuleProvider(action?: (opts: FormatCodeSettings) => void) {
|
||||
const options = {
|
||||
indentSize: 4,
|
||||
tabSize: 4,
|
||||
newLineCharacter,
|
||||
convertTabsToSpaces: true,
|
||||
indentStyle: ts.IndentStyle.Smart,
|
||||
insertSpaceAfterConstructor: false,
|
||||
insertSpaceAfterCommaDelimiter: true,
|
||||
insertSpaceAfterSemicolonInForStatements: true,
|
||||
insertSpaceBeforeAndAfterBinaryOperators: true,
|
||||
insertSpaceAfterKeywordsInControlFlowStatements: true,
|
||||
insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
|
||||
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
|
||||
insertSpaceBeforeFunctionParenthesis: false,
|
||||
placeOpenBraceOnNewLineForFunctions: false,
|
||||
placeOpenBraceOnNewLineForControlBlocks: false,
|
||||
};
|
||||
if (action) {
|
||||
action(options);
|
||||
}
|
||||
const rulesProvider = new formatting.RulesProvider();
|
||||
rulesProvider.ensureUpToDate(options);
|
||||
return rulesProvider;
|
||||
}
|
||||
|
||||
function testExtractRangeFailed(caption: string, s: string, expectedErrors: string[]) {
|
||||
return it(caption, () => {
|
||||
const t = extractTest(s);
|
||||
const file = createSourceFile("a.ts", t.source, ScriptTarget.Latest, /*setParentNodes*/ true);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${s} does not specify selection range`);
|
||||
}
|
||||
const result = refactor.extractMethod.getRangeToExtract(file, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
assert(result.targetRange === undefined, "failure expected");
|
||||
const sortedErrors = result.errors.map(e => <string>e.messageText).sort();
|
||||
assert.deepEqual(sortedErrors, expectedErrors.sort(), "unexpected errors");
|
||||
});
|
||||
}
|
||||
|
||||
function testExtractRange(s: string): void {
|
||||
const t = extractTest(s);
|
||||
const f = createSourceFile("a.ts", t.source, ScriptTarget.Latest, /*setParentNodes*/ true);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${s} does not specify selection range`);
|
||||
}
|
||||
const result = refactor.extractMethod.getRangeToExtract(f, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
const expectedRange = t.ranges.get("extracted");
|
||||
if (expectedRange) {
|
||||
let start: number, end: number;
|
||||
if (ts.isArray(result.targetRange.range)) {
|
||||
start = result.targetRange.range[0].getStart(f);
|
||||
end = ts.lastOrUndefined(result.targetRange.range).getEnd();
|
||||
}
|
||||
else {
|
||||
start = result.targetRange.range.getStart(f);
|
||||
end = result.targetRange.range.getEnd();
|
||||
}
|
||||
assert.equal(start, expectedRange.start, "incorrect start of range");
|
||||
assert.equal(end, expectedRange.end, "incorrect end of range");
|
||||
}
|
||||
else {
|
||||
assert.isTrue(!result.targetRange, `expected range to extract to be undefined`);
|
||||
}
|
||||
}
|
||||
|
||||
describe("extractMethods", () => {
|
||||
it("get extract range from selection", () => {
|
||||
testExtractRange(`
|
||||
[#|
|
||||
[$|var x = 1;
|
||||
var y = 2;|]|]
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
var x = 1;
|
||||
var y = 2|];
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|var x = 1|];
|
||||
var y = 2;
|
||||
`);
|
||||
testExtractRange(`
|
||||
if ([#|[#extracted|a && b && c && d|]|]) {
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
if [#|(a && b && c && d|]) {
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
if (a && b && c && d) {
|
||||
[#| [$|var x = 1;
|
||||
console.log(x);|] |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
if (a) {
|
||||
return 100;
|
||||
} |]
|
||||
`);
|
||||
testExtractRange(`
|
||||
function foo() {
|
||||
[#| [$|if (a) {
|
||||
}
|
||||
return 100|] |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
[$|l1:
|
||||
if (x) {
|
||||
break l1;
|
||||
}|]|]
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
[$|l2:
|
||||
{
|
||||
if (x) {
|
||||
}
|
||||
break l2;
|
||||
}|]|]
|
||||
`);
|
||||
testExtractRange(`
|
||||
while (true) {
|
||||
[#| if(x) {
|
||||
}
|
||||
break; |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
while (true) {
|
||||
[#| if(x) {
|
||||
}
|
||||
continue; |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
l3:
|
||||
{
|
||||
[#|
|
||||
if (x) {
|
||||
}
|
||||
break l3; |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
if (x) {
|
||||
return;
|
||||
} |]
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
[$|if (x) {
|
||||
}
|
||||
return;|]
|
||||
|]
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
return [#| [$|1 + 2|] |]+ 3;
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
return [$|1 + [#|2 + 3|]|];
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
return [$|1 + 2 + [#|3 + 4|]|];
|
||||
}
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed1",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
return 10;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional return statement."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed2",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
break;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional break or continue statements."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed3",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
continue;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional break or continue statements."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed4",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
l1: {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
break l1;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing labeled break or continue with target outside of the range."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed5",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
[#|
|
||||
try {
|
||||
f2()
|
||||
return 10;
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
|]
|
||||
}
|
||||
function f2() {
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional return statement."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed6",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
[#|
|
||||
try {
|
||||
f2()
|
||||
}
|
||||
catch (e) {
|
||||
return 10;
|
||||
}
|
||||
|]
|
||||
}
|
||||
function f2() {
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional return statement."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed7",
|
||||
`
|
||||
function test(x: number) {
|
||||
while (x) {
|
||||
x--;
|
||||
[#|break;|]
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional break or continue statements."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed8",
|
||||
`
|
||||
function test(x: number) {
|
||||
switch (x) {
|
||||
case 1:
|
||||
[#|break;|]
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional break or continue statements."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed9",
|
||||
`var x = ([#||]1 + 2);`,
|
||||
[
|
||||
"Statement or expression expected."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extract-method-not-for-token-expression-statement", `[#|a|]`, ["Select more than a single identifier."]);
|
||||
|
||||
testExtractMethod("extractMethod1",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod2",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod3",
|
||||
`namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function* a(z: number) {
|
||||
[#|
|
||||
let y = 5;
|
||||
yield z;
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod4",
|
||||
`namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
async function a(z: number, z1: any) {
|
||||
[#|
|
||||
let y = 5;
|
||||
if (z) {
|
||||
await z1;
|
||||
}
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod5",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod6",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod7",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
export namespace C {
|
||||
export function foo() {
|
||||
}
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return C.foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod8",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
namespace B {
|
||||
function a() {
|
||||
let a1 = 1;
|
||||
return 1 + [#|a1 + x|] + 100;
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod9",
|
||||
`namespace A {
|
||||
export interface I { x: number };
|
||||
namespace B {
|
||||
function a() {
|
||||
[#|let a1: I = { x: 1 };
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod10",
|
||||
`namespace A {
|
||||
export interface I { x: number };
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
[#|let a1: I = { x: 1 };
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod11",
|
||||
`namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
[#|let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod12",
|
||||
`namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
b() {}
|
||||
a() {
|
||||
let z = 1;
|
||||
[#|let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
this.b();
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
// The "b" type parameters aren't used and shouldn't be passed to the extracted function.
|
||||
// Type parameters should be in syntactic order (i.e. in order or character offset from BOF).
|
||||
// In all cases, we could use type inference, rather than passing explicit type arguments.
|
||||
// Note the inclusion of arrow functions to ensure that some type parameters are not from
|
||||
// targetable scopes.
|
||||
testExtractMethod("extractMethod13",
|
||||
`<U1a, U1b>(u1a: U1a, u1b: U1b) => {
|
||||
function F1<T1a, T1b>(t1a: T1a, t1b: T1b) {
|
||||
<U2a, U2b>(u2a: U2a, u2b: U2b) => {
|
||||
function F2<T2a, T2b>(t2a: T2a, t2b: T2b) {
|
||||
<U3a, U3b>(u3a: U3a, u3b: U3b) => {
|
||||
[#|t1a.toString();
|
||||
t2a.toString();
|
||||
u1a.toString();
|
||||
u2a.toString();
|
||||
u3a.toString();|]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`);
|
||||
// This test is descriptive, rather than normative. The current implementation
|
||||
// doesn't handle type parameter shadowing.
|
||||
testExtractMethod("extractMethod14",
|
||||
`function F<T>(t1: T) {
|
||||
function F<T>(t2: T) {
|
||||
[#|t1.toString();
|
||||
t2.toString();|]
|
||||
}
|
||||
}`);
|
||||
// Confirm that the constraint is preserved.
|
||||
testExtractMethod("extractMethod15",
|
||||
`function F<T>(t1: T) {
|
||||
function F<U extends T[]>(t2: U) {
|
||||
[#|t2.toString();|]
|
||||
}
|
||||
}`);
|
||||
// Confirm that the contextual type of an extracted expression counts as a use.
|
||||
testExtractMethod("extractMethod16",
|
||||
`function F<T>() {
|
||||
const array: T[] = [#|[]|];
|
||||
}`);
|
||||
// Class type parameter
|
||||
testExtractMethod("extractMethod17",
|
||||
`class C<T1, T2> {
|
||||
M(t1: T1, t2: T2) {
|
||||
[#|t1.toString()|];
|
||||
}
|
||||
}`);
|
||||
// Method type parameter
|
||||
testExtractMethod("extractMethod18",
|
||||
`class C {
|
||||
M<T1, T2>(t1: T1, t2: T2) {
|
||||
[#|t1.toString()|];
|
||||
}
|
||||
}`);
|
||||
// Coupled constraints
|
||||
testExtractMethod("extractMethod19",
|
||||
`function F<T, U extends T[], V extends U[]>(v: V) {
|
||||
[#|v.toString()|];
|
||||
}`);
|
||||
|
||||
testExtractMethod("extractMethod20",
|
||||
`const _ = class {
|
||||
a() {
|
||||
[#|let a1 = { x: 1 };
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}`);
|
||||
// Write + void return
|
||||
testExtractMethod("extractMethod21",
|
||||
`function foo() {
|
||||
let x = 10;
|
||||
[#|x++;
|
||||
return;|]
|
||||
}`);
|
||||
// Return in finally block
|
||||
testExtractMethod("extractMethod22",
|
||||
`function test() {
|
||||
try {
|
||||
}
|
||||
finally {
|
||||
[#|return 1;|]
|
||||
}
|
||||
}`);
|
||||
// Extraction position - namespace
|
||||
testExtractMethod("extractMethod23",
|
||||
`namespace NS {
|
||||
function M1() { }
|
||||
function M2() {
|
||||
[#|return 1;|]
|
||||
}
|
||||
function M3() { }
|
||||
}`);
|
||||
// Extraction position - function
|
||||
testExtractMethod("extractMethod24",
|
||||
`function Outer() {
|
||||
function M1() { }
|
||||
function M2() {
|
||||
[#|return 1;|]
|
||||
}
|
||||
function M3() { }
|
||||
}`);
|
||||
// Extraction position - file
|
||||
testExtractMethod("extractMethod25",
|
||||
`function M1() { }
|
||||
function M2() {
|
||||
[#|return 1;|]
|
||||
}
|
||||
function M3() { }`);
|
||||
// Extraction position - class without ctor
|
||||
testExtractMethod("extractMethod26",
|
||||
`class C {
|
||||
M1() { }
|
||||
M2() {
|
||||
[#|return 1;|]
|
||||
}
|
||||
M3() { }
|
||||
}`);
|
||||
// Extraction position - class with ctor in middle
|
||||
testExtractMethod("extractMethod27",
|
||||
`class C {
|
||||
M1() { }
|
||||
M2() {
|
||||
[#|return 1;|]
|
||||
}
|
||||
constructor() { }
|
||||
M3() { }
|
||||
}`);
|
||||
// Extraction position - class with ctor at end
|
||||
testExtractMethod("extractMethod28",
|
||||
`class C {
|
||||
M1() { }
|
||||
M2() {
|
||||
[#|return 1;|]
|
||||
}
|
||||
M3() { }
|
||||
constructor() { }
|
||||
}`);
|
||||
// Shorthand property names
|
||||
testExtractMethod("extractMethod29",
|
||||
`interface UnaryExpression {
|
||||
kind: "Unary";
|
||||
operator: string;
|
||||
operand: any;
|
||||
}
|
||||
|
||||
function parseUnaryExpression(operator: string): UnaryExpression {
|
||||
[#|return {
|
||||
kind: "Unary",
|
||||
operator,
|
||||
operand: parsePrimaryExpression(),
|
||||
};|]
|
||||
}
|
||||
|
||||
function parsePrimaryExpression(): any {
|
||||
throw "Not implemented";
|
||||
}`);
|
||||
// Type parameter as declared type
|
||||
testExtractMethod("extractMethod30",
|
||||
`function F<T>() {
|
||||
[#|let t: T;|]
|
||||
}`);
|
||||
// Return in nested function
|
||||
testExtractMethod("extractMethod31",
|
||||
`namespace N {
|
||||
|
||||
export const value = 1;
|
||||
|
||||
() => {
|
||||
var f: () => number;
|
||||
[#|f = function (): number {
|
||||
return value;
|
||||
}|]
|
||||
}
|
||||
}`);
|
||||
// Return in nested class
|
||||
testExtractMethod("extractMethod32",
|
||||
`namespace N {
|
||||
|
||||
export const value = 1;
|
||||
|
||||
() => {
|
||||
[#|var c = class {
|
||||
M() {
|
||||
return value;
|
||||
}
|
||||
}|]
|
||||
}
|
||||
}`);
|
||||
// Selection excludes leading trivia of declaration
|
||||
testExtractMethod("extractMethod33",
|
||||
`function F() {
|
||||
[#|function G() { }|]
|
||||
}`);
|
||||
});
|
||||
|
||||
|
||||
function testExtractMethod(caption: string, text: string) {
|
||||
it(caption, () => {
|
||||
Harness.Baseline.runBaseline(`extractMethod/${caption}.ts`, () => {
|
||||
const t = extractTest(text);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${caption} does not specify selection range`);
|
||||
}
|
||||
const f = {
|
||||
path: "/a.ts",
|
||||
content: t.source
|
||||
};
|
||||
const host = projectSystem.createServerHost([f, projectSystem.libFile]);
|
||||
const projectService = projectSystem.createProjectService(host);
|
||||
projectService.openClientFile(f.path);
|
||||
const program = projectService.inferredProjects[0].getLanguageService().getProgram();
|
||||
const sourceFile = program.getSourceFile(f.path);
|
||||
const context: RefactorContext = {
|
||||
cancellationToken: { throwIfCancellationRequested() { }, isCancellationRequested() { return false; } },
|
||||
newLineCharacter,
|
||||
program,
|
||||
file: sourceFile,
|
||||
startPosition: -1,
|
||||
rulesProvider: getRuleProvider()
|
||||
};
|
||||
const result = refactor.extractMethod.getRangeToExtract(sourceFile, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
assert.equal(result.errors, undefined, "expect no errors");
|
||||
const results = refactor.extractMethod.getPossibleExtractions(result.targetRange, context);
|
||||
const data: string[] = [];
|
||||
data.push(`// ==ORIGINAL==`);
|
||||
data.push(sourceFile.text);
|
||||
for (const r of results) {
|
||||
const { renameLocation, edits } = refactor.extractMethod.getExtractionAtIndex(result.targetRange, context, results.indexOf(r));
|
||||
assert.lengthOf(edits, 1);
|
||||
data.push(`// ==SCOPE::${r.scopeDescription}==`);
|
||||
const newText = textChanges.applyChanges(sourceFile.text, edits[0].textChanges);
|
||||
const newTextWithRename = newText.slice(0, renameLocation) + "/*RENAME*/" + newText.slice(renameLocation);
|
||||
data.push(newTextWithRename);
|
||||
}
|
||||
return data.join(newLineCharacter);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,318 @@
|
||||
/// <reference path="extractTestHelpers.ts" />
|
||||
|
||||
namespace ts {
|
||||
function testExtractRangeFailed(caption: string, s: string, expectedErrors: string[]) {
|
||||
return it(caption, () => {
|
||||
const t = extractTest(s);
|
||||
const file = createSourceFile("a.ts", t.source, ScriptTarget.Latest, /*setParentNodes*/ true);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${s} does not specify selection range`);
|
||||
}
|
||||
const result = refactor.extractSymbol.getRangeToExtract(file, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
assert(result.targetRange === undefined, "failure expected");
|
||||
const sortedErrors = result.errors.map(e => <string>e.messageText).sort();
|
||||
assert.deepEqual(sortedErrors, expectedErrors.sort(), "unexpected errors");
|
||||
});
|
||||
}
|
||||
|
||||
function testExtractRange(s: string): void {
|
||||
const t = extractTest(s);
|
||||
const f = createSourceFile("a.ts", t.source, ScriptTarget.Latest, /*setParentNodes*/ true);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${s} does not specify selection range`);
|
||||
}
|
||||
const result = refactor.extractSymbol.getRangeToExtract(f, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
const expectedRange = t.ranges.get("extracted");
|
||||
if (expectedRange) {
|
||||
let start: number, end: number;
|
||||
if (ts.isArray(result.targetRange.range)) {
|
||||
start = result.targetRange.range[0].getStart(f);
|
||||
end = ts.lastOrUndefined(result.targetRange.range).getEnd();
|
||||
}
|
||||
else {
|
||||
start = result.targetRange.range.getStart(f);
|
||||
end = result.targetRange.range.getEnd();
|
||||
}
|
||||
assert.equal(start, expectedRange.start, "incorrect start of range");
|
||||
assert.equal(end, expectedRange.end, "incorrect end of range");
|
||||
}
|
||||
else {
|
||||
assert.isTrue(!result.targetRange, `expected range to extract to be undefined`);
|
||||
}
|
||||
}
|
||||
|
||||
describe("extractRanges", () => {
|
||||
it("get extract range from selection", () => {
|
||||
testExtractRange(`
|
||||
[#|
|
||||
[$|var x = 1;
|
||||
var y = 2;|]|]
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
var x = 1;
|
||||
var y = 2|];
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|var x = 1|];
|
||||
var y = 2;
|
||||
`);
|
||||
testExtractRange(`
|
||||
if ([#|[#extracted|a && b && c && d|]|]) {
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
if [#|(a && b && c && d|]) {
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
if (a && b && c && d) {
|
||||
[#| [$|var x = 1;
|
||||
console.log(x);|] |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
if (a) {
|
||||
return 100;
|
||||
} |]
|
||||
`);
|
||||
testExtractRange(`
|
||||
function foo() {
|
||||
[#| [$|if (a) {
|
||||
}
|
||||
return 100|] |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
[$|l1:
|
||||
if (x) {
|
||||
break l1;
|
||||
}|]|]
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
[$|l2:
|
||||
{
|
||||
if (x) {
|
||||
}
|
||||
break l2;
|
||||
}|]|]
|
||||
`);
|
||||
testExtractRange(`
|
||||
while (true) {
|
||||
[#| if(x) {
|
||||
}
|
||||
break; |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
while (true) {
|
||||
[#| if(x) {
|
||||
}
|
||||
continue; |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
l3:
|
||||
{
|
||||
[#|
|
||||
if (x) {
|
||||
}
|
||||
break l3; |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
if (x) {
|
||||
return;
|
||||
} |]
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
[$|if (x) {
|
||||
}
|
||||
return;|]
|
||||
|]
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
return [#| [$|1 + 2|] |]+ 3;
|
||||
}
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed1",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
return 10;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalReturnStatement.message
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed2",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
break;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalBreakOrContinueStatements.message
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed3",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
continue;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalBreakOrContinueStatements.message
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed4",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
l1: {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
break l1;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
refactor.extractSymbol.Messages.CannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange.message
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed5",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
[#|
|
||||
try {
|
||||
f2()
|
||||
return 10;
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
|]
|
||||
}
|
||||
function f2() {
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalReturnStatement.message
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed6",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
[#|
|
||||
try {
|
||||
f2()
|
||||
}
|
||||
catch (e) {
|
||||
return 10;
|
||||
}
|
||||
|]
|
||||
}
|
||||
function f2() {
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalReturnStatement.message
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed7",
|
||||
`
|
||||
function test(x: number) {
|
||||
while (x) {
|
||||
x--;
|
||||
[#|break;|]
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalBreakOrContinueStatements.message
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed8",
|
||||
`
|
||||
function test(x: number) {
|
||||
switch (x) {
|
||||
case 1:
|
||||
[#|break;|]
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalBreakOrContinueStatements.message
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed9",
|
||||
`var x = ([#||]1 + 2);`,
|
||||
[
|
||||
refactor.extractSymbol.Messages.CannotExtractEmpty.message
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed10",
|
||||
`
|
||||
function f() {
|
||||
return 1 + [#|2 + 3|];
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
refactor.extractSymbol.Messages.CannotExtractRange.message
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extract-method-not-for-token-expression-statement", `[#|a|]`, [refactor.extractSymbol.Messages.CannotExtractIdentifier.message]);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
/// <reference path="..\harness.ts" />
|
||||
/// <reference path="tsserverProjectSystem.ts" />
|
||||
|
||||
namespace ts {
|
||||
export interface Range {
|
||||
start: number;
|
||||
end: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface Test {
|
||||
source: string;
|
||||
ranges: Map<Range>;
|
||||
}
|
||||
|
||||
export function extractTest(source: string): Test {
|
||||
const activeRanges: Range[] = [];
|
||||
let text = "";
|
||||
let lastPos = 0;
|
||||
let pos = 0;
|
||||
const ranges = createMap<Range>();
|
||||
|
||||
while (pos < source.length) {
|
||||
if (source.charCodeAt(pos) === CharacterCodes.openBracket &&
|
||||
(source.charCodeAt(pos + 1) === CharacterCodes.hash || source.charCodeAt(pos + 1) === CharacterCodes.$)) {
|
||||
const saved = pos;
|
||||
pos += 2;
|
||||
const s = pos;
|
||||
consumeIdentifier();
|
||||
const e = pos;
|
||||
if (source.charCodeAt(pos) === CharacterCodes.bar) {
|
||||
pos++;
|
||||
text += source.substring(lastPos, saved);
|
||||
const name = s === e
|
||||
? source.charCodeAt(saved + 1) === CharacterCodes.hash ? "selection" : "extracted"
|
||||
: source.substring(s, e);
|
||||
activeRanges.push({ name, start: text.length, end: undefined });
|
||||
lastPos = pos;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
pos = saved;
|
||||
}
|
||||
}
|
||||
else if (source.charCodeAt(pos) === CharacterCodes.bar && source.charCodeAt(pos + 1) === CharacterCodes.closeBracket) {
|
||||
text += source.substring(lastPos, pos);
|
||||
activeRanges[activeRanges.length - 1].end = text.length;
|
||||
const range = activeRanges.pop();
|
||||
if (range.name in ranges) {
|
||||
throw new Error(`Duplicate name of range ${range.name}`);
|
||||
}
|
||||
ranges.set(range.name, range);
|
||||
pos += 2;
|
||||
lastPos = pos;
|
||||
continue;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
text += source.substring(lastPos, pos);
|
||||
|
||||
function consumeIdentifier() {
|
||||
while (isIdentifierPart(source.charCodeAt(pos), ScriptTarget.Latest)) {
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
return { source: text, ranges };
|
||||
}
|
||||
|
||||
export const newLineCharacter = "\n";
|
||||
export function getRuleProvider(action?: (opts: FormatCodeSettings) => void) {
|
||||
const options = {
|
||||
indentSize: 4,
|
||||
tabSize: 4,
|
||||
newLineCharacter,
|
||||
convertTabsToSpaces: true,
|
||||
indentStyle: ts.IndentStyle.Smart,
|
||||
insertSpaceAfterConstructor: false,
|
||||
insertSpaceAfterCommaDelimiter: true,
|
||||
insertSpaceAfterSemicolonInForStatements: true,
|
||||
insertSpaceBeforeAndAfterBinaryOperators: true,
|
||||
insertSpaceAfterKeywordsInControlFlowStatements: true,
|
||||
insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
|
||||
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
|
||||
insertSpaceBeforeFunctionParenthesis: false,
|
||||
placeOpenBraceOnNewLineForFunctions: false,
|
||||
placeOpenBraceOnNewLineForControlBlocks: false,
|
||||
};
|
||||
if (action) {
|
||||
action(options);
|
||||
}
|
||||
const rulesProvider = new formatting.RulesProvider();
|
||||
rulesProvider.ensureUpToDate(options);
|
||||
return rulesProvider;
|
||||
}
|
||||
|
||||
export function testExtractSymbol(caption: string, text: string, baselineFolder: string, description: DiagnosticMessage) {
|
||||
const t = extractTest(text);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${caption} does not specify selection range`);
|
||||
}
|
||||
|
||||
[Extension.Ts, Extension.Js].forEach(extension =>
|
||||
it(`${caption} [${extension}]`, () => runBaseline(extension)));
|
||||
|
||||
function runBaseline(extension: Extension) {
|
||||
const path = "/a" + extension;
|
||||
const program = makeProgram({ path, content: t.source });
|
||||
|
||||
if (hasSyntacticDiagnostics(program)) {
|
||||
// Don't bother generating JS baselines for inputs that aren't valid JS.
|
||||
assert.equal(Extension.Js, extension, "Syntactic diagnostics found in non-JS file");
|
||||
return;
|
||||
}
|
||||
|
||||
const sourceFile = program.getSourceFile(path);
|
||||
const context: RefactorContext = {
|
||||
cancellationToken: { throwIfCancellationRequested() { }, isCancellationRequested() { return false; } },
|
||||
newLineCharacter,
|
||||
program,
|
||||
file: sourceFile,
|
||||
startPosition: selectionRange.start,
|
||||
endPosition: selectionRange.end,
|
||||
rulesProvider: getRuleProvider()
|
||||
};
|
||||
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
assert.equal(rangeToExtract.errors, undefined, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText);
|
||||
const infos = refactor.extractSymbol.getAvailableActions(context);
|
||||
const actions = find(infos, info => info.description === description.message).actions;
|
||||
|
||||
Harness.Baseline.runBaseline(`${baselineFolder}/${caption}${extension}`, () => {
|
||||
const data: string[] = [];
|
||||
data.push(`// ==ORIGINAL==`);
|
||||
data.push(text.replace("[#|", "/*[#|*/").replace("|]", "/*|]*/"));
|
||||
for (const action of actions) {
|
||||
const { renameLocation, edits } = refactor.extractSymbol.getEditsForAction(context, action.name);
|
||||
assert.lengthOf(edits, 1);
|
||||
data.push(`// ==SCOPE::${action.description}==`);
|
||||
const newText = textChanges.applyChanges(sourceFile.text, edits[0].textChanges);
|
||||
const newTextWithRename = newText.slice(0, renameLocation) + "/*RENAME*/" + newText.slice(renameLocation);
|
||||
data.push(newTextWithRename);
|
||||
|
||||
const diagProgram = makeProgram({ path, content: newText });
|
||||
assert.isFalse(hasSyntacticDiagnostics(diagProgram));
|
||||
}
|
||||
return data.join(newLineCharacter);
|
||||
});
|
||||
}
|
||||
|
||||
function makeProgram(f: {path: string, content: string }) {
|
||||
const host = projectSystem.createServerHost([f, projectSystem.libFile]);
|
||||
const projectService = projectSystem.createProjectService(host);
|
||||
projectService.openClientFile(f.path);
|
||||
const program = projectService.inferredProjects[0].getLanguageService().getProgram();
|
||||
return program;
|
||||
}
|
||||
|
||||
function hasSyntacticDiagnostics(program: Program) {
|
||||
const diags = program.getSyntacticDiagnostics();
|
||||
return length(diags) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
export function testExtractSymbolFailed(caption: string, text: string, description: DiagnosticMessage) {
|
||||
it(caption, () => {
|
||||
const t = extractTest(text);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${caption} does not specify selection range`);
|
||||
}
|
||||
const f = {
|
||||
path: "/a.ts",
|
||||
content: t.source
|
||||
};
|
||||
const host = projectSystem.createServerHost([f, projectSystem.libFile]);
|
||||
const projectService = projectSystem.createProjectService(host);
|
||||
projectService.openClientFile(f.path);
|
||||
const program = projectService.inferredProjects[0].getLanguageService().getProgram();
|
||||
const sourceFile = program.getSourceFile(f.path);
|
||||
const context: RefactorContext = {
|
||||
cancellationToken: { throwIfCancellationRequested() { }, isCancellationRequested() { return false; } },
|
||||
newLineCharacter,
|
||||
program,
|
||||
file: sourceFile,
|
||||
startPosition: selectionRange.start,
|
||||
endPosition: selectionRange.end,
|
||||
rulesProvider: getRuleProvider()
|
||||
};
|
||||
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
assert.isUndefined(rangeToExtract.errors, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText);
|
||||
const infos = refactor.extractSymbol.getAvailableActions(context);
|
||||
assert.isUndefined(find(infos, info => info.description === description.message));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -144,6 +144,11 @@ namespace ts {
|
||||
`/**
|
||||
* @type
|
||||
*/`);
|
||||
|
||||
parsesIncorrectly("@augments with no type",
|
||||
`/**
|
||||
* @augments
|
||||
*/`);
|
||||
});
|
||||
|
||||
describe("parsesCorrectly", () => {
|
||||
@@ -295,6 +300,11 @@ namespace ts {
|
||||
* @property {number} age
|
||||
* @property {string} name
|
||||
*/`);
|
||||
parsesCorrectly("less-than and greater-than characters",
|
||||
`/**
|
||||
* @param x hi
|
||||
< > still part of the previous comment
|
||||
*/`);
|
||||
});
|
||||
});
|
||||
describe("getFirstToken", () => {
|
||||
|
||||
@@ -110,6 +110,31 @@ namespace ts {
|
||||
createSourceFile("source.ts", "", ScriptTarget.ES2015)
|
||||
));
|
||||
|
||||
printsCorrectly("newExpressionWithPropertyAccessOnCallExpression", {}, printer => printer.printNode(
|
||||
EmitHint.Unspecified,
|
||||
createNew(
|
||||
createPropertyAccess(
|
||||
createCall(
|
||||
createIdentifier("f"), /*typeArguments*/ undefined, /*argumentsArray*/ undefined),
|
||||
"x"),
|
||||
/*typeArguments*/ undefined,
|
||||
/*argumentsArray*/ undefined
|
||||
),
|
||||
createSourceFile("source.ts", "", ScriptTarget.ESNext))
|
||||
);
|
||||
|
||||
printsCorrectly("newExpressionOnConditionalExpression", {}, printer => printer.printNode(
|
||||
EmitHint.Unspecified,
|
||||
createNew(
|
||||
createConditional(
|
||||
createIdentifier("x"), createToken(SyntaxKind.QuestionToken),
|
||||
createIdentifier("y"), createToken(SyntaxKind.ColonToken),
|
||||
createIdentifier("z")),
|
||||
/*typeArguments*/ undefined,
|
||||
/*argumentsArray*/ undefined
|
||||
),
|
||||
createSourceFile("source.ts", "", ScriptTarget.ESNext))
|
||||
);
|
||||
|
||||
printsCorrectly("emptyGlobalAugmentation", {}, printer => printer.printNode(
|
||||
EmitHint.Unspecified,
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/// <reference path="..\harness.ts" />
|
||||
|
||||
namespace ts {
|
||||
function verifyMissingFilePaths(missingPaths: ReadonlyArray<Path>, expected: ReadonlyArray<string>) {
|
||||
assert.isDefined(missingPaths);
|
||||
const map = arrayToSet(expected) as Map<boolean>;
|
||||
for (const missing of missingPaths) {
|
||||
const value = map.get(missing);
|
||||
assert.isTrue(value, `${missing} to be ${value === undefined ? "not present" : "present only once"}, in actual: ${missingPaths} expected: ${expected}`);
|
||||
map.set(missing, false);
|
||||
}
|
||||
const notFound = mapDefinedIter(map.keys(), k => map.get(k) === true ? k : undefined);
|
||||
assert.equal(notFound.length, 0, `Not found ${notFound} in actual: ${missingPaths} expected: ${expected}`);
|
||||
}
|
||||
|
||||
describe("Program.getMissingFilePaths", () => {
|
||||
|
||||
const options: CompilerOptions = {
|
||||
@@ -40,34 +52,31 @@ namespace ts {
|
||||
it("handles no missing root files", () => {
|
||||
const program = createProgram([emptyFileRelativePath], options, testCompilerHost);
|
||||
const missing = program.getMissingFilePaths();
|
||||
assert.isDefined(missing);
|
||||
assert.deepEqual(missing, []);
|
||||
verifyMissingFilePaths(missing, []);
|
||||
});
|
||||
|
||||
it("handles missing root file", () => {
|
||||
const program = createProgram(["./nonexistent.ts"], options, testCompilerHost);
|
||||
const missing = program.getMissingFilePaths();
|
||||
assert.isDefined(missing);
|
||||
assert.deepEqual(missing, ["d:/pretend/nonexistent.ts" as Path]); // Absolute path
|
||||
verifyMissingFilePaths(missing, ["d:/pretend/nonexistent.ts"]); // Absolute path
|
||||
});
|
||||
|
||||
it("handles multiple missing root files", () => {
|
||||
const program = createProgram(["./nonexistent0.ts", "./nonexistent1.ts"], options, testCompilerHost);
|
||||
const missing = program.getMissingFilePaths().slice().sort();
|
||||
assert.deepEqual(missing, ["d:/pretend/nonexistent0.ts", "d:/pretend/nonexistent1.ts"]);
|
||||
const missing = program.getMissingFilePaths();
|
||||
verifyMissingFilePaths(missing, ["d:/pretend/nonexistent0.ts", "d:/pretend/nonexistent1.ts"]);
|
||||
});
|
||||
|
||||
it("handles a mix of present and missing root files", () => {
|
||||
const program = createProgram(["./nonexistent0.ts", emptyFileRelativePath, "./nonexistent1.ts"], options, testCompilerHost);
|
||||
const missing = program.getMissingFilePaths().slice().sort();
|
||||
assert.deepEqual(missing, ["d:/pretend/nonexistent0.ts", "d:/pretend/nonexistent1.ts"]);
|
||||
const missing = program.getMissingFilePaths();
|
||||
verifyMissingFilePaths(missing, ["d:/pretend/nonexistent0.ts", "d:/pretend/nonexistent1.ts"]);
|
||||
});
|
||||
|
||||
it("handles repeatedly specified root files", () => {
|
||||
const program = createProgram(["./nonexistent.ts", "./nonexistent.ts"], options, testCompilerHost);
|
||||
const missing = program.getMissingFilePaths();
|
||||
assert.isDefined(missing);
|
||||
assert.deepEqual(missing, ["d:/pretend/nonexistent.ts" as Path]);
|
||||
verifyMissingFilePaths(missing, ["d:/pretend/nonexistent.ts"]);
|
||||
});
|
||||
|
||||
it("normalizes file paths", () => {
|
||||
@@ -81,9 +90,8 @@ namespace ts {
|
||||
|
||||
it("handles missing triple slash references", () => {
|
||||
const program = createProgram([referenceFileRelativePath], options, testCompilerHost);
|
||||
const missing = program.getMissingFilePaths().slice().sort();
|
||||
assert.isDefined(missing);
|
||||
assert.deepEqual(missing, [
|
||||
const missing = program.getMissingFilePaths();
|
||||
verifyMissingFilePaths(missing, [
|
||||
// From absolute reference
|
||||
"d:/imaginary/nonexistent1.ts",
|
||||
|
||||
@@ -100,4 +108,4 @@ namespace ts {
|
||||
]);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,19 +20,34 @@ namespace ts.projectSystem {
|
||||
}
|
||||
}
|
||||
|
||||
function checkDiagnosticsWithLinePos(errors: server.protocol.DiagnosticWithLinePosition[], expectedErrors: string[]) {
|
||||
assert.equal(errors ? errors.length : 0, expectedErrors.length, `expected ${expectedErrors.length} error in the list`);
|
||||
if (expectedErrors.length) {
|
||||
zipWith(errors, expectedErrors, ({ message: actualMessage }, expectedMessage) => {
|
||||
assert.isTrue(startsWith(actualMessage, actualMessage), `error message does not match, expected ${actualMessage} to start with ${expectedMessage}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
it("external project - diagnostics for missing files", () => {
|
||||
const file1 = {
|
||||
path: "/a/b/app.ts",
|
||||
content: ""
|
||||
};
|
||||
const file2 = {
|
||||
path: "/a/b/lib.ts",
|
||||
path: "/a/b/applib.ts",
|
||||
content: ""
|
||||
};
|
||||
// only file1 exists - expect error
|
||||
const host = createServerHost([file1]);
|
||||
const projectService = createProjectService(host);
|
||||
const host = createServerHost([file1, libFile]);
|
||||
const session = createSession(host);
|
||||
const projectService = session.getProjectService();
|
||||
const projectFileName = "/a/b/test.csproj";
|
||||
const compilerOptionsRequest: server.protocol.CompilerOptionsDiagnosticsRequest = {
|
||||
type: "request",
|
||||
command: server.CommandNames.CompilerOptionsDiagnosticsFull,
|
||||
seq: 2,
|
||||
arguments: { projectFileName }
|
||||
};
|
||||
|
||||
{
|
||||
projectService.openExternalProject({
|
||||
@@ -41,35 +56,25 @@ namespace ts.projectSystem {
|
||||
rootFiles: toExternalFiles([file1.path, file2.path])
|
||||
});
|
||||
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
const knownProjects = projectService.synchronizeProjectList([]);
|
||||
checkProjectErrors(knownProjects[0], ["File '/a/b/lib.ts' not found."]);
|
||||
checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
const diags = session.executeCommand(compilerOptionsRequest).response;
|
||||
// only file1 exists - expect error
|
||||
checkDiagnosticsWithLinePos(diags, ["File '/a/b/applib.ts' not found."]);
|
||||
}
|
||||
// only file2 exists - expect error
|
||||
host.reloadFS([file2]);
|
||||
host.reloadFS([file2, libFile]);
|
||||
{
|
||||
projectService.openExternalProject({
|
||||
projectFileName,
|
||||
options: {},
|
||||
rootFiles: toExternalFiles([file1.path, file2.path])
|
||||
});
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
const knownProjects = projectService.synchronizeProjectList([]);
|
||||
checkProjectErrors(knownProjects[0], ["File '/a/b/app.ts' not found."]);
|
||||
// only file2 exists - expect error
|
||||
checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
const diags = session.executeCommand(compilerOptionsRequest).response;
|
||||
checkDiagnosticsWithLinePos(diags, ["File '/a/b/app.ts' not found."]);
|
||||
}
|
||||
|
||||
// both files exist - expect no errors
|
||||
host.reloadFS([file1, file2]);
|
||||
host.reloadFS([file1, file2, libFile]);
|
||||
{
|
||||
projectService.openExternalProject({
|
||||
projectFileName,
|
||||
options: {},
|
||||
rootFiles: toExternalFiles([file1.path, file2.path])
|
||||
});
|
||||
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
const knownProjects = projectService.synchronizeProjectList([]);
|
||||
checkProjectErrors(knownProjects[0], []);
|
||||
// both files exist - expect no errors
|
||||
checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
const diags = session.executeCommand(compilerOptionsRequest).response;
|
||||
checkDiagnosticsWithLinePos(diags, []);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -79,25 +84,33 @@ namespace ts.projectSystem {
|
||||
content: ""
|
||||
};
|
||||
const file2 = {
|
||||
path: "/a/b/lib.ts",
|
||||
path: "/a/b/applib.ts",
|
||||
content: ""
|
||||
};
|
||||
const config = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: JSON.stringify({ files: [file1, file2].map(f => getBaseFileName(f.path)) })
|
||||
};
|
||||
const host = createServerHost([file1, config]);
|
||||
const projectService = createProjectService(host);
|
||||
const host = createServerHost([file1, config, libFile]);
|
||||
const session = createSession(host);
|
||||
const projectService = session.getProjectService();
|
||||
openFilesForSession([file1], session);
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
const project = configuredProjectAt(projectService, 0);
|
||||
const compilerOptionsRequest: server.protocol.CompilerOptionsDiagnosticsRequest = {
|
||||
type: "request",
|
||||
command: server.CommandNames.CompilerOptionsDiagnosticsFull,
|
||||
seq: 2,
|
||||
arguments: { projectFileName: project.getProjectName() }
|
||||
};
|
||||
let diags = session.executeCommand(compilerOptionsRequest).response;
|
||||
checkDiagnosticsWithLinePos(diags, ["File '/a/b/applib.ts' not found."]);
|
||||
|
||||
projectService.openClientFile(file1.path);
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
checkProjectErrors(projectService.synchronizeProjectList([])[0], ["File '/a/b/lib.ts' not found."]);
|
||||
host.reloadFS([file1, file2, config, libFile]);
|
||||
|
||||
host.reloadFS([file1, file2, config]);
|
||||
|
||||
projectService.openClientFile(file1.path);
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
checkProjectErrors(projectService.synchronizeProjectList([])[0], []);
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
diags = session.executeCommand(compilerOptionsRequest).response;
|
||||
checkDiagnosticsWithLinePos(diags, []);
|
||||
});
|
||||
|
||||
it("configured projects - diagnostics for corrupted config 1", () => {
|
||||
@@ -126,7 +139,7 @@ namespace ts.projectSystem {
|
||||
const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f);
|
||||
assert.isTrue(configuredProject !== undefined, "should find configured project");
|
||||
checkProjectErrors(configuredProject, []);
|
||||
const projectErrors = projectService.configuredProjects[0].getAllProjectErrors();
|
||||
const projectErrors = configuredProjectAt(projectService, 0).getAllProjectErrors();
|
||||
checkProjectErrorsWorker(projectErrors, [
|
||||
"'{' expected."
|
||||
]);
|
||||
@@ -135,13 +148,12 @@ namespace ts.projectSystem {
|
||||
}
|
||||
// fix config and trigger watcher
|
||||
host.reloadFS([file1, file2, correctConfig]);
|
||||
host.triggerFileWatcherCallback(correctConfig.path, FileWatcherEventKind.Changed);
|
||||
{
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f);
|
||||
assert.isTrue(configuredProject !== undefined, "should find configured project");
|
||||
checkProjectErrors(configuredProject, []);
|
||||
const projectErrors = projectService.configuredProjects[0].getAllProjectErrors();
|
||||
const projectErrors = configuredProjectAt(projectService, 0).getAllProjectErrors();
|
||||
checkProjectErrorsWorker(projectErrors, []);
|
||||
}
|
||||
});
|
||||
@@ -172,18 +184,17 @@ namespace ts.projectSystem {
|
||||
const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f);
|
||||
assert.isTrue(configuredProject !== undefined, "should find configured project");
|
||||
checkProjectErrors(configuredProject, []);
|
||||
const projectErrors = projectService.configuredProjects[0].getAllProjectErrors();
|
||||
const projectErrors = configuredProjectAt(projectService, 0).getAllProjectErrors();
|
||||
checkProjectErrorsWorker(projectErrors, []);
|
||||
}
|
||||
// break config and trigger watcher
|
||||
host.reloadFS([file1, file2, corruptedConfig]);
|
||||
host.triggerFileWatcherCallback(corruptedConfig.path, FileWatcherEventKind.Changed);
|
||||
{
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f);
|
||||
assert.isTrue(configuredProject !== undefined, "should find configured project");
|
||||
checkProjectErrors(configuredProject, []);
|
||||
const projectErrors = projectService.configuredProjects[0].getAllProjectErrors();
|
||||
const projectErrors = configuredProjectAt(projectService, 0).getAllProjectErrors();
|
||||
checkProjectErrorsWorker(projectErrors, [
|
||||
"'{' expected."
|
||||
]);
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/// <reference path="../harness.ts" />
|
||||
|
||||
describe("Public APIs", () => {
|
||||
function verifyApi(fileName: string) {
|
||||
const builtFile = `built/local/${fileName}`;
|
||||
const api = `api/${fileName}`;
|
||||
let fileContent: string;
|
||||
before(() => {
|
||||
fileContent = Harness.IO.readFile(builtFile);
|
||||
});
|
||||
|
||||
it("should be acknowledged when they change", () => {
|
||||
Harness.Baseline.runBaseline(api, () => fileContent);
|
||||
});
|
||||
|
||||
it("should compile", () => {
|
||||
const testFile: Harness.Compiler.TestFile = {
|
||||
unitName: builtFile,
|
||||
content: fileContent
|
||||
};
|
||||
const inputFiles = [testFile];
|
||||
const output = Harness.Compiler.compileFiles(inputFiles, [], /*harnessSettings*/ undefined, /*options*/ {}, /*currentDirectory*/ undefined);
|
||||
assert(!output.result.errors || !output.result.errors.length, Harness.Compiler.minimalDiagnosticsToString(output.result.errors, /*pretty*/ true));
|
||||
});
|
||||
}
|
||||
|
||||
describe("for the language service and compiler", () => {
|
||||
verifyApi("typescript.d.ts");
|
||||
});
|
||||
|
||||
describe("for the language server", () => {
|
||||
verifyApi("tsserverlibrary.d.ts");
|
||||
});
|
||||
});
|
||||
@@ -15,12 +15,12 @@ namespace ts {
|
||||
sourceText?: SourceText;
|
||||
}
|
||||
|
||||
interface NamedSourceText {
|
||||
export interface NamedSourceText {
|
||||
name: string;
|
||||
text: SourceText;
|
||||
}
|
||||
|
||||
interface ProgramWithSourceTexts extends Program {
|
||||
export interface ProgramWithSourceTexts extends Program {
|
||||
sourceTexts?: ReadonlyArray<NamedSourceText>;
|
||||
host: TestCompilerHost;
|
||||
}
|
||||
@@ -29,7 +29,7 @@ namespace ts {
|
||||
getTrace(): string[];
|
||||
}
|
||||
|
||||
class SourceText implements IScriptSnapshot {
|
||||
export class SourceText implements IScriptSnapshot {
|
||||
private fullText: string;
|
||||
|
||||
constructor(private references: string,
|
||||
@@ -103,10 +103,11 @@ namespace ts {
|
||||
function createSourceFileWithText(fileName: string, sourceText: SourceText, target: ScriptTarget) {
|
||||
const file = <SourceFileWithText>createSourceFile(fileName, sourceText.getFullText(), target);
|
||||
file.sourceText = sourceText;
|
||||
file.version = "" + sourceText.getVersion();
|
||||
return file;
|
||||
}
|
||||
|
||||
function createTestCompilerHost(texts: ReadonlyArray<NamedSourceText>, target: ScriptTarget, oldProgram?: ProgramWithSourceTexts): TestCompilerHost {
|
||||
export function createTestCompilerHost(texts: ReadonlyArray<NamedSourceText>, target: ScriptTarget, oldProgram?: ProgramWithSourceTexts): TestCompilerHost {
|
||||
const files = arrayToMap(texts, t => t.name, t => {
|
||||
if (oldProgram) {
|
||||
let oldFile = <SourceFileWithText>oldProgram.getSourceFile(t.name);
|
||||
@@ -154,7 +155,7 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
function newProgram(texts: NamedSourceText[], rootNames: string[], options: CompilerOptions): ProgramWithSourceTexts {
|
||||
export function newProgram(texts: NamedSourceText[], rootNames: string[], options: CompilerOptions): ProgramWithSourceTexts {
|
||||
const host = createTestCompilerHost(texts, options.target);
|
||||
const program = <ProgramWithSourceTexts>createProgram(rootNames, options, host);
|
||||
program.sourceTexts = texts;
|
||||
@@ -162,7 +163,7 @@ namespace ts {
|
||||
return program;
|
||||
}
|
||||
|
||||
function updateProgram(oldProgram: ProgramWithSourceTexts, rootNames: ReadonlyArray<string>, options: CompilerOptions, updater: (files: NamedSourceText[]) => void, newTexts?: NamedSourceText[]) {
|
||||
export function updateProgram(oldProgram: ProgramWithSourceTexts, rootNames: ReadonlyArray<string>, options: CompilerOptions, updater: (files: NamedSourceText[]) => void, newTexts?: NamedSourceText[]) {
|
||||
if (!newTexts) {
|
||||
newTexts = (<ProgramWithSourceTexts>oldProgram).sourceTexts.slice(0);
|
||||
}
|
||||
@@ -174,7 +175,7 @@ namespace ts {
|
||||
return program;
|
||||
}
|
||||
|
||||
function updateProgramText(files: ReadonlyArray<NamedSourceText>, fileName: string, newProgramText: string) {
|
||||
export function updateProgramText(files: ReadonlyArray<NamedSourceText>, fileName: string, newProgramText: string) {
|
||||
const file = find(files, f => f.name === fileName)!;
|
||||
file.text = file.text.updateProgram(newProgramText);
|
||||
}
|
||||
@@ -346,7 +347,7 @@ namespace ts {
|
||||
const program_2 = updateProgram(program_1, ["a.ts"], options, noop, newTexts);
|
||||
assert.deepEqual(emptyArray, program_2.getMissingFilePaths());
|
||||
|
||||
assert.equal(StructureIsReused.SafeModules, program_1.structureIsReused);
|
||||
assert.equal(StructureIsReused.Not, program_1.structureIsReused);
|
||||
});
|
||||
|
||||
it("resolution cache follows imports", () => {
|
||||
@@ -869,4 +870,172 @@ namespace ts {
|
||||
createProgram([], {});
|
||||
});
|
||||
});
|
||||
|
||||
import TestSystem = ts.TestFSWithWatch.TestServerHost;
|
||||
type FileOrFolder = ts.TestFSWithWatch.FileOrFolder;
|
||||
import createTestSystem = ts.TestFSWithWatch.createWatchedSystem;
|
||||
import libFile = ts.TestFSWithWatch.libFile;
|
||||
|
||||
describe("isProgramUptoDate should return true when there is no change in compiler options and", () => {
|
||||
function verifyProgramIsUptoDate(
|
||||
program: Program,
|
||||
newRootFileNames: string[],
|
||||
newOptions: CompilerOptions
|
||||
) {
|
||||
const actual = isProgramUptoDate(
|
||||
program, newRootFileNames, newOptions,
|
||||
path => program.getSourceFileByPath(path).version, /*fileExists*/ returnFalse,
|
||||
/*hasInvalidatedResolution*/ returnFalse,
|
||||
/*hasChangedAutomaticTypeDirectiveNames*/ false
|
||||
);
|
||||
assert.isTrue(actual);
|
||||
}
|
||||
|
||||
function duplicate(options: CompilerOptions): CompilerOptions;
|
||||
function duplicate(fileNames: string[]): string[];
|
||||
function duplicate(filesOrOptions: CompilerOptions | string[]) {
|
||||
return JSON.parse(JSON.stringify(filesOrOptions));
|
||||
}
|
||||
|
||||
function createWatchingSystemHost(host: TestSystem) {
|
||||
return ts.createWatchingSystemHost(/*pretty*/ undefined, host);
|
||||
}
|
||||
|
||||
function verifyProgramWithoutConfigFile(watchingSystemHost: WatchingSystemHost, rootFiles: string[], options: CompilerOptions) {
|
||||
const program = createWatchModeWithoutConfigFile(rootFiles, options, watchingSystemHost)();
|
||||
verifyProgramIsUptoDate(program, duplicate(rootFiles), duplicate(options));
|
||||
}
|
||||
|
||||
function getConfigParseResult(watchingSystemHost: WatchingSystemHost, configFileName: string) {
|
||||
return parseConfigFile(configFileName, {}, watchingSystemHost.system, watchingSystemHost.reportDiagnostic, watchingSystemHost.reportWatchDiagnostic);
|
||||
}
|
||||
|
||||
function verifyProgramWithConfigFile(watchingSystemHost: WatchingSystemHost, configFile: string) {
|
||||
const result = getConfigParseResult(watchingSystemHost, configFile);
|
||||
const program = createWatchModeWithConfigFile(result, {}, watchingSystemHost)();
|
||||
const { fileNames, options } = getConfigParseResult(watchingSystemHost, configFile);
|
||||
verifyProgramIsUptoDate(program, fileNames, options);
|
||||
}
|
||||
|
||||
function verifyProgram(files: FileOrFolder[], rootFiles: string[], options: CompilerOptions, configFile: string) {
|
||||
const watchingSystemHost = createWatchingSystemHost(createTestSystem(files));
|
||||
verifyProgramWithoutConfigFile(watchingSystemHost, rootFiles, options);
|
||||
verifyProgramWithConfigFile(watchingSystemHost, configFile);
|
||||
}
|
||||
|
||||
it("has empty options", () => {
|
||||
const file1: FileOrFolder = {
|
||||
path: "/a/b/file1.ts",
|
||||
content: "let x = 1"
|
||||
};
|
||||
const file2: FileOrFolder = {
|
||||
path: "/a/b/file2.ts",
|
||||
content: "let y = 1"
|
||||
};
|
||||
const configFile: FileOrFolder = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: "{}"
|
||||
};
|
||||
verifyProgram([file1, file2, libFile, configFile], [file1.path, file2.path], {}, configFile.path);
|
||||
});
|
||||
|
||||
it("has lib specified in the options", () => {
|
||||
const compilerOptions: CompilerOptions = { lib: ["es5", "es2015.promise"] };
|
||||
const app: FileOrFolder = {
|
||||
path: "/src/app.ts",
|
||||
content: "var x: Promise<string>;"
|
||||
};
|
||||
const configFile: FileOrFolder = {
|
||||
path: "/src/tsconfig.json",
|
||||
content: JSON.stringify({ compilerOptions })
|
||||
};
|
||||
const es5Lib: FileOrFolder = {
|
||||
path: "/compiler/lib.es5.d.ts",
|
||||
content: "declare const eval: any"
|
||||
};
|
||||
const es2015Promise: FileOrFolder = {
|
||||
path: "/compiler/lib.es2015.promise.d.ts",
|
||||
content: "declare class Promise<T> {}"
|
||||
};
|
||||
|
||||
verifyProgram([app, configFile, es5Lib, es2015Promise], [app.path], compilerOptions, configFile.path);
|
||||
});
|
||||
|
||||
it("has paths specified in the options", () => {
|
||||
const compilerOptions: CompilerOptions = {
|
||||
baseUrl: ".",
|
||||
paths: {
|
||||
"*": [
|
||||
"packages/mail/data/*",
|
||||
"packages/styles/*",
|
||||
"*"
|
||||
]
|
||||
}
|
||||
};
|
||||
const app: FileOrFolder = {
|
||||
path: "/src/packages/framework/app.ts",
|
||||
content: 'import classc from "module1/lib/file1";\
|
||||
import classD from "module3/file3";\
|
||||
let x = new classc();\
|
||||
let y = new classD();'
|
||||
};
|
||||
const module1: FileOrFolder = {
|
||||
path: "/src/packages/mail/data/module1/lib/file1.ts",
|
||||
content: 'import classc from "module2/file2";export default classc;',
|
||||
};
|
||||
const module2: FileOrFolder = {
|
||||
path: "/src/packages/mail/data/module1/lib/module2/file2.ts",
|
||||
content: 'class classc { method2() { return "hello"; } }\nexport default classc',
|
||||
};
|
||||
const module3: FileOrFolder = {
|
||||
path: "/src/packages/styles/module3/file3.ts",
|
||||
content: "class classD { method() { return 10; } }\nexport default classD;"
|
||||
};
|
||||
const configFile: FileOrFolder = {
|
||||
path: "/src/tsconfig.json",
|
||||
content: JSON.stringify({ compilerOptions })
|
||||
};
|
||||
|
||||
verifyProgram([app, module1, module2, module3, libFile, configFile], [app.path], compilerOptions, configFile.path);
|
||||
});
|
||||
|
||||
it("has include paths specified in tsconfig file", () => {
|
||||
const compilerOptions: CompilerOptions = {
|
||||
baseUrl: ".",
|
||||
paths: {
|
||||
"*": [
|
||||
"packages/mail/data/*",
|
||||
"packages/styles/*",
|
||||
"*"
|
||||
]
|
||||
}
|
||||
};
|
||||
const app: FileOrFolder = {
|
||||
path: "/src/packages/framework/app.ts",
|
||||
content: 'import classc from "module1/lib/file1";\
|
||||
import classD from "module3/file3";\
|
||||
let x = new classc();\
|
||||
let y = new classD();'
|
||||
};
|
||||
const module1: FileOrFolder = {
|
||||
path: "/src/packages/mail/data/module1/lib/file1.ts",
|
||||
content: 'import classc from "module2/file2";export default classc;',
|
||||
};
|
||||
const module2: FileOrFolder = {
|
||||
path: "/src/packages/mail/data/module1/lib/module2/file2.ts",
|
||||
content: 'class classc { method2() { return "hello"; } }\nexport default classc',
|
||||
};
|
||||
const module3: FileOrFolder = {
|
||||
path: "/src/packages/styles/module3/file3.ts",
|
||||
content: "class classD { method() { return 10; } }\nexport default classD;"
|
||||
};
|
||||
const configFile: FileOrFolder = {
|
||||
path: "/src/tsconfig.json",
|
||||
content: JSON.stringify({ compilerOptions, include: ["packages/**/ *.ts"] })
|
||||
};
|
||||
|
||||
const watchingSystemHost = createWatchingSystemHost(createTestSystem([app, module1, module2, module3, libFile, configFile]));
|
||||
verifyProgramWithConfigFile(watchingSystemHost, configFile.path);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace ts.server {
|
||||
clearTimeout: noop,
|
||||
setImmediate: () => 0,
|
||||
clearImmediate: noop,
|
||||
createHash: Harness.LanguageService.mockHash,
|
||||
createHash: Harness.mockHash,
|
||||
};
|
||||
|
||||
class TestSession extends Session {
|
||||
@@ -509,7 +509,7 @@ namespace ts.server {
|
||||
class InProcClient {
|
||||
private server: InProcSession;
|
||||
private seq = 0;
|
||||
private callbacks: Array<(resp: protocol.Response) => void> = [];
|
||||
private callbacks: ((resp: protocol.Response) => void)[] = [];
|
||||
private eventHandlers = createMap<(args: any) => void>();
|
||||
|
||||
handle(msg: protocol.Message): void {
|
||||
|
||||
@@ -11,18 +11,24 @@ namespace ts.projectSystem {
|
||||
});
|
||||
|
||||
it("only sends an event once", () => {
|
||||
const file = makeFile("/a.ts");
|
||||
const tsconfig = makeFile("/tsconfig.json", {});
|
||||
const file = makeFile("/a/a.ts");
|
||||
const file2 = makeFile("/b.ts");
|
||||
const tsconfig = makeFile("/a/tsconfig.json", {});
|
||||
|
||||
const et = new EventTracker([file, tsconfig]);
|
||||
const et = new EventTracker([file, file2, tsconfig]);
|
||||
et.service.openClientFile(file.path);
|
||||
et.assertProjectInfoTelemetryEvent({});
|
||||
et.assertProjectInfoTelemetryEvent({}, tsconfig.path);
|
||||
|
||||
et.service.closeClientFile(file.path);
|
||||
checkNumberOfProjects(et.service, { configuredProjects: 0 });
|
||||
checkNumberOfProjects(et.service, { configuredProjects: 1 });
|
||||
|
||||
et.service.openClientFile(file2.path);
|
||||
checkNumberOfProjects(et.service, { inferredProjects: 1 });
|
||||
|
||||
assert.equal(et.getEvents().length, 0);
|
||||
|
||||
et.service.openClientFile(file.path);
|
||||
checkNumberOfProjects(et.service, { configuredProjects: 1 });
|
||||
checkNumberOfProjects(et.service, { configuredProjects: 1, inferredProjects: 1 });
|
||||
|
||||
assert.equal(et.getEvents().length, 0);
|
||||
});
|
||||
@@ -53,7 +59,7 @@ namespace ts.projectSystem {
|
||||
|
||||
// TODO: Apparently compilerOptions is mutated, so have to repeat it here!
|
||||
et.assertProjectInfoTelemetryEvent({
|
||||
projectId: Harness.LanguageService.mockHash("/hunter2/foo.csproj"),
|
||||
projectId: Harness.mockHash("/hunter2/foo.csproj"),
|
||||
compilerOptions: { strict: true },
|
||||
compileOnSave: true,
|
||||
// These properties can't be present for an external project, so they are undefined instead of false.
|
||||
@@ -195,7 +201,7 @@ namespace ts.projectSystem {
|
||||
const et = new EventTracker([jsconfig, file]);
|
||||
et.service.openClientFile(file.path);
|
||||
et.assertProjectInfoTelemetryEvent({
|
||||
projectId: Harness.LanguageService.mockHash("/jsconfig.json"),
|
||||
projectId: Harness.mockHash("/jsconfig.json"),
|
||||
fileStats: fileStats({ js: 1 }),
|
||||
compilerOptions: autoJsCompilerOptions,
|
||||
typeAcquisition: {
|
||||
@@ -215,7 +221,7 @@ namespace ts.projectSystem {
|
||||
et.service.openClientFile(file.path);
|
||||
et.getEvent<server.ProjectLanguageServiceStateEvent>(server.ProjectLanguageServiceStateEvent, /*mayBeMore*/ true);
|
||||
et.assertProjectInfoTelemetryEvent({
|
||||
projectId: Harness.LanguageService.mockHash("/jsconfig.json"),
|
||||
projectId: Harness.mockHash("/jsconfig.json"),
|
||||
fileStats: fileStats({ js: 1 }),
|
||||
compilerOptions: autoJsCompilerOptions,
|
||||
configFileName: "jsconfig.json",
|
||||
@@ -249,9 +255,9 @@ namespace ts.projectSystem {
|
||||
return events;
|
||||
}
|
||||
|
||||
assertProjectInfoTelemetryEvent(partial: Partial<server.ProjectInfoTelemetryEventData>): void {
|
||||
assertProjectInfoTelemetryEvent(partial: Partial<server.ProjectInfoTelemetryEventData>, configFile?: string): void {
|
||||
assert.deepEqual(this.getEvent<server.ProjectInfoTelemetryEvent>(ts.server.ProjectInfoTelemetryEvent), {
|
||||
projectId: Harness.LanguageService.mockHash("/tsconfig.json"),
|
||||
projectId: Harness.mockHash(configFile || "/tsconfig.json"),
|
||||
fileStats: fileStats({ ts: 1 }),
|
||||
compilerOptions: {},
|
||||
extends: false,
|
||||
@@ -282,7 +288,7 @@ namespace ts.projectSystem {
|
||||
}
|
||||
|
||||
function makeFile(path: string, content: {} = ""): projectSystem.FileOrFolder {
|
||||
return { path, content: typeof content === "string" ? "" : JSON.stringify(content) };
|
||||
return { path, content: isString(content) ? "" : JSON.stringify(content) };
|
||||
}
|
||||
|
||||
function fileStats(nonZeroStats: Partial<server.FileStats>): server.FileStats {
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace ts.textStorage {
|
||||
const ts1 = new server.TextStorage(host, server.asNormalizedPath(f.path));
|
||||
const ts2 = new server.TextStorage(host, server.asNormalizedPath(f.path));
|
||||
|
||||
ts1.useScriptVersionCache();
|
||||
ts1.useScriptVersionCache_TestOnly();
|
||||
ts2.useText();
|
||||
|
||||
const lineMap = computeLineStarts(f.content);
|
||||
@@ -55,16 +55,16 @@ namespace ts.textStorage {
|
||||
const ts1 = new server.TextStorage(host, server.asNormalizedPath(f.path));
|
||||
|
||||
ts1.getSnapshot();
|
||||
assert.isTrue(!ts1.hasScriptVersionCache(), "should not have script version cache - 1");
|
||||
assert.isTrue(!ts1.hasScriptVersionCache_TestOnly(), "should not have script version cache - 1");
|
||||
|
||||
ts1.edit(0, 5, " ");
|
||||
assert.isTrue(ts1.hasScriptVersionCache(), "have script version cache - 1");
|
||||
assert.isTrue(ts1.hasScriptVersionCache_TestOnly(), "have script version cache - 1");
|
||||
|
||||
ts1.useText();
|
||||
assert.isTrue(!ts1.hasScriptVersionCache(), "should not have script version cache - 2");
|
||||
assert.isTrue(!ts1.hasScriptVersionCache_TestOnly(), "should not have script version cache - 2");
|
||||
|
||||
ts1.getLineInfo(0);
|
||||
assert.isTrue(ts1.hasScriptVersionCache(), "have script version cache - 2");
|
||||
assert.isTrue(ts1.hasScriptVersionCache_TestOnly(), "have script version cache - 2");
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -38,7 +38,7 @@ namespace ts.projectSystem {
|
||||
function executeCommand(self: Installer, host: TestServerHost, installedTypings: string[] | string, typingFiles: FileOrFolder[], cb: TI.RequestCompletedAction): void {
|
||||
self.addPostExecAction(installedTypings, success => {
|
||||
for (const file of typingFiles) {
|
||||
host.createFileOrFolder(file, /*createParentDirectory*/ true);
|
||||
host.ensureFileOrFolder(file);
|
||||
}
|
||||
cb(success);
|
||||
});
|
||||
@@ -92,7 +92,7 @@ namespace ts.projectSystem {
|
||||
const service = createProjectService(host, { typingsInstaller: installer });
|
||||
service.openClientFile(f1.path);
|
||||
service.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
checkProjectActualFiles(service.configuredProjects[0], [f1.path, f2.path, config.path]);
|
||||
checkProjectActualFiles(configuredProjectAt(service, 0), [f1.path, f2.path, config.path]);
|
||||
installer.installAll(0);
|
||||
});
|
||||
});
|
||||
@@ -144,12 +144,13 @@ namespace ts.projectSystem {
|
||||
projectService.openClientFile(file1.path);
|
||||
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
const p = projectService.configuredProjects[0];
|
||||
const p = configuredProjectAt(projectService, 0);
|
||||
checkProjectActualFiles(p, [file1.path, tsconfig.path]);
|
||||
|
||||
installer.installAll(/*expectedCount*/ 1);
|
||||
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
host.checkTimeoutQueueLengthAndRun(2);
|
||||
checkProjectActualFiles(p, [file1.path, jquery.path, tsconfig.path]);
|
||||
});
|
||||
|
||||
@@ -349,6 +350,8 @@ namespace ts.projectSystem {
|
||||
|
||||
installer.installAll(/*expectedCount*/ 1);
|
||||
|
||||
checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
host.checkTimeoutQueueLengthAndRun(2);
|
||||
checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
checkProjectActualFiles(p, [file1.path, file2.path, file3.path, lodash.path, react.path]);
|
||||
});
|
||||
@@ -470,6 +473,8 @@ namespace ts.projectSystem {
|
||||
|
||||
installer.installAll(/*expectedCount*/ 1);
|
||||
|
||||
checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
host.checkTimeoutQueueLengthAndRun(2);
|
||||
checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
checkProjectActualFiles(p, [file1.path, file2.path, file3.path, commander.path, express.path, jquery.path, moment.path]);
|
||||
});
|
||||
@@ -548,7 +553,7 @@ namespace ts.projectSystem {
|
||||
for (const f of typingFiles) {
|
||||
assert.isTrue(host.fileExists(f.path), `expected file ${f.path} to exist`);
|
||||
}
|
||||
|
||||
host.checkTimeoutQueueLengthAndRun(2);
|
||||
checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
checkProjectActualFiles(p, [lodashJs.path, commanderJs.path, file3.path, commander.path, express.path, jquery.path, moment.path, lodash.path]);
|
||||
});
|
||||
@@ -651,7 +656,7 @@ namespace ts.projectSystem {
|
||||
assert.equal(installer.pendingRunRequests.length, 0, "expected no throttled requests");
|
||||
|
||||
installer.executePendingCommands();
|
||||
|
||||
host.checkTimeoutQueueLengthAndRun(3); // for 2 projects and 1 refreshing inferred project
|
||||
checkProjectActualFiles(p1, [lodashJs.path, commanderJs.path, file3.path, commander.path, jquery.path, lodash.path, cordova.path]);
|
||||
checkProjectActualFiles(p2, [file3.path, grunt.path, gulp.path]);
|
||||
});
|
||||
@@ -699,12 +704,13 @@ namespace ts.projectSystem {
|
||||
projectService.openClientFile(app.path);
|
||||
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
const p = projectService.configuredProjects[0];
|
||||
const p = configuredProjectAt(projectService, 0);
|
||||
checkProjectActualFiles(p, [app.path, jsconfig.path]);
|
||||
|
||||
installer.installAll(/*expectedCount*/ 1);
|
||||
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
host.checkTimeoutQueueLengthAndRun(2);
|
||||
checkProjectActualFiles(p, [app.path, jqueryDTS.path, jsconfig.path]);
|
||||
});
|
||||
|
||||
@@ -745,13 +751,14 @@ namespace ts.projectSystem {
|
||||
projectService.openClientFile(app.path);
|
||||
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
const p = projectService.configuredProjects[0];
|
||||
const p = configuredProjectAt(projectService, 0);
|
||||
checkProjectActualFiles(p, [app.path, jsconfig.path]);
|
||||
checkWatchedFiles(host, [jsconfig.path, "/bower_components", "/node_modules", libFile.path]);
|
||||
|
||||
installer.installAll(/*expectedCount*/ 1);
|
||||
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
host.checkTimeoutQueueLengthAndRun(2);
|
||||
checkProjectActualFiles(p, [app.path, jqueryDTS.path, jsconfig.path]);
|
||||
});
|
||||
|
||||
@@ -792,12 +799,13 @@ namespace ts.projectSystem {
|
||||
projectService.openClientFile(app.path);
|
||||
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
const p = projectService.configuredProjects[0];
|
||||
const p = configuredProjectAt(projectService, 0);
|
||||
checkProjectActualFiles(p, [app.path, jsconfig.path]);
|
||||
|
||||
installer.installAll(/*expectedCount*/ 1);
|
||||
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
host.checkTimeoutQueueLengthAndRun(2);
|
||||
checkProjectActualFiles(p, [app.path, jqueryDTS.path, jsconfig.path]);
|
||||
});
|
||||
|
||||
@@ -836,10 +844,10 @@ namespace ts.projectSystem {
|
||||
installer.checkPendingCommands(/*expectedCount*/ 0);
|
||||
|
||||
host.reloadFS([f, fixedPackageJson]);
|
||||
host.triggerFileWatcherCallback(fixedPackageJson.path, FileWatcherEventKind.Changed);
|
||||
host.checkTimeoutQueueLengthAndRun(2); // To refresh the project and refresh inferred projects
|
||||
// expected install request
|
||||
installer.installAll(/*expectedCount*/ 1);
|
||||
|
||||
host.checkTimeoutQueueLengthAndRun(2);
|
||||
service.checkNumberOfProjects({ inferredProjects: 1 });
|
||||
checkProjectActualFiles(service.inferredProjects[0], [f.path, commander.path]);
|
||||
});
|
||||
@@ -963,8 +971,7 @@ namespace ts.projectSystem {
|
||||
}
|
||||
};
|
||||
session.executeCommand(changeRequest);
|
||||
host.checkTimeoutQueueLength(1);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
host.checkTimeoutQueueLengthAndRun(2); // This enqueues the updategraph and refresh inferred projects
|
||||
const version2 = proj.getCachedUnresolvedImportsPerFile_TestOnly().getVersion();
|
||||
assert.equal(version1, version2, "set of unresolved imports should not change");
|
||||
});
|
||||
@@ -1171,6 +1178,7 @@ namespace ts.projectSystem {
|
||||
installer.installAll(/*expectedCount*/ 1);
|
||||
|
||||
assert.isTrue(seenTelemetryEvent);
|
||||
host.checkTimeoutQueueLengthAndRun(2);
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
checkProjectActualFiles(projectService.inferredProjects[0], [f1.path, commander.path]);
|
||||
});
|
||||
@@ -1224,6 +1232,7 @@ namespace ts.projectSystem {
|
||||
assert.isTrue(!!endEvent);
|
||||
assert.isTrue(beginEvent.eventId === endEvent.eventId);
|
||||
assert.isTrue(endEvent.installSuccess);
|
||||
host.checkTimeoutQueueLengthAndRun(2);
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
checkProjectActualFiles(projectService.inferredProjects[0], [f1.path, commander.path]);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,593 @@
|
||||
/// <reference path="harness.ts" />
|
||||
|
||||
namespace ts.TestFSWithWatch {
|
||||
const { content: libFileContent } = Harness.getDefaultLibraryFile(Harness.IO);
|
||||
export const libFile: FileOrFolder = {
|
||||
path: "/a/lib/lib.d.ts",
|
||||
content: libFileContent
|
||||
};
|
||||
|
||||
export const safeList = {
|
||||
path: <Path>"/safeList.json",
|
||||
content: JSON.stringify({
|
||||
commander: "commander",
|
||||
express: "express",
|
||||
jquery: "jquery",
|
||||
lodash: "lodash",
|
||||
moment: "moment",
|
||||
chroma: "chroma-js"
|
||||
})
|
||||
};
|
||||
|
||||
function getExecutingFilePathFromLibFile(): string {
|
||||
return combinePaths(getDirectoryPath(libFile.path), "tsc.js");
|
||||
}
|
||||
|
||||
interface TestServerHostCreationParameters {
|
||||
useCaseSensitiveFileNames?: boolean;
|
||||
executingFilePath?: string;
|
||||
currentDirectory?: string;
|
||||
newLine?: string;
|
||||
}
|
||||
|
||||
export function createWatchedSystem(fileOrFolderList: ReadonlyArray<FileOrFolder>, params?: TestServerHostCreationParameters): TestServerHost {
|
||||
if (!params) {
|
||||
params = {};
|
||||
}
|
||||
const host = new TestServerHost(/*withSafelist*/ false,
|
||||
params.useCaseSensitiveFileNames !== undefined ? params.useCaseSensitiveFileNames : false,
|
||||
params.executingFilePath || getExecutingFilePathFromLibFile(),
|
||||
params.currentDirectory || "/",
|
||||
fileOrFolderList,
|
||||
params.newLine);
|
||||
return host;
|
||||
}
|
||||
|
||||
export function createServerHost(fileOrFolderList: ReadonlyArray<FileOrFolder>, params?: TestServerHostCreationParameters): TestServerHost {
|
||||
if (!params) {
|
||||
params = {};
|
||||
}
|
||||
const host = new TestServerHost(/*withSafelist*/ true,
|
||||
params.useCaseSensitiveFileNames !== undefined ? params.useCaseSensitiveFileNames : false,
|
||||
params.executingFilePath || getExecutingFilePathFromLibFile(),
|
||||
params.currentDirectory || "/",
|
||||
fileOrFolderList,
|
||||
params.newLine);
|
||||
return host;
|
||||
}
|
||||
|
||||
export interface FileOrFolder {
|
||||
path: string;
|
||||
content?: string;
|
||||
fileSize?: number;
|
||||
}
|
||||
|
||||
interface FSEntry {
|
||||
path: Path;
|
||||
fullPath: string;
|
||||
}
|
||||
|
||||
interface File extends FSEntry {
|
||||
content: string;
|
||||
fileSize?: number;
|
||||
}
|
||||
|
||||
interface Folder extends FSEntry {
|
||||
entries: FSEntry[];
|
||||
}
|
||||
|
||||
function isFolder(s: FSEntry): s is Folder {
|
||||
return s && isArray((<Folder>s).entries);
|
||||
}
|
||||
|
||||
function isFile(s: FSEntry): s is File {
|
||||
return s && isString((<File>s).content);
|
||||
}
|
||||
|
||||
function invokeWatcherCallbacks<T>(callbacks: T[], invokeCallback: (cb: T) => void): void {
|
||||
if (callbacks) {
|
||||
// The array copy is made to ensure that even if one of the callback removes the callbacks,
|
||||
// we dont miss any callbacks following it
|
||||
const cbs = callbacks.slice();
|
||||
for (const cb of cbs) {
|
||||
invokeCallback(cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getDiffInKeys(map: Map<any>, expectedKeys: ReadonlyArray<string>) {
|
||||
if (map.size === expectedKeys.length) {
|
||||
return "";
|
||||
}
|
||||
const notInActual: string[] = [];
|
||||
const duplicates: string[] = [];
|
||||
const seen = createMap<true>();
|
||||
forEach(expectedKeys, expectedKey => {
|
||||
if (seen.has(expectedKey)) {
|
||||
duplicates.push(expectedKey);
|
||||
return;
|
||||
}
|
||||
seen.set(expectedKey, true);
|
||||
if (!map.has(expectedKey)) {
|
||||
notInActual.push(expectedKey);
|
||||
}
|
||||
});
|
||||
const inActualNotExpected: string[] = [];
|
||||
map.forEach((_value, key) => {
|
||||
if (!seen.has(key)) {
|
||||
inActualNotExpected.push(key);
|
||||
}
|
||||
seen.set(key, true);
|
||||
});
|
||||
return `\n\nNotInActual: ${notInActual}\nDuplicates: ${duplicates}\nInActualButNotInExpected: ${inActualNotExpected}`;
|
||||
}
|
||||
|
||||
function checkMapKeys(caption: string, map: Map<any>, expectedKeys: ReadonlyArray<string>) {
|
||||
assert.equal(map.size, expectedKeys.length, `${caption}: incorrect size of map: Actual keys: ${arrayFrom(map.keys())} Expected: ${expectedKeys}${getDiffInKeys(map, expectedKeys)}`);
|
||||
for (const name of expectedKeys) {
|
||||
assert.isTrue(map.has(name), `${caption} is expected to contain ${name}, actual keys: ${arrayFrom(map.keys())}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function checkFileNames(caption: string, actualFileNames: ReadonlyArray<string>, expectedFileNames: string[]) {
|
||||
assert.equal(actualFileNames.length, expectedFileNames.length, `${caption}: incorrect actual number of files, expected ${expectedFileNames}, got ${actualFileNames}`);
|
||||
for (const f of expectedFileNames) {
|
||||
assert.isTrue(contains(actualFileNames, f), `${caption}: expected to find ${f} in ${actualFileNames}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function checkWatchedFiles(host: TestServerHost, expectedFiles: string[]) {
|
||||
checkMapKeys("watchedFiles", host.watchedFiles, expectedFiles);
|
||||
}
|
||||
|
||||
export function checkWatchedDirectories(host: TestServerHost, expectedDirectories: string[], recursive = false) {
|
||||
checkMapKeys(`watchedDirectories${recursive ? " recursive" : ""}`, recursive ? host.watchedDirectoriesRecursive : host.watchedDirectories, expectedDirectories);
|
||||
}
|
||||
|
||||
export function checkOutputContains(host: TestServerHost, expected: ReadonlyArray<string>) {
|
||||
const mapExpected = arrayToSet(expected);
|
||||
const mapSeen = createMap<true>();
|
||||
for (const f of host.getOutput()) {
|
||||
assert.isUndefined(mapSeen.get(f), `Already found ${f} in ${JSON.stringify(host.getOutput())}`);
|
||||
if (mapExpected.has(f)) {
|
||||
mapExpected.delete(f);
|
||||
mapSeen.set(f, true);
|
||||
}
|
||||
}
|
||||
assert.equal(mapExpected.size, 0, `Output has missing ${JSON.stringify(flatMapIter(mapExpected.keys(), key => key))} in ${JSON.stringify(host.getOutput())}`);
|
||||
}
|
||||
|
||||
export function checkOutputDoesNotContain(host: TestServerHost, expectedToBeAbsent: string[] | ReadonlyArray<string>) {
|
||||
const mapExpectedToBeAbsent = arrayToSet(expectedToBeAbsent);
|
||||
for (const f of host.getOutput()) {
|
||||
assert.isFalse(mapExpectedToBeAbsent.has(f), `Contains ${f} in ${JSON.stringify(host.getOutput())}`);
|
||||
}
|
||||
}
|
||||
|
||||
class Callbacks {
|
||||
private map: TimeOutCallback[] = [];
|
||||
private nextId = 1;
|
||||
|
||||
register(cb: (...args: any[]) => void, args: any[]) {
|
||||
const timeoutId = this.nextId;
|
||||
this.nextId++;
|
||||
this.map[timeoutId] = cb.bind(/*this*/ undefined, ...args);
|
||||
return timeoutId;
|
||||
}
|
||||
|
||||
unregister(id: any) {
|
||||
if (typeof id === "number") {
|
||||
delete this.map[id];
|
||||
}
|
||||
}
|
||||
|
||||
count() {
|
||||
let n = 0;
|
||||
for (const _ in this.map) {
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
invoke() {
|
||||
// Note: invoking a callback may result in new callbacks been queued,
|
||||
// so do not clear the entire callback list regardless. Only remove the
|
||||
// ones we have invoked.
|
||||
for (const key in this.map) {
|
||||
this.map[key]();
|
||||
delete this.map[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type TimeOutCallback = () => any;
|
||||
|
||||
export interface TestFileWatcher {
|
||||
cb: FileWatcherCallback;
|
||||
fileName: string;
|
||||
}
|
||||
|
||||
export interface TestDirectoryWatcher {
|
||||
cb: DirectoryWatcherCallback;
|
||||
directoryName: string;
|
||||
}
|
||||
|
||||
export class TestServerHost implements server.ServerHost {
|
||||
args: string[] = [];
|
||||
|
||||
private readonly output: string[] = [];
|
||||
|
||||
private fs: Map<FSEntry> = createMap<FSEntry>();
|
||||
private getCanonicalFileName: (s: string) => string;
|
||||
private toPath: (f: string) => Path;
|
||||
private timeoutCallbacks = new Callbacks();
|
||||
private immediateCallbacks = new Callbacks();
|
||||
|
||||
readonly watchedDirectories = createMultiMap<TestDirectoryWatcher>();
|
||||
readonly watchedDirectoriesRecursive = createMultiMap<TestDirectoryWatcher>();
|
||||
readonly watchedFiles = createMultiMap<TestFileWatcher>();
|
||||
|
||||
constructor(public withSafeList: boolean, public useCaseSensitiveFileNames: boolean, private executingFilePath: string, private currentDirectory: string, fileOrFolderList: ReadonlyArray<FileOrFolder>, public readonly newLine = "\n") {
|
||||
this.getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
|
||||
this.toPath = s => toPath(s, currentDirectory, this.getCanonicalFileName);
|
||||
|
||||
this.reloadFS(fileOrFolderList);
|
||||
}
|
||||
|
||||
toNormalizedAbsolutePath(s: string) {
|
||||
return getNormalizedAbsolutePath(s, this.currentDirectory);
|
||||
}
|
||||
|
||||
toFullPath(s: string) {
|
||||
return this.toPath(this.toNormalizedAbsolutePath(s));
|
||||
}
|
||||
|
||||
reloadFS(fileOrFolderList: ReadonlyArray<FileOrFolder>) {
|
||||
const mapNewLeaves = createMap<true>();
|
||||
const isNewFs = this.fs.size === 0;
|
||||
// always inject safelist file in the list of files
|
||||
for (const fileOrDirectory of fileOrFolderList.concat(this.withSafeList ? safeList : [])) {
|
||||
const path = this.toFullPath(fileOrDirectory.path);
|
||||
mapNewLeaves.set(path, true);
|
||||
// If its a change
|
||||
const currentEntry = this.fs.get(path);
|
||||
if (currentEntry) {
|
||||
if (isFile(currentEntry)) {
|
||||
if (isString(fileOrDirectory.content)) {
|
||||
// Update file
|
||||
if (currentEntry.content !== fileOrDirectory.content) {
|
||||
currentEntry.content = fileOrDirectory.content;
|
||||
this.invokeFileWatcher(currentEntry.fullPath, FileWatcherEventKind.Changed);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: Changing from file => folder
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Folder
|
||||
if (isString(fileOrDirectory.content)) {
|
||||
// TODO: Changing from folder => file
|
||||
}
|
||||
else {
|
||||
// Folder update: Nothing to do.
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.ensureFileOrFolder(fileOrDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isNewFs) {
|
||||
this.fs.forEach((fileOrDirectory, path) => {
|
||||
// If this entry is not from the new file or folder
|
||||
if (!mapNewLeaves.get(path)) {
|
||||
// Leaf entries that arent in new list => remove these
|
||||
if (isFile(fileOrDirectory) || isFolder(fileOrDirectory) && fileOrDirectory.entries.length === 0) {
|
||||
this.removeFileOrFolder(fileOrDirectory, folder => !mapNewLeaves.get(folder.path));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ensureFileOrFolder(fileOrDirectory: FileOrFolder) {
|
||||
if (isString(fileOrDirectory.content)) {
|
||||
const file = this.toFile(fileOrDirectory);
|
||||
Debug.assert(!this.fs.get(file.path));
|
||||
const baseFolder = this.ensureFolder(getDirectoryPath(file.fullPath));
|
||||
this.addFileOrFolderInFolder(baseFolder, file);
|
||||
}
|
||||
else {
|
||||
const fullPath = getNormalizedAbsolutePath(fileOrDirectory.path, this.currentDirectory);
|
||||
this.ensureFolder(fullPath);
|
||||
}
|
||||
}
|
||||
|
||||
private ensureFolder(fullPath: string): Folder {
|
||||
const path = this.toPath(fullPath);
|
||||
let folder = this.fs.get(path) as Folder;
|
||||
if (!folder) {
|
||||
folder = this.toFolder(fullPath);
|
||||
const baseFullPath = getDirectoryPath(fullPath);
|
||||
if (fullPath !== baseFullPath) {
|
||||
// Add folder in the base folder
|
||||
const baseFolder = this.ensureFolder(baseFullPath);
|
||||
this.addFileOrFolderInFolder(baseFolder, folder);
|
||||
}
|
||||
else {
|
||||
// root folder
|
||||
Debug.assert(this.fs.size === 0);
|
||||
this.fs.set(path, folder);
|
||||
}
|
||||
}
|
||||
Debug.assert(isFolder(folder));
|
||||
return folder;
|
||||
}
|
||||
|
||||
private addFileOrFolderInFolder(folder: Folder, fileOrDirectory: File | Folder) {
|
||||
folder.entries.push(fileOrDirectory);
|
||||
this.fs.set(fileOrDirectory.path, fileOrDirectory);
|
||||
|
||||
if (isFile(fileOrDirectory)) {
|
||||
this.invokeFileWatcher(fileOrDirectory.fullPath, FileWatcherEventKind.Created);
|
||||
}
|
||||
this.invokeDirectoryWatcher(folder.fullPath, fileOrDirectory.fullPath);
|
||||
}
|
||||
|
||||
private removeFileOrFolder(fileOrDirectory: File | Folder, isRemovableLeafFolder: (folder: Folder) => boolean) {
|
||||
const basePath = getDirectoryPath(fileOrDirectory.path);
|
||||
const baseFolder = this.fs.get(basePath) as Folder;
|
||||
if (basePath !== fileOrDirectory.path) {
|
||||
Debug.assert(!!baseFolder);
|
||||
filterMutate(baseFolder.entries, entry => entry !== fileOrDirectory);
|
||||
}
|
||||
this.fs.delete(fileOrDirectory.path);
|
||||
|
||||
if (isFile(fileOrDirectory)) {
|
||||
this.invokeFileWatcher(fileOrDirectory.fullPath, FileWatcherEventKind.Deleted);
|
||||
}
|
||||
else {
|
||||
Debug.assert(fileOrDirectory.entries.length === 0);
|
||||
const relativePath = this.getRelativePathToDirectory(fileOrDirectory.fullPath, fileOrDirectory.fullPath);
|
||||
// Invoke directory and recursive directory watcher for the folder
|
||||
// Here we arent invoking recursive directory watchers for the base folders
|
||||
// since that is something we would want to do for both file as well as folder we are deleting
|
||||
invokeWatcherCallbacks(this.watchedDirectories.get(fileOrDirectory.path), cb => this.directoryCallback(cb, relativePath));
|
||||
invokeWatcherCallbacks(this.watchedDirectoriesRecursive.get(fileOrDirectory.path), cb => this.directoryCallback(cb, relativePath));
|
||||
}
|
||||
|
||||
if (basePath !== fileOrDirectory.path) {
|
||||
if (baseFolder.entries.length === 0 && isRemovableLeafFolder(baseFolder)) {
|
||||
this.removeFileOrFolder(baseFolder, isRemovableLeafFolder);
|
||||
}
|
||||
else {
|
||||
this.invokeRecursiveDirectoryWatcher(baseFolder.fullPath, fileOrDirectory.fullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private invokeFileWatcher(fileFullPath: string, eventKind: FileWatcherEventKind) {
|
||||
const callbacks = this.watchedFiles.get(this.toPath(fileFullPath));
|
||||
invokeWatcherCallbacks(callbacks, ({ cb, fileName }) => cb(fileName, eventKind));
|
||||
}
|
||||
|
||||
private getRelativePathToDirectory(directoryFullPath: string, fileFullPath: string) {
|
||||
return getRelativePathToDirectoryOrUrl(directoryFullPath, fileFullPath, this.currentDirectory, this.getCanonicalFileName, /*isAbsolutePathAnUrl*/ false);
|
||||
}
|
||||
|
||||
/**
|
||||
* This will call the directory watcher for the folderFullPath and recursive directory watchers for this and base folders
|
||||
*/
|
||||
private invokeDirectoryWatcher(folderFullPath: string, fileName: string) {
|
||||
const relativePath = this.getRelativePathToDirectory(folderFullPath, fileName);
|
||||
invokeWatcherCallbacks(this.watchedDirectories.get(this.toPath(folderFullPath)), cb => this.directoryCallback(cb, relativePath));
|
||||
this.invokeRecursiveDirectoryWatcher(folderFullPath, fileName);
|
||||
}
|
||||
|
||||
private directoryCallback({ cb, directoryName }: TestDirectoryWatcher, relativePath: string) {
|
||||
cb(combinePaths(directoryName, relativePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* This will call the recursive directory watcher for this directory as well as all the base directories
|
||||
*/
|
||||
private invokeRecursiveDirectoryWatcher(fullPath: string, fileName: string) {
|
||||
const relativePath = this.getRelativePathToDirectory(fullPath, fileName);
|
||||
invokeWatcherCallbacks(this.watchedDirectoriesRecursive.get(this.toPath(fullPath)), cb => this.directoryCallback(cb, relativePath));
|
||||
const basePath = getDirectoryPath(fullPath);
|
||||
if (this.getCanonicalFileName(fullPath) !== this.getCanonicalFileName(basePath)) {
|
||||
this.invokeRecursiveDirectoryWatcher(basePath, fileName);
|
||||
}
|
||||
}
|
||||
|
||||
private toFile(fileOrDirectory: FileOrFolder): File {
|
||||
const fullPath = getNormalizedAbsolutePath(fileOrDirectory.path, this.currentDirectory);
|
||||
return {
|
||||
path: this.toPath(fullPath),
|
||||
content: fileOrDirectory.content,
|
||||
fullPath,
|
||||
fileSize: fileOrDirectory.fileSize
|
||||
};
|
||||
}
|
||||
|
||||
private toFolder(path: string): Folder {
|
||||
const fullPath = getNormalizedAbsolutePath(path, this.currentDirectory);
|
||||
return {
|
||||
path: this.toPath(fullPath),
|
||||
entries: [],
|
||||
fullPath
|
||||
};
|
||||
}
|
||||
|
||||
fileExists(s: string) {
|
||||
const path = this.toFullPath(s);
|
||||
return isFile(this.fs.get(path));
|
||||
}
|
||||
|
||||
readFile(s: string) {
|
||||
const fsEntry = this.fs.get(this.toFullPath(s));
|
||||
return isFile(fsEntry) ? fsEntry.content : undefined;
|
||||
}
|
||||
|
||||
getFileSize(s: string) {
|
||||
const path = this.toFullPath(s);
|
||||
const entry = this.fs.get(path);
|
||||
if (isFile(entry)) {
|
||||
return entry.fileSize ? entry.fileSize : entry.content.length;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
directoryExists(s: string) {
|
||||
const path = this.toFullPath(s);
|
||||
return isFolder(this.fs.get(path));
|
||||
}
|
||||
|
||||
getDirectories(s: string) {
|
||||
const path = this.toFullPath(s);
|
||||
const folder = this.fs.get(path);
|
||||
if (isFolder(folder)) {
|
||||
return mapDefined(folder.entries, entry => isFolder(entry) ? getBaseFileName(entry.fullPath) : undefined);
|
||||
}
|
||||
Debug.fail(folder ? "getDirectories called on file" : "getDirectories called on missing folder");
|
||||
return [];
|
||||
}
|
||||
|
||||
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[] {
|
||||
return ts.matchFiles(this.toNormalizedAbsolutePath(path), extensions, exclude, include, this.useCaseSensitiveFileNames, this.getCurrentDirectory(), depth, (dir) => {
|
||||
const directories: string[] = [];
|
||||
const files: string[] = [];
|
||||
const dirEntry = this.fs.get(this.toPath(dir));
|
||||
if (isFolder(dirEntry)) {
|
||||
dirEntry.entries.forEach((entry) => {
|
||||
if (isFolder(entry)) {
|
||||
directories.push(getBaseFileName(entry.fullPath));
|
||||
}
|
||||
else if (isFile(entry)) {
|
||||
files.push(getBaseFileName(entry.fullPath));
|
||||
}
|
||||
else {
|
||||
Debug.fail("Unknown entry");
|
||||
}
|
||||
});
|
||||
}
|
||||
return { directories, files };
|
||||
});
|
||||
}
|
||||
|
||||
watchDirectory(directoryName: string, cb: DirectoryWatcherCallback, recursive: boolean): FileWatcher {
|
||||
const path = this.toFullPath(directoryName);
|
||||
const map = recursive ? this.watchedDirectoriesRecursive : this.watchedDirectories;
|
||||
const callback: TestDirectoryWatcher = {
|
||||
cb,
|
||||
directoryName
|
||||
};
|
||||
map.add(path, callback);
|
||||
return {
|
||||
close: () => map.remove(path, callback)
|
||||
};
|
||||
}
|
||||
|
||||
createHash(s: string): string {
|
||||
return Harness.mockHash(s);
|
||||
}
|
||||
|
||||
watchFile(fileName: string, cb: FileWatcherCallback) {
|
||||
const path = this.toFullPath(fileName);
|
||||
const callback: TestFileWatcher = { fileName, cb };
|
||||
this.watchedFiles.add(path, callback);
|
||||
return { close: () => this.watchedFiles.remove(path, callback) };
|
||||
}
|
||||
|
||||
// TOOD: record and invoke callbacks to simulate timer events
|
||||
setTimeout(callback: TimeOutCallback, _time: number, ...args: any[]) {
|
||||
return this.timeoutCallbacks.register(callback, args);
|
||||
}
|
||||
|
||||
clearTimeout(timeoutId: any): void {
|
||||
this.timeoutCallbacks.unregister(timeoutId);
|
||||
}
|
||||
|
||||
checkTimeoutQueueLengthAndRun(expected: number) {
|
||||
this.checkTimeoutQueueLength(expected);
|
||||
this.runQueuedTimeoutCallbacks();
|
||||
}
|
||||
|
||||
checkTimeoutQueueLength(expected: number) {
|
||||
const callbacksCount = this.timeoutCallbacks.count();
|
||||
assert.equal(callbacksCount, expected, `expected ${expected} timeout callbacks queued but found ${callbacksCount}.`);
|
||||
}
|
||||
|
||||
runQueuedTimeoutCallbacks() {
|
||||
try {
|
||||
this.timeoutCallbacks.invoke();
|
||||
}
|
||||
catch (e) {
|
||||
if (e.message === this.existMessage) {
|
||||
return;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
runQueuedImmediateCallbacks() {
|
||||
this.immediateCallbacks.invoke();
|
||||
}
|
||||
|
||||
setImmediate(callback: TimeOutCallback, _time: number, ...args: any[]) {
|
||||
return this.immediateCallbacks.register(callback, args);
|
||||
}
|
||||
|
||||
clearImmediate(timeoutId: any): void {
|
||||
this.immediateCallbacks.unregister(timeoutId);
|
||||
}
|
||||
|
||||
createDirectory(directoryName: string): void {
|
||||
const folder = this.toFolder(directoryName);
|
||||
|
||||
// base folder has to be present
|
||||
const base = getDirectoryPath(folder.fullPath);
|
||||
const baseFolder = this.fs.get(base) as Folder;
|
||||
Debug.assert(isFolder(baseFolder));
|
||||
|
||||
Debug.assert(!this.fs.get(folder.path));
|
||||
this.addFileOrFolderInFolder(baseFolder, folder);
|
||||
}
|
||||
|
||||
writeFile(path: string, content: string): void {
|
||||
const file = this.toFile({ path, content });
|
||||
|
||||
// base folder has to be present
|
||||
const base = getDirectoryPath(file.fullPath);
|
||||
const folder = this.fs.get(base) as Folder;
|
||||
Debug.assert(isFolder(folder));
|
||||
|
||||
this.addFileOrFolderInFolder(folder, file);
|
||||
}
|
||||
|
||||
write(message: string) {
|
||||
this.output.push(message);
|
||||
}
|
||||
|
||||
getOutput(): ReadonlyArray<string> {
|
||||
return this.output;
|
||||
}
|
||||
|
||||
clearOutput() {
|
||||
clear(this.output);
|
||||
}
|
||||
|
||||
readonly existMessage = "System Exit";
|
||||
exitCode: number;
|
||||
readonly resolvePath = (s: string) => s;
|
||||
readonly getExecutingFilePath = () => this.executingFilePath;
|
||||
readonly getCurrentDirectory = () => this.currentDirectory;
|
||||
exit(exitCode?: number) {
|
||||
this.exitCode = exitCode;
|
||||
throw new Error(this.existMessage);
|
||||
}
|
||||
readonly getEnvironmentVariable = notImplemented;
|
||||
}
|
||||
}
|
||||
Vendored
+1
-21
@@ -4233,11 +4233,7 @@ interface HTMLBodyElement extends HTMLElement {
|
||||
onafterprint: (this: HTMLBodyElement, ev: Event) => any;
|
||||
onbeforeprint: (this: HTMLBodyElement, ev: Event) => any;
|
||||
onbeforeunload: (this: HTMLBodyElement, ev: BeforeUnloadEvent) => any;
|
||||
onblur: (this: HTMLBodyElement, ev: FocusEvent) => any;
|
||||
onerror: (this: HTMLBodyElement, ev: ErrorEvent) => any;
|
||||
onfocus: (this: HTMLBodyElement, ev: FocusEvent) => any;
|
||||
onhashchange: (this: HTMLBodyElement, ev: HashChangeEvent) => any;
|
||||
onload: (this: HTMLBodyElement, ev: Event) => any;
|
||||
onmessage: (this: HTMLBodyElement, ev: MessageEvent) => any;
|
||||
onoffline: (this: HTMLBodyElement, ev: Event) => any;
|
||||
ononline: (this: HTMLBodyElement, ev: Event) => any;
|
||||
@@ -4246,7 +4242,6 @@ interface HTMLBodyElement extends HTMLElement {
|
||||
onpageshow: (this: HTMLBodyElement, ev: PageTransitionEvent) => any;
|
||||
onpopstate: (this: HTMLBodyElement, ev: PopStateEvent) => any;
|
||||
onresize: (this: HTMLBodyElement, ev: UIEvent) => any;
|
||||
onscroll: (this: HTMLBodyElement, ev: UIEvent) => any;
|
||||
onstorage: (this: HTMLBodyElement, ev: StorageEvent) => any;
|
||||
onunload: (this: HTMLBodyElement, ev: Event) => any;
|
||||
text: any;
|
||||
@@ -4901,10 +4896,6 @@ interface HTMLFrameElement extends HTMLElement, GetSVGDocument {
|
||||
* Sets or retrieves whether the user can resize the frame.
|
||||
*/
|
||||
noResize: boolean;
|
||||
/**
|
||||
* Raised when the object has been completely received from the server.
|
||||
*/
|
||||
onload: (this: HTMLFrameElement, ev: Event) => any;
|
||||
/**
|
||||
* Sets or retrieves whether the frame can be scrolled.
|
||||
*/
|
||||
@@ -4970,17 +4961,10 @@ interface HTMLFrameSetElement extends HTMLElement {
|
||||
onafterprint: (this: HTMLFrameSetElement, ev: Event) => any;
|
||||
onbeforeprint: (this: HTMLFrameSetElement, ev: Event) => any;
|
||||
onbeforeunload: (this: HTMLFrameSetElement, ev: BeforeUnloadEvent) => any;
|
||||
/**
|
||||
* Fires when the object loses the input focus.
|
||||
*/
|
||||
onblur: (this: HTMLFrameSetElement, ev: FocusEvent) => any;
|
||||
onerror: (this: HTMLFrameSetElement, ev: ErrorEvent) => any;
|
||||
/**
|
||||
* Fires when the object receives focus.
|
||||
*/
|
||||
onfocus: (this: HTMLFrameSetElement, ev: FocusEvent) => any;
|
||||
onhashchange: (this: HTMLFrameSetElement, ev: HashChangeEvent) => any;
|
||||
onload: (this: HTMLFrameSetElement, ev: Event) => any;
|
||||
onmessage: (this: HTMLFrameSetElement, ev: MessageEvent) => any;
|
||||
onoffline: (this: HTMLFrameSetElement, ev: Event) => any;
|
||||
ononline: (this: HTMLFrameSetElement, ev: Event) => any;
|
||||
@@ -4989,7 +4973,6 @@ interface HTMLFrameSetElement extends HTMLElement {
|
||||
onpageshow: (this: HTMLFrameSetElement, ev: PageTransitionEvent) => any;
|
||||
onpopstate: (this: HTMLFrameSetElement, ev: PopStateEvent) => any;
|
||||
onresize: (this: HTMLFrameSetElement, ev: UIEvent) => any;
|
||||
onscroll: (this: HTMLFrameSetElement, ev: UIEvent) => any;
|
||||
onstorage: (this: HTMLFrameSetElement, ev: StorageEvent) => any;
|
||||
onunload: (this: HTMLFrameSetElement, ev: Event) => any;
|
||||
/**
|
||||
@@ -5125,10 +5108,7 @@ interface HTMLIFrameElement extends HTMLElement, GetSVGDocument {
|
||||
* Sets or retrieves whether the user can resize the frame.
|
||||
*/
|
||||
noResize: boolean;
|
||||
/**
|
||||
* Raised when the object has been completely received from the server.
|
||||
*/
|
||||
onload: (this: HTMLIFrameElement, ev: Event) => any;
|
||||
|
||||
readonly sandbox: DOMSettableTokenList;
|
||||
/**
|
||||
* Sets or retrieves whether the frame can be scrolled.
|
||||
|
||||
Vendored
+5
-5
@@ -10,7 +10,7 @@ interface Array<T> {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: T, index: number, obj: Array<T>) => boolean, thisArg?: any): T | undefined;
|
||||
find(predicate: (value: T, index: number, obj: T[]) => boolean, thisArg?: any): T | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -21,7 +21,7 @@ interface Array<T> {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: T, index: number, obj: Array<T>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (value: T, index: number, obj: T[]) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Returns the this object after filling the section identified by start and end with value
|
||||
@@ -52,13 +52,13 @@ interface ArrayConstructor {
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from<T, U = T>(arrayLike: ArrayLike<T>, mapfn?: (v: T, k: number) => U, thisArg?: any): Array<U>;
|
||||
from<T, U = T>(arrayLike: ArrayLike<T>, mapfn?: (v: T, k: number) => U, thisArg?: any): U[];
|
||||
|
||||
/**
|
||||
* Returns a new array from a set of elements.
|
||||
* @param items A set of elements to include in the new array object.
|
||||
*/
|
||||
of<T>(...items: T[]): Array<T>;
|
||||
of<T>(...items: T[]): T[];
|
||||
}
|
||||
|
||||
interface DateConstructor {
|
||||
@@ -162,7 +162,7 @@ interface Math {
|
||||
* If any argument is NaN, the result is NaN.
|
||||
* If all arguments are either +0 or −0, the result is +0.
|
||||
*/
|
||||
hypot(...values: number[] ): number;
|
||||
hypot(...values: number[]): number;
|
||||
|
||||
/**
|
||||
* Returns the integral part of the a numeric expression, x, removing any fractional digits.
|
||||
|
||||
Vendored
+1
-1
@@ -54,7 +54,7 @@ interface ArrayConstructor {
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from<T, U = T>(iterable: Iterable<T>, mapfn?: (v: T, k: number) => U, thisArg?: any): Array<U>;
|
||||
from<T, U = T>(iterable: Iterable<T>, mapfn?: (v: T, k: number) => U, thisArg?: any): U[];
|
||||
}
|
||||
|
||||
interface ReadonlyArray<T> {
|
||||
|
||||
Vendored
+1
-1
@@ -8,7 +8,7 @@ declare namespace Reflect {
|
||||
function getPrototypeOf(target: object): object;
|
||||
function has(target: object, propertyKey: PropertyKey): boolean;
|
||||
function isExtensible(target: object): boolean;
|
||||
function ownKeys(target: object): Array<PropertyKey>;
|
||||
function ownKeys(target: object): PropertyKey[];
|
||||
function preventExtensions(target: object): boolean;
|
||||
function set(target: object, propertyKey: PropertyKey, value: any, receiver?: any): boolean;
|
||||
function setPrototypeOf(target: object, proto: any): boolean;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user