Merge branch 'master' into release-3.0

This commit is contained in:
Mohamed Hegazy
2018-07-10 23:24:34 -07:00
270 changed files with 7524 additions and 9113 deletions
+139 -57
View File
@@ -24,6 +24,10 @@ const baselineAccept = require("./scripts/build/baselineAccept");
const cmdLineOptions = require("./scripts/build/options");
const exec = require("./scripts/build/exec");
const browserify = require("./scripts/build/browserify");
const debounce = require("./scripts/build/debounce");
const prepend = require("./scripts/build/prepend");
const { removeSourceMaps } = require("./scripts/build/sourcemaps");
const { CancelSource, CancelError } = require("./scripts/build/cancellation");
const { libraryTargets, generateLibs } = require("./scripts/build/lib");
const { runConsoleTests, cleanTestDirs, writeTestConfigFile, refBaseline, localBaseline, refRwcBaseline, localRwcBaseline } = require("./scripts/build/tests");
@@ -44,17 +48,9 @@ const generateLocalizedDiagnosticMessagesJs = "scripts/generateLocalizedDiagnost
const buildProtocolJs = "scripts/buildProtocol.js";
const produceLKGJs = "scripts/produceLKG.js";
const word2mdJs = "scripts/word2md.js";
gulp.task("scripts", /*help*/ false, () => project.compile(scriptsProject), {
aliases: [
configurePrereleaseJs,
processDiagnosticMessagesJs,
generateLocalizedDiagnosticMessagesJs,
produceLKGJs,
buildProtocolJs,
word2mdJs
]
});
gulp.task("clean-scripts", /*help*/ false, () => project.clean(scriptsProject));
const scriptsTaskAliases = [configurePrereleaseJs, processDiagnosticMessagesJs, generateLocalizedDiagnosticMessagesJs, produceLKGJs, buildProtocolJs, word2mdJs];
gulp.task("scripts", /*help*/ false, () => project.compile(scriptsProject), { aliases: scriptsTaskAliases });
gulp.task("clean:scripts", /*help*/ false, () => project.clean(scriptsProject), { aliases: scriptsTaskAliases.map(alias => `clean:${alias}`)});
// Nightly management tasks
gulp.task(
@@ -73,7 +69,7 @@ gulp.task(
const importDefinitelyTypedTestsProject = "scripts/importDefinitelyTypedTests/tsconfig.json";
const importDefinitelyTypedTestsJs = "scripts/importDefinitelyTypedTests/importDefinitelyTypedTests.js";
gulp.task(importDefinitelyTypedTestsJs, /*help*/ false, () => project.compile(importDefinitelyTypedTestsProject));
gulp.task("clean:" + importDefinitelyTypedTestsJs, /*help*/ false, () => project.clean(importDefinitelyTypedTestsProject));
gulp.task(`clean:${importDefinitelyTypedTestsJs}`, /*help*/ false, () => project.clean(importDefinitelyTypedTestsProject));
gulp.task(
"importDefinitelyTypedTests",
@@ -95,7 +91,7 @@ gulp.task(diagnosticInformationMapTs, /*help*/ false, [processDiagnosticMessages
return exec(host, [processDiagnosticMessagesJs, diagnosticMessagesJson]);
}
});
gulp.task("clean:" + diagnosticInformationMapTs, /*help*/ false, () => del([diagnosticInformationMapTs, diagnosticMessagesGeneratedJson]));
gulp.task(`clean:${diagnosticInformationMapTs}`, /*help*/ false, () => del([diagnosticInformationMapTs, diagnosticMessagesGeneratedJson]));
const builtGeneratedDiagnosticMessagesJson = "built/local/diagnosticMessages.generated.json";
gulp.task(builtGeneratedDiagnosticMessagesJson, /*help*/ false, [diagnosticInformationMapTs], () =>
@@ -140,9 +136,10 @@ gulp.task(typescriptServicesProject, /*help*/ false, () => {
// NOTE: flatten services so that we can properly strip @internal
project.flatten(servicesProject, typescriptServicesProject, {
compilerOptions: {
"removeComments": true,
"removeComments": false,
"stripInternal": true,
"outFile": "typescriptServices.js"
"declarationMap": false,
"outFile": "typescriptServices.out.js" // must align with same task in jakefile. We fix this name below.
}
});
});
@@ -150,7 +147,16 @@ gulp.task(typescriptServicesProject, /*help*/ false, () => {
const typescriptServicesJs = "built/local/typescriptServices.js";
const typescriptServicesDts = "built/local/typescriptServices.d.ts";
gulp.task(typescriptServicesJs, /*help*/ false, ["lib", "generate-diagnostics", typescriptServicesProject], () =>
project.compile(typescriptServicesProject, { dts: files => files.pipe(convertConstEnums()) }),
project.compile(typescriptServicesProject, {
js: files => files
.pipe(prepend.file(copyright))
.pipe(rename("typescriptServices.js")),
dts: files => files
.pipe(removeSourceMaps())
.pipe(prepend.file(copyright))
.pipe(convertConstEnums())
.pipe(rename("typescriptServices.d.ts"))
}),
{ aliases: [typescriptServicesDts] });
const typescriptJs = "built/local/typescript.js";
@@ -179,29 +185,39 @@ gulp.task(typescriptStandaloneDts, /*help*/ false, [typescriptServicesDts], () =
// build all 'typescriptServices'-related outputs
gulp.task("services", /*help*/ false, [typescriptServicesJs, typescriptServicesDts, typescriptJs, typescriptDts, typescriptStandaloneDts]);
const useCompiler = cmdLineOptions.lkg ? "lkg" : "built";
const useCompilerDeps = cmdLineOptions.lkg ? ["lib", "generate-diagnostics"] : [typescriptServicesJs];
const tscProject = "src/tsc/tsconfig.json";
const tscJs = "built/local/tsc.js";
gulp.task(tscJs, /*help*/ false, [typescriptServicesJs], () => project.compile(tscProject, { typescript: "built" }));
gulp.task(tscJs, /*help*/ false, useCompilerDeps, () =>
project.compile(tscProject, {
typescript: useCompiler,
js: files => files.pipe(prepend.file(copyright))
}));
const tscReleaseProject = "src/tsc/tsconfig.release.json";
const tscReleaseJs = "built/local/tsc.release.js";
gulp.task(tscReleaseJs, /*help*/ false, () => project.compile(tscReleaseProject));
gulp.task(tscReleaseJs, /*help*/ false, () =>
project.compile(tscReleaseProject, {
js: files => files.pipe(prepend.file(copyright))
}));
const cancellationTokenProject = "src/cancellationToken/tsconfig.json";
const cancellationTokenJs = "built/local/cancellationToken.js";
gulp.task(cancellationTokenJs, /*help*/ false, [typescriptServicesJs], () => project.compile(cancellationTokenProject, { typescript: "built" }));
gulp.task(cancellationTokenJs, /*help*/ false, useCompilerDeps, () => project.compile(cancellationTokenProject, { typescript: useCompiler }));
const typingsInstallerProject = "src/typingsInstaller/tsconfig.json";
const typingsInstallerJs = "built/local/typingsInstaller.js";
gulp.task(typingsInstallerJs, /*help*/ false, [typescriptServicesJs], () => project.compile(typingsInstallerProject, { typescript: "built" }));
gulp.task(typingsInstallerJs, /*help*/ false, useCompilerDeps, () => project.compile(typingsInstallerProject, { typescript: useCompiler }));
const tsserverProject = "src/tsserver/tsconfig.json";
const tsserverJs = "built/local/tsserver.js";
gulp.task(tsserverJs, /*help*/ false, [typescriptServicesJs], () => project.compile(tsserverProject, { typescript: "built" }));
gulp.task(tsserverJs, /*help*/ false, useCompilerDeps, () => project.compile(tsserverProject, { typescript: useCompiler }));
const watchGuardProject = "src/watchGuard/tsconfig.json";
const watchGuardJs = "built/local/watchGuard.js";
gulp.task(watchGuardJs, /*help*/ false, [typescriptServicesJs], () => project.compile(watchGuardProject, { typescript: "built" }));
gulp.task(watchGuardJs, /*help*/ false, useCompilerDeps, () => project.compile(watchGuardProject, { typescript: useCompiler }));
const typesMapJson = "built/local/typesMap.json";
gulp.task(typesMapJson, /*help*/ false, [], () =>
@@ -216,21 +232,28 @@ gulp.task(tsserverlibraryProject, /*help*/ false, () => {
project.flatten("src/tsserver/tsconfig.json", tsserverlibraryProject, {
exclude: ["src/tsserver/server.ts"],
compilerOptions: {
"removeComments": true,
"removeComments": false,
"stripInternal": true,
"outFile": "tsserverlibrary.js"
"declarationMap": false,
"outFile": "tsserverlibrary.out.js" // must align with same task in jakefile. We fix this name below.
}
});
});
const tsserverlibraryJs = "built/local/tsserverlibrary.js";
const tsserverlibraryDts = "built/local/tsserverlibrary.d.ts";
gulp.task(tsserverlibraryJs, /*help*/ false, [typescriptServicesJs, tsserverlibraryProject], () =>
gulp.task(tsserverlibraryJs, /*help*/ false, useCompilerDeps.concat([tsserverlibraryProject]), () =>
project.compile(tsserverlibraryProject, {
js: files => files
.pipe(prepend.file(copyright))
.pipe(rename("tsserverlibrary.js")),
dts: files => files
.pipe(removeSourceMaps())
.pipe(prepend.file(copyright))
.pipe(convertConstEnums())
.pipe(append("\nexport = ts;\nexport as namespace ts;")),
typescript: "built"
.pipe(append("\nexport = ts;\nexport as namespace ts;"))
.pipe(rename("tsserverlibrary.d.ts")),
typescript: useCompiler
}), { aliases: [tsserverlibraryDts] });
gulp.task(
@@ -294,29 +317,29 @@ gulp.task(
// Task to build the tests infrastructure using the built compiler
const testRunnerProject = "src/testRunner/tsconfig.json";
const runJs = "built/local/run.js";
gulp.task(runJs, /*help*/ false, [typescriptServicesJs, tsserverlibraryDts], () => project.compile(testRunnerProject, { typescript: "built" }));
gulp.task(runJs, /*help*/ false, useCompilerDeps, () => project.compile(testRunnerProject, { typescript: useCompiler }));
gulp.task(
"tests",
"Builds the test infrastructure using the built compiler",
[runJs]);
[runJs, tsserverlibraryDts]);
gulp.task(
"runtests-parallel",
"Runs all the tests in parallel using the built run.js file. Optional arguments are: --t[ests]=category1|category2|... --d[ebug]=true.",
["build-rules", "tests"],
() => runConsoleTests(runJs, "min", /*runInParallel*/ true));
["build-rules", "tests", "services", tsserverlibraryDts],
() => runConsoleTests(runJs, "min", /*runInParallel*/ true, /*watchMode*/ false));
gulp.task(
"runtests",
"Runs the tests using the built run.js file. Optional arguments are: --t[ests]=regex --r[eporter]=[list|spec|json|<more>] --d[ebug]=true --color[s]=false --lint=true.",
["build-rules", "tests"],
() => runConsoleTests(runJs, "mocha-fivemat-progress-reporter", /*runInParallel*/ false));
["build-rules", "tests", "services", tsserverlibraryDts],
() => runConsoleTests(runJs, "mocha-fivemat-progress-reporter", /*runInParallel*/ false, /*watchMode*/ false));
const webTestServerProject = "tests/webTestServer.tsconfig.json";
const webTestServerJs = "tests/webTestServer.js";
gulp.task(webTestServerJs, /*help*/ false, [typescriptServicesJs], () => project.compile(webTestServerProject, { typescript: "built" }));
gulp.task("clean:" + webTestServerJs, /*help*/ false, () => project.clean(webTestServerProject));
gulp.task(webTestServerJs, /*help*/ false, useCompilerDeps, () => project.compile(webTestServerProject, { typescript: useCompiler }));
gulp.task(`clean:${webTestServerJs}`, /*help*/ false, () => project.clean(webTestServerProject));
const bundlePath = path.resolve("built/local/bundle.js");
@@ -392,8 +415,8 @@ gulp.task(
// Webhost
const webtscProject = "tests/webhost/webtsc.tsconfig.json";
const webtscJs = "tests/webhost/webtsc.js";
gulp.task(webtscJs, /*help*/ false, [typescriptServicesJs], () => project.compile(webtscProject, { typescript: "built" }));
gulp.task("clean:" + webtscJs, /*help*/ false, () => project.clean(webtscProject));
gulp.task(webtscJs, /*help*/ false, useCompilerDeps, () => project.compile(webtscProject, { typescript: useCompiler }));
gulp.task(`clean:${webtscJs}`, /*help*/ false, () => project.clean(webtscProject));
gulp.task("webhost", "Builds the tsc web host", [webtscJs], () =>
gulp.src("built/local/lib.d.ts")
@@ -402,8 +425,8 @@ gulp.task("webhost", "Builds the tsc web host", [webtscJs], () =>
// Perf compiler
const perftscProject = "tests/perftsc.tsconfig.json";
const perftscJs = "built/local/perftsc.js";
gulp.task(perftscJs, /*help*/ false, [typescriptServicesJs], () => project.compile(perftscProject, { typescript: "built" }));
gulp.task("clean:" + perftscJs, /*help*/ false, () => project.clean(perftscProject));
gulp.task(perftscJs, /*help*/ false, useCompilerDeps, () => project.compile(perftscProject, { typescript: useCompiler }));
gulp.task(`clean:${perftscJs}`, /*help*/ false, () => project.clean(perftscProject));
gulp.task(
"perftsc",
@@ -423,7 +446,7 @@ gulp.task(loggedIOJs, /*help*/ false, [], (done) => {
const instrumenterProject = "src/instrumenter/tsconfig.json";
const instrumenterJs = "built/local/instrumenter.js";
gulp.task(instrumenterJs, /*help*/ false, () => project.compile(instrumenterProject));
gulp.task("clean:" + instrumenterJs, /*help*/ false, () => project.clean(instrumenterProject));
gulp.task(`clean:${instrumenterJs}`, /*help*/ false, () => project.clean(instrumenterProject));
gulp.task(
"tsc-instrumented",
@@ -479,20 +502,37 @@ gulp.task(
gulp.task(
"watch-tsc",
/*help*/ false,
["watch-diagnostics", "watch-lib", typescriptServicesJs],
() => project.watch(tscProject, { typescript: "built" }));
["watch-diagnostics", "watch-lib"].concat(useCompilerDeps),
() => project.watch(tscProject, { typescript: useCompiler }));
const watchServicesPatterns = [
"src/compiler/**/*",
"src/jsTypings/**/*",
"src/services/**/*"
];
gulp.task(
"watch-services",
/*help*/ false,
["watch-diagnostics", "watch-lib", typescriptServicesJs],
() => project.watch(servicesProject, { typescript: "built" }));
["watch-diagnostics", "watch-lib"],
() => gulp.watch(watchServicesPatterns, ["services"]));
const watchLsslPatterns = [
...watchServicesPatterns,
"src/server/**/*",
"src/tsserver/tsconfig.json"
];
gulp.task(
"watch-lssl",
/*help*/ false,
() => gulp.watch(watchLsslPatterns, ["lssl"]));
gulp.task(
"watch-server",
/*help*/ false,
["watch-diagnostics", "watch-lib", typescriptServicesJs],
() => project.watch(tsserverProject, { typescript: "built" }));
["watch-diagnostics", "watch-lib"].concat(useCompilerDeps),
() => project.watch(tsserverProject, { typescript: useCompiler }));
gulp.task(
"watch-local",
@@ -500,22 +540,64 @@ gulp.task(
["watch-lib", "watch-tsc", "watch-services", "watch-server"]);
gulp.task(
"watch",
"Watches for changes to the build inputs for built/local/run.js executes runtests-parallel.",
[typescriptServicesJs],
() => project.watch(testRunnerProject, { typescript: "built" }, ["runtests-parallel"]));
"watch-runner",
/*help*/ false,
useCompilerDeps,
() => project.watch(testRunnerProject, { typescript: useCompiler }));
gulp.task("clean-built", /*help*/ false, ["clean:" + diagnosticInformationMapTs], () => del(["built"]));
const watchPatterns = [
runJs,
typescriptDts,
tsserverlibraryDts
];
gulp.task(
"watch",
"Watches for changes to the build inputs for built/local/run.js, then executes runtests-parallel.",
["build-rules", "watch-runner", "watch-services", "watch-lssl"],
() => {
/** @type {CancelSource | undefined} */
let runTestsSource;
const fn = debounce(() => {
runTests().catch(error => {
if (error instanceof CancelError) {
log.warn("Operation was canceled");
}
else {
log.error(error);
}
});
}, /*timeout*/ 100, { max: 500 });
gulp.watch(watchPatterns, () => project.wait().then(fn));
// NOTE: gulp.watch is far too slow when watching tests/cases/**/* as it first enumerates *every* file
const testFilePattern = /(\.ts|[\\/]tsconfig\.json)$/;
fs.watch("tests/cases", { recursive: true }, (_, file) => {
if (testFilePattern.test(file)) project.wait().then(fn);
});
function runTests() {
if (runTestsSource) runTestsSource.cancel();
runTestsSource = new CancelSource();
return cmdLineOptions.tests || cmdLineOptions.failed
? runConsoleTests(runJs, "mocha-fivemat-progress-reporter", /*runInParallel*/ false, /*watchMode*/ true, runTestsSource.token)
: runConsoleTests(runJs, "min", /*runInParallel*/ true, /*watchMode*/ true, runTestsSource.token);
}
});
gulp.task("clean-built", /*help*/ false, [`clean:${diagnosticInformationMapTs}`], () => del(["built"]));
gulp.task(
"clean",
"Cleans the compiler output, declare files, and tests",
[
"clean:" + importDefinitelyTypedTestsJs,
"clean:" + webtscJs,
"clean:" + perftscJs,
"clean:" + instrumenterJs,
"clean:" + webTestServerJs,
"clean-scripts",
`clean:${importDefinitelyTypedTestsJs}`,
`clean:${webtscJs}`,
`clean:${perftscJs}`,
`clean:${instrumenterJs}`,
`clean:${webTestServerJs}`,
"clean:scripts",
"clean-rules",
"clean-built"
]);
+150 -50
View File
@@ -9,6 +9,9 @@ const fold = require("travis-fold");
const ts = require("./lib/typescript");
const del = require("del");
const getDirSize = require("./scripts/build/getDirSize");
const { base64VLQFormatEncode } = require("./scripts/build/sourcemaps");
const needsUpdate = require("./scripts/build/needsUpdate");
const { flatten } = require("./scripts/build/project");
// add node_modules to path so we don't need global modules, prefer the modules by adding them first
var nodeModulesPathPrefix = path.resolve("./node_modules/.bin/") + path.delimiter;
@@ -64,9 +67,14 @@ Paths.typesMapOutput = "built/local/typesMap.json";
Paths.typescriptFile = "built/local/typescript.js";
Paths.servicesFile = "built/local/typescriptServices.js";
Paths.servicesDefinitionFile = "built/local/typescriptServices.d.ts";
Paths.servicesOutFile = "built/local/typescriptServices.out.js";
Paths.servicesDefinitionOutFile = "built/local/typescriptServices.out.d.ts";
Paths.typescriptDefinitionFile = "built/local/typescript.d.ts";
Paths.typescriptStandaloneDefinitionFile = "built/local/typescript_standalone.d.ts";
Paths.tsserverLibraryFile = "built/local/tsserverlibrary.js";
Paths.tsserverLibraryDefinitionFile = "built/local/tsserverlibrary.d.ts";
Paths.tsserverLibraryOutFile = "built/local/tsserverlibrary.out.js";
Paths.tsserverLibraryDefinitionOutFile = "built/local/tsserverlibrary.out.d.ts";
Paths.baselines = {};
Paths.baselines.local = "tests/baselines/local";
Paths.baselines.localTest262 = "tests/baselines/test262/local";
@@ -101,7 +109,9 @@ const ConfigFileFor = {
runjs: "src/testRunner",
lint: "scripts/tslint",
scripts: "scripts",
all: "src"
all: "src",
typescriptServices: "built/local/typescriptServices.tsconfig.json",
tsserverLibrary: "built/local/tsserverlibrary.tsconfig.json",
};
const ExpectedLKGFiles = [
@@ -124,13 +134,18 @@ desc("Builds the full compiler and services");
task(TaskNames.local, [
TaskNames.buildFoldStart,
TaskNames.coreBuild,
Paths.servicesDefinitionFile,
Paths.typescriptFile,
Paths.typescriptDefinitionFile,
Paths.typescriptStandaloneDefinitionFile,
Paths.tsserverLibraryDefinitionFile,
TaskNames.localize,
TaskNames.buildFoldEnd
]);
task("default", [TaskNames.local]);
const RunTestsPrereqs = [TaskNames.lib, Paths.servicesDefinitionFile, Paths.tsserverLibraryDefinitionFile];
const RunTestsPrereqs = [TaskNames.lib, Paths.servicesDefinitionFile, Paths.typescriptDefinitionFile, Paths.tsserverLibraryDefinitionFile];
desc("Runs all the tests in parallel using the built run.js file. Optional arguments are: t[ests]=category1|category2|... d[ebug]=true.");
task(TaskNames.runtestsParallel, RunTestsPrereqs, function () {
tsbuild([ConfigFileFor.runjs], true, () => {
@@ -172,6 +187,9 @@ task(TaskNames.lkg, [
TaskNames.release,
TaskNames.local,
Paths.servicesDefinitionFile,
Paths.typescriptFile,
Paths.typescriptDefinitionFile,
Paths.typescriptStandaloneDefinitionFile,
Paths.tsserverLibraryDefinitionFile,
Paths.releaseCompiler,
...libraryTargets
@@ -333,64 +351,146 @@ file(Paths.diagnosticInformationMap, [Paths.diagnosticMessagesJson], function ()
});
}, { async: true });
// tsserverlibrary.d.ts
file(Paths.tsserverLibraryDefinitionFile, [TaskNames.coreBuild], function() {
const sources = ["compiler.d.ts", "jsTyping.d.ts", "services.d.ts", "server.d.ts"].map(f => path.join(Paths.builtLocal, f));
let output = "";
for (const f of sources) {
output = output + "\n" + removeConstModifierFromEnumDeclarations(readFileSync(f));
}
output = output + "\nexport = ts;\nexport as namespace ts;";
fs.writeFileSync(Paths.tsserverLibraryDefinitionFile, output, { encoding: "utf-8" });
file(ConfigFileFor.tsserverLibrary, [], function () {
flatten("src/tsserver/tsconfig.json", ConfigFileFor.tsserverLibrary, {
exclude: ["src/tsserver/server.ts"],
compilerOptions: {
"removeComments": false,
"stripInternal": true,
"declarationMap": false,
"outFile": "tsserverlibrary.out.js"
}
})
});
// typescriptservices.d.ts
file(Paths.servicesDefinitionFile, [TaskNames.coreBuild], function() {
// Generate a config file
const files = [];
recur(`src/services/tsconfig.json`);
// tsserverlibrary.js
// tsserverlibrary.d.ts
file(Paths.tsserverLibraryFile, [TaskNames.coreBuild, ConfigFileFor.tsserverLibrary], function() {
tsbuild(ConfigFileFor.tsserverLibrary, false, () => {
if (needsUpdate([Paths.tsserverLibraryOutFile, Paths.tsserverLibraryDefinitionOutFile], [Paths.tsserverLibraryFile, Paths.tsserverLibraryDefinitionFile])) {
const copyright = readFileSync(Paths.copyright);
const config = {
extends: "../../src/tsconfig-base",
let libraryDefinitionContent = readFileSync(Paths.tsserverLibraryDefinitionOutFile);
libraryDefinitionContent = copyright + removeConstModifierFromEnumDeclarations(libraryDefinitionContent);
libraryDefinitionContent += "\nexport = ts;\nexport as namespace ts;";
fs.writeFileSync(Paths.tsserverLibraryDefinitionFile, libraryDefinitionContent, "utf8");
let libraryContent = readFileSync(Paths.tsserverLibraryOutFile);
libraryContent = copyright + libraryContent;
fs.writeFileSync(Paths.tsserverLibraryFile, libraryContent, "utf8");
// adjust source map for tsserverlibrary.js
let libraryMapContent = readFileSync(Paths.tsserverLibraryOutFile + ".map");
const map = JSON.parse(libraryMapContent);
const lineStarts = /**@type {*}*/(ts).computeLineStarts(copyright);
let prependMappings = "";
for (let i = 1; i < lineStarts.length; i++) {
prependMappings += ";";
}
const offset = copyright.length - lineStarts[lineStarts.length - 1];
if (offset > 0) {
prependMappings += base64VLQFormatEncode(offset) + ",";
}
const outputMap = {
version: map.version,
file: map.file,
sources: map.sources,
sourceRoot: map.sourceRoot,
mappings: prependMappings + map.mappings,
names: map.names,
sourcesContent: map.sourcesContent
};
libraryMapContent = JSON.stringify(outputMap);
fs.writeFileSync(Paths.tsserverLibraryFile + ".map", libraryMapContent);
}
complete();
});
}, { async: true });
task(Paths.tsserverLibraryDefinitionFile, [Paths.tsserverLibraryFile]);
file(ConfigFileFor.typescriptServices, [], function () {
flatten("src/services/tsconfig.json", ConfigFileFor.typescriptServices, {
compilerOptions: {
"removeComments": false,
"stripInternal": true,
"outFile": "typescriptServices.js"
},
files
};
"declarationMap": false,
"outFile": "typescriptServices.out.js"
}
});
});
const configFilePath = `built/local/typescriptServices.tsconfig.json`;
fs.writeFileSync(configFilePath, JSON.stringify(config, undefined, 2));
tsbuild(configFilePath, false, () => {
const servicesContent = readFileSync(Paths.servicesDefinitionFile);
const servicesContentWithoutConstEnums = removeConstModifierFromEnumDeclarations(servicesContent);
fs.writeFileSync(Paths.servicesDefinitionFile, servicesContentWithoutConstEnums);
// Also build typescript.js, typescript.js.map, and typescript.d.ts
// typescriptServices.js
// typescriptServices.d.ts
file(Paths.servicesFile, [TaskNames.coreBuild, ConfigFileFor.typescriptServices], function() {
tsbuild(ConfigFileFor.typescriptServices, false, () => {
if (needsUpdate([Paths.servicesOutFile, Paths.servicesDefinitionOutFile], [Paths.servicesFile, Paths.servicesDefinitionFile])) {
const copyright = readFileSync(Paths.copyright);
let servicesDefinitionContent = readFileSync(Paths.servicesDefinitionOutFile);
servicesDefinitionContent = copyright + removeConstModifierFromEnumDeclarations(servicesDefinitionContent);
fs.writeFileSync(Paths.servicesDefinitionFile, servicesDefinitionContent, "utf8");
let servicesContent = readFileSync(Paths.servicesOutFile);
servicesContent = copyright + servicesContent;
fs.writeFileSync(Paths.servicesFile, servicesContent, "utf8");
// adjust source map for typescriptServices.js
let servicesMapContent = readFileSync(Paths.servicesOutFile + ".map");
const map = JSON.parse(servicesMapContent);
const lineStarts = /**@type {*}*/(ts).computeLineStarts(copyright);
let prependMappings = "";
for (let i = 1; i < lineStarts.length; i++) {
prependMappings += ";";
}
const offset = copyright.length - lineStarts[lineStarts.length - 1];
if (offset > 0) {
prependMappings += base64VLQFormatEncode(offset) + ",";
}
const outputMap = {
version: map.version,
file: map.file,
sources: map.sources,
sourceRoot: map.sourceRoot,
mappings: prependMappings + map.mappings,
names: map.names,
sourcesContent: map.sourcesContent
};
servicesMapContent = JSON.stringify(outputMap);
fs.writeFileSync(Paths.servicesFile + ".map", servicesMapContent);
}
complete();
});
}, { async: true });
task(Paths.servicesDefinitionFile, [Paths.servicesFile]);
// typescript.js
// typescript.d.ts
file(Paths.typescriptFile, [Paths.servicesFile], function() {
if (needsUpdate([Paths.servicesFile, Paths.servicesDefinitionFile], [Paths.typescriptFile, Paths.typescriptDefinitionFile])) {
jake.cpR(Paths.servicesFile, Paths.typescriptFile);
if (fs.existsSync(Paths.servicesFile + ".map")) {
jake.cpR(Paths.servicesFile + ".map", Paths.typescriptFile + ".map");
}
fs.writeFileSync(Paths.typescriptDefinitionFile, servicesContentWithoutConstEnums + "\r\nexport = ts", { encoding: "utf-8" });
// And typescript_standalone.d.ts
fs.writeFileSync(Paths.typescriptStandaloneDefinitionFile, servicesContentWithoutConstEnums.replace(/declare (namespace|module) ts(\..+)? \{/g, 'declare module "typescript" {'), { encoding: "utf-8"});
complete();
});
function recur(configPath) {
const cfgFile = readJson(configPath);
if (cfgFile.references) {
for (const ref of cfgFile.references) {
recur(path.join(path.dirname(configPath), ref.path, "tsconfig.json"));
}
}
for (const file of cfgFile.files) {
files.push(path.join(`../../`, path.dirname(configPath), file));
}
const content = readFileSync(Paths.servicesDefinitionFile);
fs.writeFileSync(Paths.typescriptDefinitionFile, content + "\r\nexport = ts;", { encoding: "utf-8" });
}
}, { async: true });
});
task(Paths.typescriptDefinitionFile, [Paths.typescriptFile]);
// typescript_standalone.d.ts
file(Paths.typescriptStandaloneDefinitionFile, [Paths.servicesDefinitionFile], function() {
if (needsUpdate(Paths.servicesDefinitionFile, Paths.typescriptStandaloneDefinitionFile)) {
const content = readFileSync(Paths.servicesDefinitionFile);
fs.writeFileSync(Paths.typescriptStandaloneDefinitionFile, content.replace(/declare (namespace|module) ts(\..+)? \{/g, 'declare module "typescript" {'), { encoding: "utf-8"});
}
});
function getLibraryTargets() {
/** @type {{ libs: string[], paths?: Record<string, string>, sources?: Record<string, string[]> }} */
@@ -765,4 +865,4 @@ function getDiffTool() {
*/
function removeConstModifierFromEnumDeclarations(text) {
return text.replace(/^(\s*)(export )?const enum (\S+) {(\s*)$/gm, '$1$2enum $3 {$4');
}
}
+1181 -1180
View File
File diff suppressed because it is too large Load Diff
+15 -101
View File
@@ -1,120 +1,34 @@
// @ts-check
const Browserify = require("browserify");
const Vinyl = require("vinyl");
const fs = require("fs");
const path = require("path");
const convertMap = require("convert-source-map");
const applySourceMap = require("vinyl-sourcemaps-apply");
const { Transform, Readable } = require("stream");
const browserify = require("browserify");
const Vinyl = require("./vinyl");
const { Transform } = require("stream");
const { streamFromFile } = require("./utils");
const { replaceContents } = require("./sourcemaps");
module.exports = browserify;
module.exports = browserifyFile;
/**
* @param {import("browserify").Options} [opts]
*/
function browserify(opts) {
function browserifyFile(opts) {
return new Transform({
objectMode: true,
/**
* @param {string | Buffer | File} input
* @param {string | Buffer | Vinyl} input
*/
transform(input, _, cb) {
if (typeof input === "string" || Buffer.isBuffer(input)) return cb(new Error("Only Vinyl files are supported."));
try {
const sourceMap = input.sourceMap;
const cwd = input.cwd || process.cwd();
const base = input.base || cwd;
const output = /**@type {File}*/(new Vinyl({ path: input.path, base: input.base }));
const stream = streamFromFile(input);
const b = new Browserify(Object.assign({}, opts, { debug: !!sourceMap, basedir: input.base }));
b.add(stream, { file: input.path, basedir: input.base });
b.bundle((err, contents) => {
if (err) return cb(err);
output.contents = contents;
if (sourceMap) {
output.sourceMap = typeof sourceMap === "string" ? JSON.parse(sourceMap) : sourceMap;
const sourceRoot = output.sourceMap.sourceRoot;
makeAbsoluteSourceMap(cwd, base, output.sourceMap);
const stringContents = contents.toString("utf8");
const newSourceMapConverter = convertMap.fromSource(stringContents);
if (newSourceMapConverter) {
const newSourceMap = newSourceMapConverter.toObject();
makeAbsoluteSourceMap(cwd, base, newSourceMap);
applySourceMap(output, newSourceMap);
makeRelativeSourceMap(cwd, base, sourceRoot, output.sourceMap);
output.contents = new Buffer(convertMap.removeComments(stringContents), "utf8");
}
}
cb(null, output);
});
browserify(Object.assign({}, opts, { debug: !!input.sourceMap, basedir: input.base }))
.add(streamFromFile(input), { file: input.path, basedir: input.base })
.bundle((err, contents) => {
if (err) return cb(err);
cb(null, replaceContents(input, contents));
});
}
catch (e) {
cb(e);
}
}
});
}
/**
* @param {string | undefined} cwd
* @param {string | undefined} base
* @param {RawSourceMap} sourceMap
*
* @typedef RawSourceMap
* @property {string} version
* @property {string} file
* @property {string} [sourceRoot]
* @property {string[]} sources
* @property {string[]} [sourcesContents]
* @property {string} mappings
* @property {string[]} [names]
*/
function makeAbsoluteSourceMap(cwd = process.cwd(), base = "", sourceMap) {
const sourceRoot = sourceMap.sourceRoot || "";
const resolvedBase = path.resolve(cwd, base);
const resolvedSourceRoot = path.resolve(resolvedBase, sourceRoot);
sourceMap.file = path.resolve(resolvedBase, sourceMap.file).replace(/\\/g, "/");
sourceMap.sources = sourceMap.sources.map(source => path.resolve(resolvedSourceRoot, source).replace(/\\/g, "/"));
sourceMap.sourceRoot = "";
}
/**
* @param {string | undefined} cwd
* @param {string | undefined} base
* @param {string} sourceRoot
* @param {RawSourceMap} sourceMap
*/
function makeRelativeSourceMap(cwd = process.cwd(), base = "", sourceRoot, sourceMap) {
makeAbsoluteSourceMap(cwd, base, sourceMap);
const resolvedBase = path.resolve(cwd, base);
const resolvedSourceRoot = path.resolve(resolvedBase, sourceRoot);
sourceMap.file = path.relative(resolvedBase, sourceMap.file).replace(/\\/g, "/");
sourceMap.sources = sourceMap.sources.map(source => path.relative(resolvedSourceRoot, source).replace(/\\/g, "/"));
sourceMap.sourceRoot = sourceRoot;
}
/**
* @param {File} file
*/
function streamFromFile(file) {
return file.isBuffer() ? streamFromBuffer(file.contents) :
file.isStream() ? file.contents :
fs.createReadStream(file.path, { autoClose: true });
}
/**
* @param {Buffer} buffer
*/
function streamFromBuffer(buffer) {
return new Readable({
read() {
this.push(buffer);
this.push(null);
}
});
}
/**
* @typedef {import("vinyl") & { sourceMap?: any }} File
*/
void 0;
}
+71
View File
@@ -0,0 +1,71 @@
// @ts-check
const symSource = Symbol("CancelToken.source");
const symToken = Symbol("CancelSource.token");
const symCancellationRequested = Symbol("CancelSource.cancellationRequested");
const symCancellationCallbacks = Symbol("CancelSource.cancellationCallbacks");
class CancelSource {
constructor() {
this[symCancellationRequested] = false;
this[symCancellationCallbacks] = [];
}
/** @type {CancelToken} */
get token() {
return this[symToken] || (this[symToken] = new CancelToken(this));
}
cancel() {
if (!this[symCancellationRequested]) {
this[symCancellationRequested] = true;
for (const callback of this[symCancellationCallbacks]) {
callback();
}
}
}
}
exports.CancelSource = CancelSource;
class CancelToken {
/**
* @param {CancelSource} source
*/
constructor(source) {
if (source[symToken]) return source[symToken];
this[symSource] = source;
}
/** @type {boolean} */
get cancellationRequested() {
return this[symSource][symCancellationRequested];
}
/**
* @param {() => void} callback
*/
subscribe(callback) {
const source = this[symSource];
if (source[symCancellationRequested]) {
callback();
return;
}
source[symCancellationCallbacks].push(callback);
return {
unsubscribe() {
const index = source[symCancellationCallbacks].indexOf(callback);
if (index !== -1) source[symCancellationCallbacks].splice(index, 1);
}
};
}
}
exports.CancelToken = CancelToken;
class CancelError extends Error {
constructor(message = "Operation was canceled") {
super(message);
this.name = "CancelError";
}
}
exports.CancelError = CancelError;
+31
View File
@@ -0,0 +1,31 @@
// @ts-check
module.exports = debounce;
/**
* @param {() => void} cb
* @param {number} timeout
* @param {DebounceOptions} [opts]
*
* @typedef DebounceOptions
* @property {number} [max]
*/
function debounce(cb, timeout, opts = {}) {
if (timeout < 10) timeout = 10;
let max = opts.max || 10;
if (max < timeout) max = timeout;
let minTimer;
let maxTimer;
return trigger;
function trigger() {
if (max > timeout && !maxTimer) maxTimer = setTimeout(done, max);
if (minTimer) clearTimeout(minTimer);
minTimer = setTimeout(done, timeout);
}
function done() {
if (maxTimer) maxTimer = void clearTimeout(maxTimer);
if (minTimer) minTimer = void clearTimeout(minTimer);
cb();
}
}
+16 -3
View File
@@ -3,6 +3,7 @@ const cp = require("child_process");
const log = require("fancy-log"); // was `require("gulp-util").log (see https://github.com/gulpjs/gulp-util)
const isWin = /^win/.test(process.platform);
const chalk = require("./chalk");
const { CancelToken, CancelError } = require("./cancellation");
module.exports = exec;
@@ -10,8 +11,11 @@ module.exports = exec;
* Executes the provided command once with the supplied arguments.
* @param {string} cmd
* @param {string[]} args
* @param {object} [options]
* @param {boolean} [options.ignoreExitCode]
* @param {ExecOptions} [options]
*
* @typedef ExecOptions
* @property {boolean} [ignoreExitCode]
* @property {CancelToken} [cancelToken]
*/
function exec(cmd, args, options = {}) {
return /**@type {Promise<{exitCode: number}>}*/(new Promise((resolve, reject) => {
@@ -20,7 +24,13 @@ function exec(cmd, args, options = {}) {
const subshellFlag = isWin ? "/c" : "-c";
const command = isWin ? [possiblyQuote(cmd), ...args] : [`${cmd} ${args.join(" ")}`];
const ex = cp.spawn(isWin ? "cmd" : "/bin/sh", [subshellFlag, ...command], { stdio: "inherit", windowsVerbatimArguments: true });
const subscription = options.cancelToken && options.cancelToken.subscribe(() => {
ex.kill("SIGINT");
ex.kill("SIGTERM");
reject(new CancelError());
});
ex.on("exit", exitCode => {
subscription && subscription.unsubscribe();
if (exitCode === 0 || options.ignoreExitCode) {
resolve({ exitCode });
}
@@ -28,7 +38,10 @@ function exec(cmd, args, options = {}) {
reject(new Error(`Process exited with code: ${exitCode}`));
}
});
ex.on("error", reject);
ex.on("error", error => {
subscription && subscription.unsubscribe();
reject(error);
});
}));
}
+7 -3
View File
@@ -4,7 +4,7 @@ const os = require("os");
/** @type {CommandLineOptions} */
module.exports = minimist(process.argv.slice(2), {
boolean: ["debug", "inspect", "light", "colors", "lint", "soft", "fix", "failed", "keepFailed"],
boolean: ["debug", "dirty", "inspect", "light", "colors", "lint", "lkg", "soft", "fix", "failed", "keepFailed"],
string: ["browser", "tests", "host", "reporter", "stackTraceLimit", "timeout"],
alias: {
"b": "browser",
@@ -33,17 +33,21 @@ module.exports = minimist(process.argv.slice(2), {
fix: process.env.fix || process.env.f,
workers: process.env.workerCount || os.cpus().length,
failed: false,
keepFailed: false
keepFailed: false,
lkg: false,
dirty: false
}
});
/**
* @typedef TypedOptions
* @property {boolean} debug
* @property {boolean} dirty
* @property {boolean} inspect
* @property {boolean} light
* @property {boolean} colors
* @property {boolean} lint
* @property {boolean} lkg
* @property {boolean} soft
* @property {boolean} fix
* @property {string} browser
@@ -56,7 +60,7 @@ module.exports = minimist(process.argv.slice(2), {
* @property {string|number} timeout
* @property {boolean} failed
* @property {boolean} keepFailed
*
*
* @typedef {import("minimist").ParsedArgs & TypedOptions} CommandLineOptions
*/
void 0;
+66
View File
@@ -0,0 +1,66 @@
// @ts-check
const stream = require("stream");
const Vinyl = require("./vinyl");
const ts = require("../../lib/typescript");
const fs = require("fs");
const { base64VLQFormatEncode } = require("./sourcemaps");
module.exports = exports = prepend;
/**
* @param {string | ((file: Vinyl) => string)} data
*/
function prepend(data) {
return new stream.Transform({
objectMode: true,
/**
* @param {string | Buffer | Vinyl} input
* @param {(error: Error, data?: any) => void} cb
*/
transform(input, _, cb) {
if (typeof input === "string" || Buffer.isBuffer(input)) return cb(new Error("Only Vinyl files are supported."));
if (!input.isBuffer()) return cb(new Error("Streams not supported."));
try {
const output = input.clone();
const prependContent = typeof data === "function" ? data(input) : data;
output.contents = Buffer.concat([Buffer.from(prependContent, "utf8"), input.contents]);
if (input.sourceMap) {
if (typeof input.sourceMap === "string") input.sourceMap = /**@type {import("./sourcemaps").RawSourceMap}*/(JSON.parse(input.sourceMap));
const lineStarts = /**@type {*}*/(ts).computeLineStarts(prependContent);
let prependMappings = "";
for (let i = 1; i < lineStarts.length; i++) {
prependMappings += ";";
}
const offset = prependContent.length - lineStarts[lineStarts.length - 1];
if (offset > 0) {
prependMappings += base64VLQFormatEncode(offset) + ",";
}
output.sourceMap = {
version: input.sourceMap.version,
file: input.sourceMap.file,
sources: input.sourceMap.sources,
sourceRoot: input.sourceMap.sourceRoot,
mappings: prependMappings + input.sourceMap.mappings,
names: input.names,
sourcesContent: input.sourcesContent
};
}
return cb(null, output);
}
catch (e) {
return cb(e);
}
}
})
}
exports.prepend = prepend;
/**
* @param {string | ((file: Vinyl) => string)} file
*/
function prependFile(file) {
const data = typeof file === "string" ? fs.readFileSync(file, "utf8") :
vinyl => fs.readFileSync(file(vinyl), "utf8");
return prepend(data)
}
exports.file = prependFile;
+21
View File
@@ -209,6 +209,27 @@ function flatten(projectSpec, flattenedProjectSpec, options = {}) {
}
exports.flatten = flatten;
/**
* Returns a Promise that resolves when all pending build tasks have completed
*/
function wait() {
return new Promise(resolve => {
if (compilationGulp.allDone()) {
resolve();
}
else {
const onDone = () => {
compilationGulp.removeListener("onDone", onDone);
compilationGulp.removeListener("err", onDone);
resolve();
};
compilationGulp.on("stop", onDone);
compilationGulp.on("err", onDone);
}
});
}
exports.wait = wait;
/**
* Resolve a TypeScript specifier into a fully-qualified module specifier and any requisite dependencies.
* @param {string} typescript An unresolved module specifier to a TypeScript version.
+143
View File
@@ -0,0 +1,143 @@
// @ts-check
const path = require("path");
const Vinyl = require("./vinyl");
const convertMap = require("convert-source-map");
const applySourceMap = require("vinyl-sourcemaps-apply");
const through2 = require("through2");
/**
* @param {Vinyl} input
* @param {string | Buffer} contents
* @param {string | RawSourceMap} [sourceMap]
*/
function replaceContents(input, contents, sourceMap) {
const output = input.clone();
output.contents = typeof contents === "string" ? Buffer.from(contents, "utf8") : contents;
if (input.sourceMap) {
output.sourceMap = typeof input.sourceMap === "string" ? /**@type {RawSourceMap}*/(JSON.parse(input.sourceMap)) : input.sourceMap;
if (typeof sourceMap === "string") {
sourceMap = /**@type {RawSourceMap}*/(JSON.parse(sourceMap));
}
else if (sourceMap === undefined) {
const stringContents = typeof contents === "string" ? contents : contents.toString("utf8");
const newSourceMapConverter = convertMap.fromSource(stringContents);
if (newSourceMapConverter) {
sourceMap = /**@type {RawSourceMap}*/(newSourceMapConverter.toObject());
output.contents = new Buffer(convertMap.removeMapFileComments(stringContents), "utf8");
}
}
if (sourceMap) {
const cwd = input.cwd || process.cwd();
const base = input.base || cwd;
const sourceRoot = output.sourceMap.sourceRoot;
makeAbsoluteSourceMap(cwd, base, output.sourceMap);
makeAbsoluteSourceMap(cwd, base, sourceMap);
applySourceMap(output, sourceMap);
makeRelativeSourceMap(cwd, base, sourceRoot, output.sourceMap);
}
else {
output.sourceMap = undefined;
}
}
return output;
}
exports.replaceContents = replaceContents;
function removeSourceMaps() {
return through2.obj((/**@type {Vinyl}*/file, _, cb) => {
if (file.sourceMap && file.isBuffer()) {
file.contents = Buffer.from(convertMap.removeMapFileComments(file.contents.toString("utf8")), "utf8");
file.sourceMap = undefined;
}
cb(null, file);
});
}
exports.removeSourceMaps = removeSourceMaps;
/**
* @param {string | undefined} cwd
* @param {string | undefined} base
* @param {RawSourceMap} sourceMap
*
* @typedef RawSourceMap
* @property {string} version
* @property {string} file
* @property {string} [sourceRoot]
* @property {string[]} sources
* @property {string[]} [sourcesContent]
* @property {string} mappings
* @property {string[]} [names]
*/
function makeAbsoluteSourceMap(cwd = process.cwd(), base = "", sourceMap) {
const sourceRoot = sourceMap.sourceRoot || "";
const resolvedBase = path.resolve(cwd, base);
const resolvedSourceRoot = path.resolve(resolvedBase, sourceRoot);
sourceMap.file = path.resolve(resolvedBase, sourceMap.file).replace(/\\/g, "/");
sourceMap.sources = sourceMap.sources.map(source => path.resolve(resolvedSourceRoot, source).replace(/\\/g, "/"));
sourceMap.sourceRoot = "";
}
exports.makeAbsoluteSourceMap = makeAbsoluteSourceMap;
/**
* @param {string | undefined} cwd
* @param {string | undefined} base
* @param {string} sourceRoot
* @param {RawSourceMap} sourceMap
*/
function makeRelativeSourceMap(cwd = process.cwd(), base = "", sourceRoot, sourceMap) {
makeAbsoluteSourceMap(cwd, base, sourceMap);
const resolvedBase = path.resolve(cwd, base);
const resolvedSourceRoot = path.resolve(resolvedBase, sourceRoot);
sourceMap.file = path.relative(resolvedBase, sourceMap.file).replace(/\\/g, "/");
sourceMap.sources = sourceMap.sources.map(source => path.relative(resolvedSourceRoot, source).replace(/\\/g, "/"));
sourceMap.sourceRoot = sourceRoot;
}
exports.makeRelativeSourceMap = makeRelativeSourceMap;
/**
* @param {string} message
* @returns {never}
*/
function fail(message) {
throw new Error(message);
}
/**
* @param {number} value
*/
function base64FormatEncode(value) {
return value < 0 ? fail("Invalid value") :
value < 26 ? 0x41 /*A*/ + value :
value < 52 ? 0x61 /*a*/ + value - 26 :
value < 62 ? 0x30 /*0*/ + value - 52 :
value === 62 ? 0x2B /*+*/ :
value === 63 ? 0x2F /*/*/ :
fail("Invalid value");
}
/**
* @param {number} value
*/
function base64VLQFormatEncode(value) {
if (value < 0) {
value = ((-value) << 1) + 1;
}
else {
value = value << 1;
}
// Encode 5 bits at a time starting from least significant bits
let result = "";
do {
let currentDigit = value & 31; // 11111
value = value >> 5;
if (value > 0) {
// There are still more digits to decode, set the msb (6th bit)
currentDigit = currentDigit | 32;
}
result += String.fromCharCode(base64FormatEncode(currentDigit));
} while (value > 0);
return result;
}
exports.base64VLQFormatEncode = base64VLQFormatEncode;
+108 -106
View File
@@ -1,4 +1,5 @@
// @ts-check
const gulp = require("./gulp");
const del = require("del");
const fs = require("fs");
const os = require("os");
@@ -6,13 +7,8 @@ const path = require("path");
const mkdirP = require("./mkdirp");
const cmdLineOptions = require("./options");
const exec = require("./exec");
const runSequence = require("run-sequence");
const finished = require("./finished");
const log = require("fancy-log"); // was `require("gulp-util").log (see https://github.com/gulpjs/gulp-util)
const nodeModulesPathPrefix = path.resolve("./node_modules/.bin/");
const isWin = /^win/.test(process.platform);
const mocha = path.join(nodeModulesPathPrefix, "mocha") + (isWin ? ".cmd" : "");
const mochaJs = require.resolve("mocha/bin/_mocha");
exports.localBaseline = "tests/baselines/local/";
exports.refBaseline = "tests/baselines/reference/";
@@ -24,8 +20,10 @@ exports.localTest262Baseline = "internal/baselines/test262/local";
* @param {string} runJs
* @param {string} defaultReporter
* @param {boolean} runInParallel
* @param {boolean} watchMode
* @param {InstanceType<typeof import("./cancellation").CancelToken>} [cancelToken]
*/
function runConsoleTests(runJs, defaultReporter, runInParallel) {
async function runConsoleTests(runJs, defaultReporter, runInParallel, watchMode, cancelToken) {
let testTimeout = cmdLineOptions.timeout;
let tests = cmdLineOptions.tests;
const lintFlag = cmdLineOptions.lint;
@@ -36,112 +34,116 @@ function runConsoleTests(runJs, defaultReporter, runInParallel) {
const stackTraceLimit = cmdLineOptions.stackTraceLimit;
const testConfigFile = "test.config";
const failed = cmdLineOptions.failed;
const keepFailed = cmdLineOptions.keepFailed || failed;
return cleanTestDirs()
.then(() => {
if (fs.existsSync(testConfigFile)) {
fs.unlinkSync(testConfigFile);
}
let workerCount, taskConfigsFolder;
if (runInParallel) {
// generate name to store task configuration files
const prefix = os.tmpdir() + "/ts-tests";
let i = 1;
do {
taskConfigsFolder = prefix + i;
i++;
} while (fs.existsSync(taskConfigsFolder));
fs.mkdirSync(taskConfigsFolder);
workerCount = cmdLineOptions.workers;
}
if (tests && tests.toLocaleLowerCase() === "rwc") {
testTimeout = 400000;
}
if (tests || runners || light || testTimeout || taskConfigsFolder || keepFailed) {
writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, testTimeout, keepFailed);
}
const colors = cmdLineOptions.colors;
const reporter = cmdLineOptions.reporter || defaultReporter;
/** @type {string} */
let host = "node";
/** @type {string[]} */
let args = [];
// timeout normally isn"t necessary but Travis-CI has been timing out on compiler baselines occasionally
// default timeout is 2sec which really should be enough, but maybe we just need a small amount longer
if (!runInParallel) {
args.push("-R", "scripts/failed-tests");
args.push("-O", '"reporter=' + reporter + (keepFailed ? ",keepFailed=true" : "") + '"');
if (tests) {
args.push("-g", `"${tests}"`);
}
if (colors) {
args.push("--colors");
}
else {
args.push("--no-colors");
}
if (inspect) {
args.unshift("--inspect-brk");
}
else if (debug) {
args.unshift("--debug-brk");
}
else {
args.push("-t", "" + testTimeout);
}
args.push(runJs);
host = mocha;
}
else {
// run task to load all tests and partition them between workers
host = "node";
args.push(runJs);
}
setNodeEnvToDevelopment();
if (failed) {
return exec(host, ["scripts/run-failed-tests.js"].concat(args));
}
else {
return exec(host, args);
}
})
.then(({ exitCode }) => {
if (exitCode !== 0) return finish(undefined, exitCode);
if (lintFlag) return finished(runSequence("lint")).then(() => finish(), finish);
return finish();
}, finish);
/**
* @param {any=} error
* @param {number=} errorStatus
*/
function finish(error, errorStatus) {
restoreSavedNodeEnv();
return deleteTestConfig()
.then(deleteTemporaryProjectOutput)
.then(() => {
if (error !== undefined || errorStatus !== undefined) {
process.exit(typeof errorStatus === "number" ? errorStatus : 2);
}
});
const keepFailed = cmdLineOptions.keepFailed;
if (!cmdLineOptions.dirty) {
await cleanTestDirs();
}
function deleteTestConfig() {
return del("test.config");
if (fs.existsSync(testConfigFile)) {
fs.unlinkSync(testConfigFile);
}
let workerCount, taskConfigsFolder;
if (runInParallel) {
// generate name to store task configuration files
const prefix = os.tmpdir() + "/ts-tests";
let i = 1;
do {
taskConfigsFolder = prefix + i;
i++;
} while (fs.existsSync(taskConfigsFolder));
fs.mkdirSync(taskConfigsFolder);
workerCount = cmdLineOptions.workers;
}
if (tests && tests.toLocaleLowerCase() === "rwc") {
testTimeout = 400000;
}
if (tests || runners || light || testTimeout || taskConfigsFolder || keepFailed) {
writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, testTimeout, keepFailed);
}
const colors = cmdLineOptions.colors;
const reporter = cmdLineOptions.reporter || defaultReporter;
/** @type {string[]} */
let args = [];
// timeout normally isn"t necessary but Travis-CI has been timing out on compiler baselines occasionally
// default timeout is 2sec which really should be enough, but maybe we just need a small amount longer
if (!runInParallel) {
args.push(failed ? "scripts/run-failed-tests.js" : mochaJs);
args.push("-R", "scripts/failed-tests");
args.push("-O", '"reporter=' + reporter + (keepFailed ? ",keepFailed=true" : "") + '"');
if (tests) {
args.push("-g", `"${tests}"`);
}
if (colors) {
args.push("--colors");
}
else {
args.push("--no-colors");
}
if (inspect) {
args.unshift("--inspect-brk");
}
else if (debug) {
args.unshift("--debug-brk");
}
else {
args.push("-t", "" + testTimeout);
}
args.push(runJs);
}
else {
// run task to load all tests and partition them between workers
args.push(runJs);
}
/** @type {number | undefined} */
let errorStatus;
/** @type {Error | undefined} */
let error;
try {
setNodeEnvToDevelopment();
const { exitCode } = await exec("node", args, { cancelToken });
if (exitCode !== 0) {
errorStatus = exitCode;
error = new Error(`Process exited with status code ${errorStatus}.`);
}
else if (lintFlag) {
await new Promise((resolve, reject) => gulp.start(["lint"], error => error ? reject(error) : resolve()));
}
}
catch (e) {
errorStatus = undefined;
error = e;
}
finally {
restoreSavedNodeEnv();
}
await del("test.config");
await deleteTemporaryProjectOutput();
if (error !== undefined) {
if (watchMode) {
throw error;
}
else {
log.error(error);
process.exit(typeof errorStatus === "number" ? errorStatus : 2);
}
}
}
exports.runConsoleTests = runConsoleTests;
function cleanTestDirs() {
return del([exports.localBaseline, exports.localRwcBaseline,])
return del([exports.localBaseline, exports.localRwcBaseline])
.then(() => mkdirP(exports.localRwcBaseline))
.then(() => mkdirP(exports.localBaseline));
}
+27
View File
@@ -0,0 +1,27 @@
// @ts-check
const fs = require("fs");
const File = require("./vinyl");
const { Readable } = require("stream");
/**
* @param {File} file
*/
function streamFromFile(file) {
return file.isBuffer() ? streamFromBuffer(file.contents) :
file.isStream() ? file.contents :
fs.createReadStream(file.path, { autoClose: true });
}
exports.streamFromFile = streamFromFile;
/**
* @param {Buffer} buffer
*/
function streamFromBuffer(buffer) {
return new Readable({
read() {
this.push(buffer);
this.push(null);
}
});
}
exports.streamFromBuffer = streamFromBuffer;
+60
View File
@@ -0,0 +1,60 @@
// NOTE: This makes it possible to correctly type vinyl Files under @ts-check.
export = File;
declare class File<T extends File.Contents = File.Contents> {
constructor(options?: File.VinylOptions<T>);
cwd: string;
base: string;
path: string;
readonly history: ReadonlyArray<string>;
contents: T;
relative: string;
dirname: string;
basename: string;
stem: string;
extname: string;
symlink: string | null;
stat: import("fs").Stats | null;
sourceMap?: import("./sourcemaps").RawSourceMap | string;
[custom: string]: any;
isBuffer(): this is T extends Buffer ? File<Buffer> : never;
isStream(): this is T extends NodeJS.ReadableStream ? File<NodeJS.ReadableStream> : never;
isNull(): this is T extends null ? File<null> : never;
isDirectory(): this is T extends null ? File.Directory : never;
isSymbolic(): this is T extends null ? File.Symbolic : never;
clone(opts?: { contents?: boolean, deep?: boolean }): this;
}
namespace File {
export interface VinylOptions<T extends Contents = Contents> {
cwd?: string;
base?: string;
path?: string;
history?: ReadonlyArray<string>;
stat?: import("fs").Stats;
contents?: T;
sourceMap?: import("./sourcemaps").RawSourceMap | string;
[custom: string]: any;
}
export type Contents = Buffer | NodeJS.ReadableStream | null;
export type File = import("./vinyl");
export type NullFile = File<null>;
export type BufferFile = File<Buffer>;
export type StreamFile = File<NodeJS.ReadableStream>;
export interface Directory extends NullFile {
isNull(): true;
isDirectory(): true;
isSymbolic(): this is never;
}
export interface Symbolic extends NullFile {
isNull(): true;
isDirectory(): this is never;
isSymbolic(): true;
}
}
+1
View File
@@ -0,0 +1 @@
module.exports = require("vinyl");
+42 -17
View File
@@ -4,9 +4,11 @@ const path = require("path");
const fs = require("fs");
const os = require("os");
const failingHookRegExp = /^(.*) "(before|after) (all|each)" hook$/;
/**
* .failed-tests reporter
*
*
* @typedef {Object} ReporterOptions
* @property {string} [file]
* @property {boolean} [keepFailed]
@@ -15,7 +17,7 @@ const os = require("os");
*/
class FailedTestsReporter extends Mocha.reporters.Base {
/**
* @param {Mocha.Runner} runner
* @param {Mocha.Runner} runner
* @param {{ reporterOptions?: ReporterOptions }} [options]
*/
constructor(runner, options) {
@@ -49,35 +51,58 @@ class FailedTestsReporter extends Mocha.reporters.Base {
/** @type {Mocha.Test[]} */
this.passes = [];
/** @type {Mocha.Test[]} */
/** @type {(Mocha.Test)[]} */
this.failures = [];
runner.on("pass", test => this.passes.push(test));
runner.on("fail", test => this.failures.push(test));
}
/**
* @param {string} file
* @param {ReadonlyArray<Mocha.Test>} passes
* @param {ReadonlyArray<Mocha.Test>} failures
* @param {boolean} keepFailed
* @param {(err?: NodeJS.ErrnoException) => void} done
* @param {string} file
* @param {ReadonlyArray<Mocha.Test>} passes
* @param {ReadonlyArray<Mocha.Test | Mocha.Hook>} failures
* @param {boolean} keepFailed
* @param {(err?: NodeJS.ErrnoException) => void} done
*/
static writeFailures(file, passes, failures, keepFailed, done) {
const failingTests = new Set(fs.existsSync(file) ? readTests() : undefined);
if (failingTests.size > 0) {
const possiblyPassingSuites = /**@type {Set<string>}*/(new Set());
// Remove tests that are now passing and track suites that are now
// possibly passing.
if (failingTests.size > 0 && !keepFailed) {
for (const test of passes) {
const title = test.fullTitle().trim();
if (title) failingTests.delete(title);
failingTests.delete(test.fullTitle().trim());
possiblyPassingSuites.add(test.parent.fullTitle().trim());
}
}
// Add tests that are now failing. If a hook failed, track its
// containing suite as failing. If the suite for a test or hook was
// possibly passing then it is now definitely failing.
for (const test of failures) {
const title = test.fullTitle().trim();
if (title) failingTests.add(title);
const suiteTitle = test.parent.fullTitle().trim();
if (test.type === "test") {
failingTests.add(test.fullTitle().trim());
}
else {
failingTests.add(suiteTitle);
}
possiblyPassingSuites.delete(suiteTitle);
}
// Remove all definitely passing suites.
for (const suite of possiblyPassingSuites) {
failingTests.delete(suite);
}
if (failingTests.size > 0) {
const failed = Array.from(failingTests).join(os.EOL);
const failed = Array
.from(failingTests)
.sort()
.join(os.EOL);
fs.writeFile(file, failed, "utf8", done);
}
else if (!keepFailed && fs.existsSync(file)) {
@@ -96,7 +121,7 @@ class FailedTestsReporter extends Mocha.reporters.Base {
}
/**
* @param {number} failures
* @param {number} failures
* @param {(failures: number) => void} [fn]
*/
done(failures, fn) {
+6 -5
View File
@@ -54,16 +54,17 @@ async function copyScriptOutputs() {
await copyWithCopyright("cancellationToken.js");
await copyWithCopyright("tsc.release.js", "tsc.js");
await copyWithCopyright("tsserver.js");
await copyWithCopyright("typescript.js");
await copyWithCopyright("typescriptServices.js");
await copyFromBuiltLocal("tsserverlibrary.js"); // copyright added by build
await copyFromBuiltLocal("typescript.js"); // copyright added by build
await copyFromBuiltLocal("typescriptServices.js"); // copyright added by build
await copyWithCopyright("typingsInstaller.js");
await copyWithCopyright("watchGuard.js");
}
async function copyDeclarationOutputs() {
await copyWithCopyright("tsserverlibrary.d.ts");
await copyWithCopyright("typescript.d.ts");
await copyWithCopyright("typescriptServices.d.ts");
await copyFromBuiltLocal("tsserverlibrary.d.ts"); // copyright added by build
await copyFromBuiltLocal("typescript.d.ts"); // copyright added by build
await copyFromBuiltLocal("typescriptServices.d.ts"); // copyright added by build
}
async function writeGitAttributes() {
+6 -1
View File
@@ -69,7 +69,12 @@ const proc = spawn(process.execPath, args, {
proc.on('exit', (code, signal) => {
process.on('exit', () => {
if (grepFile) {
fs.unlinkSync(grepFile);
try {
fs.unlinkSync(grepFile);
}
catch (e) {
if (e.code !== "ENOENT") throw e;
}
}
if (signal) {
+44 -5
View File
@@ -1211,7 +1211,7 @@ namespace ts {
bind(node.statement);
popActiveLabel();
if (!activeLabel.referenced && !options.allowUnusedLabels) {
errorOrSuggestionOnFirstToken(unusedLabelIsError(options), node, Diagnostics.Unused_label);
errorOrSuggestionOnNode(unusedLabelIsError(options), node.label, Diagnostics.Unused_label);
}
if (!node.statement || node.statement.kind !== SyntaxKind.DoStatement) {
// do statement sets current flow inside bindDoStatement
@@ -1918,9 +1918,16 @@ namespace ts {
file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length, message, arg0, arg1, arg2));
}
function errorOrSuggestionOnFirstToken(isError: boolean, node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any) {
const span = getSpanOfTokenAtPosition(file, node.pos);
const diag = createFileDiagnostic(file, span.start, span.length, message, arg0, arg1, arg2);
function errorOrSuggestionOnNode(isError: boolean, node: Node, message: DiagnosticMessage): void {
errorOrSuggestionOnRange(isError, node, node, message);
}
function errorOrSuggestionOnRange(isError: boolean, startNode: Node, endNode: Node, message: DiagnosticMessage): void {
addErrorOrSuggestionDiagnostic(isError, { pos: getTokenPosOfNode(startNode, file), end: endNode.end }, message);
}
function addErrorOrSuggestionDiagnostic(isError: boolean, range: TextRange, message: DiagnosticMessage): void {
const diag = createFileDiagnostic(file, range.pos, range.end - range.pos, message);
if (isError) {
file.bindDiagnostics.push(diag);
}
@@ -2792,7 +2799,7 @@ namespace ts {
node.declarationList.declarations.some(d => !!d.initializer)
);
errorOrSuggestionOnFirstToken(isError, node, Diagnostics.Unreachable_code_detected);
eachUnreachableRange(node, (start, end) => errorOrSuggestionOnRange(isError, start, end, Diagnostics.Unreachable_code_detected));
}
}
}
@@ -2800,6 +2807,38 @@ namespace ts {
}
}
function eachUnreachableRange(node: Node, cb: (start: Node, last: Node) => void): void {
if (isStatement(node) && isExecutableStatement(node) && isBlock(node.parent)) {
const { statements } = node.parent;
const slice = sliceAfter(statements, node);
getRangesWhere(slice, isExecutableStatement, (start, afterEnd) => cb(slice[start], slice[afterEnd - 1]));
}
else {
cb(node, node);
}
}
// As opposed to a pure declaration like an `interface`
function isExecutableStatement(s: Statement): boolean {
// Don't remove statements that can validly be used before they appear.
return !isFunctionDeclaration(s) && !isPurelyTypeDeclaration(s) &&
// `var x;` may declare a variable used above
!(isVariableStatement(s) && !(getCombinedNodeFlags(s) & (NodeFlags.Let | NodeFlags.Const)) && s.declarationList.declarations.some(d => !d.initializer));
}
function isPurelyTypeDeclaration(s: Statement): boolean {
switch (s.kind) {
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.TypeAliasDeclaration:
return true;
case SyntaxKind.ModuleDeclaration:
return getModuleInstanceState(s as ModuleDeclaration) !== ModuleInstanceState.Instantiated;
case SyntaxKind.EnumDeclaration:
return hasModifier(s, ModifierFlags.Const);
default:
return false;
}
}
/* @internal */
export function isExportsOrModuleExportsOrAlias(sourceFile: SourceFile, node: Expression): boolean {
return isExportsIdentifier(node) ||
+251 -97
View File
@@ -295,7 +295,7 @@ namespace ts {
getAllPossiblePropertiesOfTypes,
getSuggestionForNonexistentProperty: (node, type) => getSuggestionForNonexistentProperty(node, type),
getSuggestionForNonexistentSymbol: (location, name, meaning) => getSuggestionForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning),
getSuggestionForNonexistentModule: (node, target) => getSuggestionForNonexistentModule(node, target),
getSuggestionForNonexistentExport: (node, target) => getSuggestionForNonexistentExport(node, target),
getBaseConstraintOfType,
getDefaultFromTypeParameter: type => type && type.flags & TypeFlags.TypeParameter ? getDefaultFromTypeParameter(type as TypeParameter) : undefined,
resolveName(name, location, meaning, excludeGlobals) {
@@ -710,7 +710,7 @@ namespace ts {
}
}
function addRelatedInfo(diagnostic: Diagnostic, ...relatedInformation: DiagnosticRelatedInformation[]) {
function addRelatedInfo(diagnostic: Diagnostic, ...relatedInformation: [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]]) {
if (!diagnostic.relatedInformation) {
diagnostic.relatedInformation = [];
}
@@ -1059,6 +1059,7 @@ namespace ts {
// 5. inside a TS export= declaration (since we will move the export statement during emit to avoid TDZ)
// or if usage is in a type context:
// 1. inside a type query (typeof in type position)
// 2. inside a jsdoc comment
if (usage.parent.kind === SyntaxKind.ExportSpecifier || (usage.parent.kind === SyntaxKind.ExportAssignment && (usage.parent as ExportAssignment).isExportEquals)) {
// export specifiers do not use the variable, they only make it available for use
return true;
@@ -1069,7 +1070,7 @@ namespace ts {
}
const container = getEnclosingBlockScopeContainer(declaration);
return isInTypeQuery(usage) || isUsedInFunctionOrInstanceProperty(usage, declaration, container);
return !!(usage.flags & NodeFlags.JSDoc) || isInTypeQuery(usage) || isUsedInFunctionOrInstanceProperty(usage, declaration, container);
function isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration: VariableDeclaration, usage: Node): boolean {
const container = getEnclosingBlockScopeContainer(declaration);
@@ -1434,11 +1435,18 @@ namespace ts {
!checkAndReportErrorForUsingTypeAsNamespace(errorLocation, name, meaning) &&
!checkAndReportErrorForUsingTypeAsValue(errorLocation, name, meaning) &&
!checkAndReportErrorForUsingNamespaceModuleAsValue(errorLocation, name, meaning)) {
let suggestion: string | undefined;
let suggestion: Symbol | undefined;
if (suggestedNameNotFoundMessage && suggestionCount < maximumSuggestionCount) {
suggestion = getSuggestionForNonexistentSymbol(originalLocation, name, meaning);
suggestion = getSuggestedSymbolForNonexistentSymbol(originalLocation, name, meaning);
if (suggestion) {
error(errorLocation, suggestedNameNotFoundMessage, diagnosticName(nameArg!), suggestion);
const suggestionName = symbolToString(suggestion);
const diagnostic = error(errorLocation, suggestedNameNotFoundMessage, diagnosticName(nameArg!), suggestionName);
if (suggestion.valueDeclaration) {
addRelatedInfo(
diagnostic,
createDiagnosticForNode(suggestion.valueDeclaration, Diagnostics._0_is_declared_here, suggestionName)
);
}
}
}
if (!suggestion) {
@@ -1674,7 +1682,7 @@ namespace ts {
if (diagnosticMessage) {
addRelatedInfo(diagnosticMessage,
createDiagnosticForNode(declaration, Diagnostics._0_was_declared_here, declarationName)
createDiagnosticForNode(declaration, Diagnostics._0_is_declared_here, declarationName)
);
}
}
@@ -1866,9 +1874,15 @@ namespace ts {
if (!symbol) {
const moduleName = getFullyQualifiedName(moduleSymbol);
const declarationName = declarationNameToString(name);
const suggestion = getSuggestionForNonexistentModule(name, targetSymbol);
const suggestion = getSuggestedSymbolForNonexistentModule(name, targetSymbol);
if (suggestion !== undefined) {
error(name, Diagnostics.Module_0_has_no_exported_member_1_Did_you_mean_2, moduleName, declarationName, suggestion);
const suggestionName = symbolToString(suggestion);
const diagnostic = error(name, Diagnostics.Module_0_has_no_exported_member_1_Did_you_mean_2, moduleName, declarationName, suggestionName);
if (suggestion.valueDeclaration) {
addRelatedInfo(diagnostic,
createDiagnosticForNode(suggestion.valueDeclaration, Diagnostics._0_is_declared_here, suggestionName)
);
}
}
else {
error(name, Diagnostics.Module_0_has_no_exported_member_1, moduleName, declarationName);
@@ -2993,7 +3007,8 @@ namespace ts {
}
function typeToString(type: Type, enclosingDeclaration?: Node, flags: TypeFormatFlags = TypeFormatFlags.AllowUniqueESSymbolType | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, writer: EmitTextWriter = createTextWriter("")): string {
const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors, writer);
const noTruncation = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation;
const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | (noTruncation ? NodeBuilderFlags.NoTruncation : 0), writer);
if (typeNode === undefined) return Debug.fail("should always get typenode");
const options = { removeComments: true };
const printer = createPrinter(options);
@@ -3001,7 +3016,7 @@ namespace ts {
printer.writeNode(EmitHint.Unspecified, typeNode, /*sourceFile*/ sourceFile, writer);
const result = writer.getText();
const maxLength = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation ? undefined : 100;
const maxLength = noTruncation ? undefined : defaultMaximumTruncationLength * 2;
if (maxLength && result && result.length >= maxLength) {
return result.substr(0, maxLength - "...".length) + "...";
}
@@ -3040,12 +3055,18 @@ namespace ts {
tracker: tracker && tracker.trackSymbol ? tracker : { trackSymbol: noop },
encounteredError: false,
visitedSymbols: undefined,
inferTypeParameters: undefined
inferTypeParameters: undefined,
approximateLength: 0
};
const resultingNode = cb(context);
return context.encounteredError ? undefined : resultingNode;
}
function checkTruncationLength(context: NodeBuilderContext): boolean {
if (context.truncating) return context.truncating;
return context.truncating = !(context.flags & NodeBuilderFlags.NoTruncation) && context.approximateLength > defaultMaximumTruncationLength;
}
function typeToTypeNodeHelper(type: Type, context: NodeBuilderContext): TypeNode {
if (cancellationToken && cancellationToken.throwIfCancellationRequested) {
cancellationToken.throwIfCancellationRequested();
@@ -3059,66 +3080,83 @@ namespace ts {
}
if (type.flags & TypeFlags.Any) {
context.approximateLength += 3;
return createKeywordTypeNode(SyntaxKind.AnyKeyword);
}
if (type.flags & TypeFlags.Unknown) {
return createKeywordTypeNode(SyntaxKind.UnknownKeyword);
}
if (type.flags & TypeFlags.String) {
context.approximateLength += 6;
return createKeywordTypeNode(SyntaxKind.StringKeyword);
}
if (type.flags & TypeFlags.Number) {
context.approximateLength += 6;
return createKeywordTypeNode(SyntaxKind.NumberKeyword);
}
if (type.flags & TypeFlags.Boolean) {
context.approximateLength += 7;
return createKeywordTypeNode(SyntaxKind.BooleanKeyword);
}
if (type.flags & TypeFlags.EnumLiteral && !(type.flags & TypeFlags.Union)) {
const parentSymbol = getParentOfSymbol(type.symbol)!;
const parentName = symbolToName(parentSymbol, context, SymbolFlags.Type, /*expectsIdentifier*/ false);
const enumLiteralName = getDeclaredTypeOfSymbol(parentSymbol) === type ? parentName : createQualifiedName(parentName, symbolName(type.symbol));
context.approximateLength += symbolName(type.symbol).length;
return createTypeReferenceNode(enumLiteralName, /*typeArguments*/ undefined);
}
if (type.flags & TypeFlags.EnumLike) {
const name = symbolToName(type.symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ false);
context.approximateLength += symbolName(type.symbol).length;
return createTypeReferenceNode(name, /*typeArguments*/ undefined);
}
if (type.flags & (TypeFlags.StringLiteral)) {
if (type.flags & TypeFlags.StringLiteral) {
context.approximateLength += ((<StringLiteralType>type).value.length + 2);
return createLiteralTypeNode(setEmitFlags(createLiteral((<StringLiteralType>type).value), EmitFlags.NoAsciiEscaping));
}
if (type.flags & (TypeFlags.NumberLiteral)) {
if (type.flags & TypeFlags.NumberLiteral) {
context.approximateLength += (("" + (<NumberLiteralType>type).value).length);
return createLiteralTypeNode((createLiteral((<NumberLiteralType>type).value)));
}
if (type.flags & TypeFlags.BooleanLiteral) {
context.approximateLength += (<IntrinsicType>type).intrinsicName.length;
return (<IntrinsicType>type).intrinsicName === "true" ? createTrue() : createFalse();
}
if (type.flags & TypeFlags.UniqueESSymbol) {
if (!(context.flags & NodeBuilderFlags.AllowUniqueESSymbolType)) {
if (isValueSymbolAccessible(type.symbol, context.enclosingDeclaration!)) {
context.approximateLength += 6;
return symbolToTypeNode(type.symbol, context, SymbolFlags.Value);
}
if (context.tracker.reportInaccessibleUniqueSymbolError) {
context.tracker.reportInaccessibleUniqueSymbolError();
}
}
context.approximateLength += 13;
return createTypeOperatorNode(SyntaxKind.UniqueKeyword, createKeywordTypeNode(SyntaxKind.SymbolKeyword));
}
if (type.flags & TypeFlags.Void) {
context.approximateLength += 4;
return createKeywordTypeNode(SyntaxKind.VoidKeyword);
}
if (type.flags & TypeFlags.Undefined) {
context.approximateLength += 9;
return createKeywordTypeNode(SyntaxKind.UndefinedKeyword);
}
if (type.flags & TypeFlags.Null) {
context.approximateLength += 4;
return createKeywordTypeNode(SyntaxKind.NullKeyword);
}
if (type.flags & TypeFlags.Never) {
context.approximateLength += 5;
return createKeywordTypeNode(SyntaxKind.NeverKeyword);
}
if (type.flags & TypeFlags.ESSymbol) {
context.approximateLength += 6;
return createKeywordTypeNode(SyntaxKind.SymbolKeyword);
}
if (type.flags & TypeFlags.NonPrimitive) {
context.approximateLength += 6;
return createKeywordTypeNode(SyntaxKind.ObjectKeyword);
}
if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) {
@@ -3130,6 +3168,7 @@ namespace ts {
context.tracker.reportInaccessibleThisError();
}
}
context.approximateLength += 4;
return createThis();
}
@@ -3141,6 +3180,7 @@ namespace ts {
}
if (type.flags & TypeFlags.TypeParameter || objectFlags & ObjectFlags.ClassOrInterface) {
if (type.flags & TypeFlags.TypeParameter && contains(context.inferTypeParameters, type)) {
context.approximateLength += (symbolName(type.symbol).length + 6);
return createInferTypeNode(typeParameterToDeclarationWithConstraint(type as TypeParameter, context, /*constraintNode*/ undefined));
}
if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams &&
@@ -3149,7 +3189,9 @@ namespace ts {
isTypeParameterDeclaration(type.symbol.declarations[0]) &&
typeParameterShadowsNameInScope(type, context) &&
!isTypeSymbolAccessible(type.symbol, context.enclosingDeclaration)) {
return createTypeReferenceNode(getGeneratedNameForNode((type.symbol.declarations[0] as TypeParameterDeclaration).name, GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.ReservedInNestedScopes), /*typeArguments*/ undefined);
const name = (type.symbol.declarations[0] as TypeParameterDeclaration).name;
context.approximateLength += idText(name).length;
return createTypeReferenceNode(getGeneratedNameForNode(name, GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.ReservedInNestedScopes), /*typeArguments*/ undefined);
}
// Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter.
return type.symbol
@@ -3163,7 +3205,7 @@ namespace ts {
}
if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) {
const types = type.flags & TypeFlags.Union ? formatUnionTypes((<UnionType>type).types) : (<IntersectionType>type).types;
const typeNodes = mapToTypeNodes(types, context);
const typeNodes = mapToTypeNodes(types, context, /*isBareList*/ true);
if (typeNodes && typeNodes.length > 0) {
const unionOrIntersectionTypeNode = createUnionOrIntersectionTypeNode(type.flags & TypeFlags.Union ? SyntaxKind.UnionType : SyntaxKind.IntersectionType, typeNodes);
return unionOrIntersectionTypeNode;
@@ -3182,12 +3224,14 @@ namespace ts {
}
if (type.flags & TypeFlags.Index) {
const indexedType = (<IndexType>type).type;
context.approximateLength += 6;
const indexTypeNode = typeToTypeNodeHelper(indexedType, context);
return createTypeOperatorNode(indexTypeNode);
}
if (type.flags & TypeFlags.IndexedAccess) {
const objectTypeNode = typeToTypeNodeHelper((<IndexedAccessType>type).objectType, context);
const indexTypeNode = typeToTypeNodeHelper((<IndexedAccessType>type).indexType, context);
context.approximateLength += 2;
return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode);
}
if (type.flags & TypeFlags.Conditional) {
@@ -3198,6 +3242,7 @@ namespace ts {
context.inferTypeParameters = saveInferTypeParameters;
const trueTypeNode = typeToTypeNodeHelper(getTrueTypeFromConditionalType(<ConditionalType>type), context);
const falseTypeNode = typeToTypeNodeHelper(getFalseTypeFromConditionalType(<ConditionalType>type), context);
context.approximateLength += 15;
return createConditionalTypeNode(checkTypeNode, extendsTypeNode, trueTypeNode, falseTypeNode);
}
if (type.flags & TypeFlags.Substitution) {
@@ -3222,6 +3267,7 @@ namespace ts {
const typeParameterNode = typeParameterToDeclarationWithConstraint(getTypeParameterFromMappedType(type), context, appropriateConstraintTypeNode);
const templateTypeNode = typeToTypeNodeHelper(getTemplateTypeFromMappedType(type), context);
const mappedTypeNode = createMappedTypeNode(readonlyToken, typeParameterNode, questionToken, templateTypeNode);
context.approximateLength += 10;
return setEmitFlags(mappedTypeNode, EmitFlags.SingleLine);
}
@@ -3250,6 +3296,7 @@ namespace ts {
return symbolToTypeNode(typeAlias, context, SymbolFlags.Type);
}
else {
context.approximateLength += 3;
return createKeywordTypeNode(SyntaxKind.AnyKeyword);
}
}
@@ -3294,6 +3341,7 @@ namespace ts {
const resolved = resolveStructuredTypeMembers(type);
if (!resolved.properties.length && !resolved.stringIndexInfo && !resolved.numberIndexInfo) {
if (!resolved.callSignatures.length && !resolved.constructSignatures.length) {
context.approximateLength += 2;
return setEmitFlags(createTypeLiteralNode(/*members*/ undefined), EmitFlags.SingleLine);
}
@@ -3316,6 +3364,7 @@ namespace ts {
const members = createTypeNodesFromResolvedType(resolved);
context.flags = savedFlags;
const typeLiteralNode = createTypeLiteralNode(members);
context.approximateLength += 2;
return setEmitFlags(typeLiteralNode, (context.flags & NodeBuilderFlags.MultilineObjectLiterals) ? 0 : EmitFlags.SingleLine);
}
@@ -3437,6 +3486,9 @@ namespace ts {
}
function createTypeNodesFromResolvedType(resolvedType: ResolvedType): TypeElement[] | undefined {
if (checkTruncationLength(context)) {
return [createPropertySignature(/*modifiers*/ undefined, "...", /*questionToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined)];
}
const typeElements: TypeElement[] = [];
for (const signature of resolvedType.callSignatures) {
typeElements.push(<CallSignatureDeclaration>signatureToSignatureDeclarationHelper(signature, SyntaxKind.CallSignature, context));
@@ -3459,7 +3511,9 @@ namespace ts {
return typeElements;
}
let i = 0;
for (const propertySymbol of properties) {
i++;
if (context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral) {
if (propertySymbol.flags & SymbolFlags.Prototype) {
continue;
@@ -3468,65 +3522,102 @@ namespace ts {
context.tracker.reportPrivateInBaseOfClassExpression(unescapeLeadingUnderscores(propertySymbol.escapedName));
}
}
const propertyType = getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped && context.flags & NodeBuilderFlags.InReverseMappedType ?
anyType : getTypeOfSymbol(propertySymbol);
const saveEnclosingDeclaration = context.enclosingDeclaration;
context.enclosingDeclaration = undefined;
if (getCheckFlags(propertySymbol) & CheckFlags.Late) {
const decl = first(propertySymbol.declarations);
if (context.tracker.trackSymbol && hasLateBindableName(decl)) {
// get symbol of the first identifier of the entityName
const firstIdentifier = getFirstIdentifier(decl.name.expression);
const name = resolveName(firstIdentifier, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true);
if (name) {
context.tracker.trackSymbol(name, saveEnclosingDeclaration, SymbolFlags.Value);
}
}
if (checkTruncationLength(context) && (i + 2 < properties.length - 1)) {
typeElements.push(createPropertySignature(/*modifiers*/ undefined, `... ${properties.length - i} more ...`, /*questionToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined));
addPropertyToElementList(properties[properties.length - 1], context, typeElements);
break;
}
const propertyName = symbolToName(propertySymbol, context, SymbolFlags.Value, /*expectsIdentifier*/ true);
context.enclosingDeclaration = saveEnclosingDeclaration;
const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? createToken(SyntaxKind.QuestionToken) : undefined;
if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length) {
const signatures = getSignaturesOfType(propertyType, SignatureKind.Call);
for (const signature of signatures) {
const methodDeclaration = <MethodSignature>signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature, context);
methodDeclaration.name = propertyName;
methodDeclaration.questionToken = optionalToken;
if (propertySymbol.valueDeclaration) {
// Copy comments to node for declaration emit
setCommentRange(methodDeclaration, propertySymbol.valueDeclaration);
}
typeElements.push(methodDeclaration);
}
}
else {
const savedFlags = context.flags;
context.flags |= !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped) ? NodeBuilderFlags.InReverseMappedType : 0;
const propertyTypeNode = propertyType ? typeToTypeNodeHelper(propertyType, context) : createKeywordTypeNode(SyntaxKind.AnyKeyword);
context.flags = savedFlags;
addPropertyToElementList(propertySymbol, context, typeElements);
const modifiers = isReadonlySymbol(propertySymbol) ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined;
const propertySignature = createPropertySignature(
modifiers,
propertyName,
optionalToken,
propertyTypeNode,
/*initializer*/ undefined);
if (propertySymbol.valueDeclaration) {
// Copy comments to node for declaration emit
setCommentRange(propertySignature, propertySymbol.valueDeclaration);
}
typeElements.push(propertySignature);
}
}
return typeElements.length ? typeElements : undefined;
}
}
function mapToTypeNodes(types: ReadonlyArray<Type> | undefined, context: NodeBuilderContext): TypeNode[] | undefined {
function addPropertyToElementList(propertySymbol: Symbol, context: NodeBuilderContext, typeElements: TypeElement[]) {
const propertyType = getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped && context.flags & NodeBuilderFlags.InReverseMappedType ?
anyType : getTypeOfSymbol(propertySymbol);
const saveEnclosingDeclaration = context.enclosingDeclaration;
context.enclosingDeclaration = undefined;
if (getCheckFlags(propertySymbol) & CheckFlags.Late) {
const decl = first(propertySymbol.declarations);
if (context.tracker.trackSymbol && hasLateBindableName(decl)) {
// get symbol of the first identifier of the entityName
const firstIdentifier = getFirstIdentifier(decl.name.expression);
const name = resolveName(firstIdentifier, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true);
if (name) {
context.tracker.trackSymbol(name, saveEnclosingDeclaration, SymbolFlags.Value);
}
}
}
const propertyName = symbolToName(propertySymbol, context, SymbolFlags.Value, /*expectsIdentifier*/ true);
context.approximateLength += (symbolName(propertySymbol).length + 1);
context.enclosingDeclaration = saveEnclosingDeclaration;
const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? createToken(SyntaxKind.QuestionToken) : undefined;
if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length) {
const signatures = getSignaturesOfType(propertyType, SignatureKind.Call);
for (const signature of signatures) {
const methodDeclaration = <MethodSignature>signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature, context);
methodDeclaration.name = propertyName;
methodDeclaration.questionToken = optionalToken;
if (propertySymbol.valueDeclaration) {
// Copy comments to node for declaration emit
setCommentRange(methodDeclaration, propertySymbol.valueDeclaration);
}
typeElements.push(methodDeclaration);
}
}
else {
const savedFlags = context.flags;
context.flags |= !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped) ? NodeBuilderFlags.InReverseMappedType : 0;
const propertyTypeNode = propertyType ? typeToTypeNodeHelper(propertyType, context) : createKeywordTypeNode(SyntaxKind.AnyKeyword);
context.flags = savedFlags;
const modifiers = isReadonlySymbol(propertySymbol) ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined;
if (modifiers) {
context.approximateLength += 9;
}
const propertySignature = createPropertySignature(
modifiers,
propertyName,
optionalToken,
propertyTypeNode,
/*initializer*/ undefined);
if (propertySymbol.valueDeclaration) {
// Copy comments to node for declaration emit
setCommentRange(propertySignature, propertySymbol.valueDeclaration);
}
typeElements.push(propertySignature);
}
}
function mapToTypeNodes(types: ReadonlyArray<Type> | undefined, context: NodeBuilderContext, isBareList?: boolean): TypeNode[] | undefined {
if (some(types)) {
if (checkTruncationLength(context)) {
if (!isBareList) {
return [createTypeReferenceNode("...", /*typeArguments*/ undefined)];
}
else if (types.length > 2) {
return [
typeToTypeNodeHelper(types[0], context),
createTypeReferenceNode(`... ${types.length - 2} more ...`, /*typeArguments*/ undefined),
typeToTypeNodeHelper(types[types.length - 1], context)
];
}
}
const result = [];
let i = 0;
for (const type of types) {
i++;
if (checkTruncationLength(context) && (i + 2 < types.length - 1)) {
result.push(createTypeReferenceNode(`... ${types.length - i} more ...`, /*typeArguments*/ undefined));
const typeNode = typeToTypeNodeHelper(types[types.length - 1], context);
if (typeNode) {
result.push(typeNode);
}
break;
}
context.approximateLength += 2; // Account for whitespace + separator
const typeNode = typeToTypeNodeHelper(type, context);
if (typeNode) {
result.push(typeNode);
@@ -3553,6 +3644,7 @@ namespace ts {
if (!indexInfo.type && !(context.flags & NodeBuilderFlags.AllowEmptyIndexInfoType)) {
context.encounteredError = true;
}
context.approximateLength += (name.length + 4);
return createIndexSignature(
/*decorators*/ undefined,
indexInfo.isReadonly ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined,
@@ -3597,6 +3689,7 @@ namespace ts {
else if (!returnTypeNode) {
returnTypeNode = createKeywordTypeNode(SyntaxKind.AnyKeyword);
}
context.approximateLength += 3; // Usually a signature contributes a few more characters than this, but 3 is the minimum
return createSignatureDeclaration(kind, typeParameters, parameters, returnTypeNode, typeArguments);
}
@@ -3658,6 +3751,7 @@ namespace ts {
questionToken,
parameterTypeNode,
/*initializer*/ undefined);
context.approximateLength += symbolName(parameterSymbol).length + 3;
return parameterNode;
function cloneBindingName(node: BindingName): BindingName {
@@ -3812,7 +3906,9 @@ namespace ts {
// module is root, must use `ImportTypeNode`
const nonRootParts = chain.length > 1 ? createAccessFromSymbolChain(chain, chain.length - 1, 1) : undefined;
const typeParameterNodes = overrideTypeArguments || lookupTypeParameterNodes(chain, 0, context);
const lit = createLiteralTypeNode(createLiteral(getSpecifierForModuleSymbol(chain[0], context)));
const specifier = getSpecifierForModuleSymbol(chain[0], context);
const lit = createLiteralTypeNode(createLiteral(specifier));
context.approximateLength += specifier.length + 10; // specifier + import("")
if (!nonRootParts || isEntityName(nonRootParts)) {
if (nonRootParts) {
const lastId = isIdentifier(nonRootParts) ? nonRootParts : nonRootParts.right;
@@ -3849,6 +3945,7 @@ namespace ts {
context.flags |= NodeBuilderFlags.InInitialEntityName;
}
const symbolName = getNameOfSymbolAsWritten(symbol, context);
context.approximateLength += symbolName.length + 1;
if (index === 0) {
context.flags ^= NodeBuilderFlags.InInitialEntityName;
}
@@ -4033,6 +4130,8 @@ namespace ts {
encounteredError: boolean;
visitedSymbols: Map<true> | undefined;
inferTypeParameters: TypeParameter[] | undefined;
approximateLength: number;
truncating?: boolean;
}
function isDefaultBindingContext(location: Node) {
@@ -5904,6 +6003,12 @@ namespace ts {
&& isTypeUsableAsLateBoundName(checkComputedPropertyName(node));
}
function isLateBoundName(name: __String): boolean {
return (name as string).charCodeAt(0) === CharacterCodes._ &&
(name as string).charCodeAt(1) === CharacterCodes._ &&
(name as string).charCodeAt(2) === CharacterCodes.at;
}
/**
* Indicates whether a declaration has a late-bindable dynamic name.
*/
@@ -7010,6 +7115,7 @@ namespace ts {
function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: __String): Symbol | undefined {
let props: Symbol[] | undefined;
let indexTypes: Type[] | undefined;
const isUnion = containingType.flags & TypeFlags.Union;
const excludeModifiers = isUnion ? ModifierFlags.NonPublicAccessibilityModifier : 0;
// Flags we want to propagate to the result if they exist in all source symbols
@@ -7034,14 +7140,21 @@ namespace ts {
}
}
else if (isUnion) {
checkFlags |= CheckFlags.Partial;
const index = !isLateBoundName(name) && ((isNumericLiteralName(name) && getIndexInfoOfType(type, IndexKind.Number)) || getIndexInfoOfType(type, IndexKind.String));
if (index) {
checkFlags |= index.isReadonly ? CheckFlags.Readonly : 0;
indexTypes = append(indexTypes, index.type);
}
else {
checkFlags |= CheckFlags.Partial;
}
}
}
}
if (!props) {
return undefined;
}
if (props.length === 1 && !(checkFlags & CheckFlags.Partial)) {
if (props.length === 1 && !(checkFlags & CheckFlags.Partial) && !indexTypes) {
return props[0];
}
let declarations: Declaration[] | undefined;
@@ -7072,6 +7185,7 @@ namespace ts {
}
propTypes.push(type);
}
addRange(propTypes, indexTypes);
const result = createSymbol(SymbolFlags.Property | commonFlags, name, syntheticFlag | checkFlags);
result.containingType = containingType;
if (!hasNonUniformValueDeclaration && commonValueDeclaration) {
@@ -8137,7 +8251,7 @@ namespace ts {
// The expression is processed as an identifier expression (section 4.3)
// or property access expression(section 4.10),
// the widened type(section 3.9) of which becomes the result.
links.resolvedType = getWidenedType(checkExpression(node.exprName));
links.resolvedType = getRegularTypeOfLiteralType(getWidenedType(checkExpression(node.exprName)));
}
return links.resolvedType;
}
@@ -10254,9 +10368,9 @@ namespace ts {
}
}
if (!issuedElaboration && (length(targetProp && targetProp.declarations) || length(target.symbol && target.symbol.declarations))) {
if (!issuedElaboration && (targetProp && length(targetProp.declarations) || target.symbol && length(target.symbol.declarations))) {
addRelatedInfo(reportedDiag, createDiagnosticForNode(
targetProp ? targetProp.declarations[0] : target.symbol.declarations[0],
targetProp && length(targetProp.declarations) ? targetProp.declarations[0] : target.symbol.declarations[0],
Diagnostics.The_expected_type_comes_from_property_0_which_is_declared_here_on_type_1,
propertyName && !(nameType.flags & TypeFlags.UniqueESSymbol) ? unescapeLeadingUnderscores(propertyName) : typeToString(nameType),
typeToString(target)
@@ -17661,7 +17775,7 @@ namespace ts {
if (diagnosticMessage) {
addRelatedInfo(diagnosticMessage,
createDiagnosticForNode(valueDeclaration, Diagnostics._0_was_declared_here, declarationName)
createDiagnosticForNode(valueDeclaration, Diagnostics._0_is_declared_here, declarationName)
);
}
}
@@ -17711,6 +17825,7 @@ namespace ts {
function reportNonexistentProperty(propNode: Identifier, containingType: Type) {
let errorInfo: DiagnosticMessageChain | undefined;
let relatedInfo: Diagnostic | undefined;
if (containingType.flags & TypeFlags.Union && !(containingType.flags & TypeFlags.Primitive)) {
for (const subtype of (containingType as UnionType).types) {
if (!getPropertyOfType(subtype, propNode.escapedText)) {
@@ -17724,30 +17839,34 @@ namespace ts {
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_forget_to_use_await, declarationNameToString(propNode), typeToString(containingType));
}
else {
const suggestion = getSuggestionForNonexistentProperty(propNode, containingType);
const suggestion = getSuggestedSymbolForNonexistentProperty(propNode, containingType);
if (suggestion !== undefined) {
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, declarationNameToString(propNode), typeToString(containingType), suggestion);
const suggestedName = symbolName(suggestion);
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, declarationNameToString(propNode), typeToString(containingType), suggestedName);
relatedInfo = suggestion.valueDeclaration && createDiagnosticForNode(suggestion.valueDeclaration, Diagnostics._0_is_declared_here, suggestedName);
}
else {
const suggestion = getSuggestionForNonexistentProperty(propNode, containingType);
if (suggestion !== undefined) {
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, declarationNameToString(propNode), typeToString(containingType), suggestion);
}
else {
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(propNode), typeToString(containingType));
}
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(propNode), typeToString(containingType));
}
}
diagnostics.add(createDiagnosticForNodeFromMessageChain(propNode, errorInfo));
const resultDiagnostic = createDiagnosticForNodeFromMessageChain(propNode, errorInfo);
if (relatedInfo) {
addRelatedInfo(resultDiagnostic, relatedInfo);
}
diagnostics.add(resultDiagnostic);
}
function getSuggestedSymbolForNonexistentProperty(name: Identifier | string, containingType: Type): Symbol | undefined {
return getSpellingSuggestionForName(isString(name) ? name : idText(name), getPropertiesOfType(containingType), SymbolFlags.Value);
}
function getSuggestionForNonexistentProperty(name: Identifier | string, containingType: Type): string | undefined {
const suggestion = getSpellingSuggestionForName(isString(name) ? name : idText(name), getPropertiesOfType(containingType), SymbolFlags.Value);
const suggestion = getSuggestedSymbolForNonexistentProperty(name, containingType);
return suggestion && symbolName(suggestion);
}
function getSuggestionForNonexistentSymbol(location: Node | undefined, outerName: __String, meaning: SymbolFlags): string | undefined {
function getSuggestedSymbolForNonexistentSymbol(location: Node | undefined, outerName: __String, meaning: SymbolFlags): Symbol | undefined {
Debug.assert(outerName !== undefined, "outername should always be defined");
const result = resolveNameHelper(location, outerName, meaning, /*nameNotFoundMessage*/ undefined, outerName, /*isUse*/ false, /*excludeGlobals*/ false, (symbols, name, meaning) => {
Debug.assertEqual(outerName, name, "name should equal outerName");
@@ -17757,11 +17876,20 @@ namespace ts {
// However, resolveNameHelper will continue and call this callback again, so we'll eventually get a correct suggestion.
return symbol || getSpellingSuggestionForName(unescapeLeadingUnderscores(name), arrayFrom(symbols.values()), meaning);
});
return result && symbolName(result);
return result;
}
function getSuggestionForNonexistentModule(name: Identifier, targetModule: Symbol): string | undefined {
const suggestion = targetModule.exports && getSpellingSuggestionForName(idText(name), getExportsOfModuleAsArray(targetModule), SymbolFlags.ModuleMember);
function getSuggestionForNonexistentSymbol(location: Node | undefined, outerName: __String, meaning: SymbolFlags): string | undefined {
const symbolResult = getSuggestedSymbolForNonexistentSymbol(location, outerName, meaning);
return symbolResult && symbolName(symbolResult);
}
function getSuggestedSymbolForNonexistentModule(name: Identifier, targetModule: Symbol): Symbol | undefined {
return targetModule.exports && getSpellingSuggestionForName(idText(name), getExportsOfModuleAsArray(targetModule), SymbolFlags.ModuleMember);
}
function getSuggestionForNonexistentExport(name: Identifier, targetModule: Symbol): string | undefined {
const suggestion = getSuggestedSymbolForNonexistentModule(name, targetModule);
return suggestion && symbolName(suggestion);
}
@@ -19218,6 +19346,38 @@ namespace ts {
return resolveErrorCall(node);
}
function typeHasProtectedAccessibleBase(target: Symbol, type: InterfaceType): boolean {
const baseTypes = getBaseTypes(type);
if (!length(baseTypes)) {
return false;
}
const firstBase = baseTypes[0];
if (firstBase.flags & TypeFlags.Intersection) {
const types = (firstBase as IntersectionType).types;
const mixinCount = countWhere(types, isMixinConstructorType);
let i = 0;
for (const intersectionMember of (firstBase as IntersectionType).types) {
i++;
// We want to ignore mixin ctors
if (mixinCount === 0 || mixinCount === types.length && i === 0 || !isMixinConstructorType(intersectionMember)) {
if (getObjectFlags(intersectionMember) & (ObjectFlags.Class | ObjectFlags.Interface)) {
if (intersectionMember.symbol === target) {
return true;
}
if (typeHasProtectedAccessibleBase(target, intersectionMember as InterfaceType)) {
return true;
}
}
}
}
return false;
}
if (firstBase.symbol === target) {
return true;
}
return typeHasProtectedAccessibleBase(target, firstBase as InterfaceType);
}
function isConstructorAccessible(node: NewExpression, signature: Signature) {
if (!signature || !signature.declaration) {
return true;
@@ -19237,16 +19397,10 @@ namespace ts {
// A private or protected constructor can only be instantiated within its own class (or a subclass, for protected)
if (!isNodeWithinClass(node, declaringClassDeclaration)) {
const containingClass = getContainingClass(node);
if (containingClass) {
if (containingClass && modifiers & ModifierFlags.Protected) {
const containingType = getTypeOfNode(containingClass);
let baseTypes = getBaseTypes(containingType as InterfaceType);
while (baseTypes.length) {
const baseType = baseTypes[0];
if (modifiers & ModifierFlags.Protected &&
baseType.symbol === declaration.parent.symbol) {
return true;
}
baseTypes = getBaseTypes(baseType as InterfaceType);
if (typeHasProtectedAccessibleBase(declaration.parent.symbol, containingType as InterfaceType)) {
return true;
}
}
if (modifiers & ModifierFlags.Private) {
@@ -20975,7 +21129,7 @@ namespace ts {
getUnionType([removeDefinitelyFalsyTypes(leftType), rightType], UnionReduction.Subtype) :
leftType;
case SyntaxKind.EqualsToken:
const special = getSpecialPropertyAssignmentKind(left.parent as BinaryExpression);
const special = isBinaryExpression(left.parent) ? getSpecialPropertyAssignmentKind(left.parent) : SpecialPropertyAssignmentKind.None;
checkSpecialAssignment(special, right);
if (isJSSpecialPropertyAssignment(special)) {
return leftType;
+7 -3
View File
@@ -2401,8 +2401,8 @@
"category": "Error",
"code": 2727
},
"'{0}' was declared here.": {
"category": "Error",
"'{0}' is declared here.": {
"category": "Message",
"code": 2728
},
"Property '{0}' is used before its initialization.": {
@@ -2864,6 +2864,10 @@
"category": "Error",
"code": 5070
},
"Option '--resolveJsonModule' can only be specified when module code generation is 'commonjs'.": {
"category": "Error",
"code": 5071
},
"Generates a sourcemap for each corresponding '.d.ts' file.": {
"category": "Message",
@@ -3886,7 +3890,7 @@
"code": 7037
},
"Type originates at this import. A namespace-style import cannot be called or constructed, and will cause a failure at runtime. Consider using a default import or import require here instead.": {
"category": "Error",
"category": "Message",
"code": 7038
},
"Mapped object type implicitly has an 'any' template type.": {
+3 -3
View File
@@ -43,7 +43,7 @@ namespace ts {
if (sourceFile.kind === SyntaxKind.Bundle) {
const jsFilePath = options.outFile || options.out!;
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
const declarationFilePath = (forceDtsPaths || options.declaration) ? removeFileExtension(jsFilePath) + Extension.Dts : undefined;
const declarationFilePath = (forceDtsPaths || getEmitDeclarations(options)) ? removeFileExtension(jsFilePath) + Extension.Dts : undefined;
const declarationMapPath = getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined;
const bundleInfoPath = options.references && jsFilePath ? (removeFileExtension(jsFilePath) + infoExtension) : undefined;
return { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, bundleInfoPath };
@@ -53,7 +53,7 @@ namespace ts {
const sourceMapFilePath = isJsonSourceFile(sourceFile) ? undefined : getSourceMapFilePath(jsFilePath, options);
// For legacy reasons (ie, we have baselines capturing the behavior), js files don't report a .d.ts output path - this would only matter if `declaration` and `allowJs` were both on, which is currently an error
const isJs = isSourceFileJavaScript(sourceFile);
const declarationFilePath = ((forceDtsPaths || options.declaration) && !isJs) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined;
const declarationFilePath = ((forceDtsPaths || getEmitDeclarations(options)) && !isJs) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined;
const declarationMapPath = getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined;
return { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, bundleInfoPath: undefined };
}
@@ -192,7 +192,7 @@ namespace ts {
// Setup and perform the transformation to retrieve declarations from the input files
const nonJsFiles = filter(sourceFiles, isSourceFileNotJavaScript);
const inputListOrBundle = (compilerOptions.outFile || compilerOptions.out) ? [createBundle(nonJsFiles, !isSourceFile(sourceFileOrBundle) ? sourceFileOrBundle.prepends : undefined)] : nonJsFiles;
if (emitOnlyDtsFiles && !compilerOptions.declaration) {
if (emitOnlyDtsFiles && !getEmitDeclarations(compilerOptions)) {
// Checker wont collect the linked aliases since thats only done when declaration is enabled.
// Do that here when emitting only dts files
nonJsFiles.forEach(collectLinkedAliases);
+9 -5
View File
@@ -4183,11 +4183,15 @@ namespace ts {
*/
export function parenthesizeDefaultExpression(e: Expression) {
const check = skipPartiallyEmittedExpressions(e);
return check.kind === SyntaxKind.ClassExpression ||
check.kind === SyntaxKind.FunctionExpression ||
isCommaSequence(check)
? createParen(e)
: e;
let needsParens = isCommaSequence(check);
if (!needsParens) {
switch (getLeftmostExpression(check, /*stopAtCallExpression*/ false).kind) {
case SyntaxKind.ClassExpression:
case SyntaxKind.FunctionExpression:
needsParens = true;
}
}
return needsParens ? createParen(e) : e;
}
/**
+6 -2
View File
@@ -2329,7 +2329,7 @@ namespace ts {
if (!sourceFile.isDeclarationFile) {
const absoluteSourceFilePath = host.getCanonicalFileName(getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory));
if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, sourceFile.fileName, options.rootDir));
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, sourceFile.fileName, rootDirectory));
allFilesBelongToPath = false;
}
}
@@ -2500,7 +2500,7 @@ namespace ts {
}
}
if (options.declarationMap && !options.declaration) {
if (options.declarationMap && !getEmitDeclarations(options)) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "declarationMap", "declaration");
}
@@ -2548,6 +2548,10 @@ namespace ts {
if (getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeJs) {
createDiagnosticForOptionName(Diagnostics.Option_resolveJsonModule_cannot_be_specified_without_node_module_resolution_strategy, "resolveJsonModule");
}
// Any emit other than common js is error
else if (getEmitModuleKind(options) !== ModuleKind.CommonJS) {
createDiagnosticForOptionName(Diagnostics.Option_resolveJsonModule_can_only_be_specified_when_module_code_generation_is_commonjs, "resolveJsonModule", "module");
}
}
// there has to be common source directory if user specified --outdir || --sourceRoot
+35 -13
View File
@@ -81,6 +81,7 @@ namespace ts {
let filesWithInvalidatedResolutions: Map<true> | undefined;
let filesWithInvalidatedNonRelativeUnresolvedImports: Map<ReadonlyArray<string>> | undefined;
let allFilesHaveInvalidatedResolution = false;
const nonRelativeExternalModuleResolutions = createMultiMap<ResolutionWithFailedLookupLocations>();
const getCurrentDirectory = memoize(() => resolutionHost.getCurrentDirectory!()); // TODO: GH#18217
const cachedDirectoryStructureHost = resolutionHost.getCachedDirectoryStructureHost();
@@ -154,6 +155,7 @@ namespace ts {
function clear() {
clearMap(directoryWatchesOfFailedLookups, closeFileWatcherOf);
customFailedLookupPaths.clear();
nonRelativeExternalModuleResolutions.clear();
closeTypeRootsWatch();
resolvedModuleNames.clear();
resolvedTypeReferenceDirectives.clear();
@@ -199,19 +201,20 @@ namespace ts {
perDirectoryResolvedModuleNames.clear();
nonRelaticeModuleNameCache.clear();
perDirectoryResolvedTypeReferenceDirectives.clear();
nonRelativeExternalModuleResolutions.forEach(watchFailedLookupLocationOfNonRelativeModuleResolutions);
nonRelativeExternalModuleResolutions.clear();
}
function finishCachingPerDirectoryResolution() {
allFilesHaveInvalidatedResolution = false;
filesWithInvalidatedNonRelativeUnresolvedImports = undefined;
clearPerDirectoryResolutions();
directoryWatchesOfFailedLookups.forEach((watcher, path) => {
if (watcher.refCount === 0) {
directoryWatchesOfFailedLookups.delete(path);
watcher.watcher.close();
}
});
clearPerDirectoryResolutions();
}
function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): CachedResolvedModuleWithFailedLookupLocations {
@@ -275,7 +278,7 @@ namespace ts {
perDirectoryResolution.set(name, resolution);
}
resolutionsInFile.set(name, resolution);
watchFailedLookupLocationOfResolution(resolution);
watchFailedLookupLocationsOfExternalModuleResolutions(name, resolution);
if (existingResolution) {
stopWatchFailedLookupLocationOfResolution(existingResolution);
}
@@ -441,18 +444,27 @@ namespace ts {
return fileExtensionIsOneOf(path, failedLookupDefaultExtensions);
}
function watchFailedLookupLocationOfResolution(resolution: ResolutionWithFailedLookupLocations) {
function watchFailedLookupLocationsOfExternalModuleResolutions(name: string, resolution: ResolutionWithFailedLookupLocations) {
// No need to set the resolution refCount
if (!resolution.failedLookupLocations || !resolution.failedLookupLocations.length) {
return;
if (resolution.failedLookupLocations && resolution.failedLookupLocations.length) {
if (resolution.refCount) {
resolution.refCount++;
}
else {
resolution.refCount = 1;
if (isExternalModuleNameRelative(name)) {
watchFailedLookupLocationOfResolution(resolution);
}
else {
nonRelativeExternalModuleResolutions.add(name, resolution);
}
}
}
}
if (resolution.refCount !== undefined) {
resolution.refCount++;
return;
}
function watchFailedLookupLocationOfResolution(resolution: ResolutionWithFailedLookupLocations) {
Debug.assert(!!resolution.refCount);
resolution.refCount = 1;
const { failedLookupLocations } = resolution;
let setAtRoot = false;
for (const failedLookupLocation of failedLookupLocations) {
@@ -480,6 +492,16 @@ namespace ts {
}
}
function setRefCountToUndefined(resolution: ResolutionWithFailedLookupLocations) {
resolution.refCount = undefined;
}
function watchFailedLookupLocationOfNonRelativeModuleResolutions(resolutions: ResolutionWithFailedLookupLocations[], name: string) {
const updateResolution = resolutionHost.getCurrentProgram().getTypeChecker().tryFindAmbientModuleWithoutAugmentations(name) ?
setRefCountToUndefined : watchFailedLookupLocationOfResolution;
resolutions.forEach(updateResolution);
}
function setDirectoryWatcher(dir: string, dirPath: Path, nonRecursive?: boolean) {
const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath);
if (dirWatcher) {
@@ -492,11 +514,11 @@ namespace ts {
}
function stopWatchFailedLookupLocationOfResolution(resolution: ResolutionWithFailedLookupLocations) {
if (!resolution.failedLookupLocations || !resolution.failedLookupLocations.length) {
if (!resolution.refCount) {
return;
}
resolution.refCount!--;
resolution.refCount--;
if (resolution.refCount) {
return;
}
+65 -31
View File
@@ -332,9 +332,9 @@ namespace ts {
/*@internal*/
export interface RecursiveDirectoryWatcherHost {
watchDirectory: HostWatchDirectory;
useCaseSensitiveFileNames: boolean;
getAccessibleSortedChildDirectories(path: string): ReadonlyArray<string>;
directoryExists(dir: string): boolean;
filePathComparer: Comparer<string>;
realpath(s: string): string;
}
@@ -345,60 +345,94 @@ namespace ts {
*/
/*@internal*/
export function createRecursiveDirectoryWatcher(host: RecursiveDirectoryWatcherHost): (directoryName: string, callback: DirectoryWatcherCallback) => FileWatcher {
type ChildWatches = ReadonlyArray<DirectoryWatcher>;
interface DirectoryWatcher extends FileWatcher {
childWatches: ChildWatches;
interface ChildDirectoryWatcher extends FileWatcher {
dirName: string;
}
type ChildWatches = ReadonlyArray<ChildDirectoryWatcher>;
interface HostDirectoryWatcher {
watcher: FileWatcher;
childWatches: ChildWatches;
refCount: number;
}
const cache = createMap<HostDirectoryWatcher>();
const callbackCache = createMultiMap<DirectoryWatcherCallback>();
const filePathComparer = getStringComparer(!host.useCaseSensitiveFileNames);
const toCanonicalFilePath = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
return createDirectoryWatcher;
/**
* Create the directory watcher for the dirPath.
*/
function createDirectoryWatcher(dirName: string, callback: DirectoryWatcherCallback): DirectoryWatcher {
const watcher = host.watchDirectory(dirName, fileName => {
// Call the actual callback
callback(fileName);
function createDirectoryWatcher(dirName: string, callback?: DirectoryWatcherCallback): ChildDirectoryWatcher {
const dirPath = toCanonicalFilePath(dirName) as Path;
let directoryWatcher = cache.get(dirPath);
if (directoryWatcher) {
directoryWatcher.refCount++;
}
else {
directoryWatcher = {
watcher: host.watchDirectory(dirName, fileName => {
// Call the actual callback
callbackCache.forEach((callbacks, rootDirName) => {
if (rootDirName === dirPath || (startsWith(dirPath, rootDirName) && dirPath[rootDirName.length] === directorySeparator)) {
callbacks.forEach(callback => callback(fileName));
}
});
// Iterate through existing children and update the watches if needed
updateChildWatches(result, callback);
});
// Iterate through existing children and update the watches if needed
updateChildWatches(dirName, dirPath);
}),
refCount: 1,
childWatches: emptyArray
};
cache.set(dirPath, directoryWatcher);
updateChildWatches(dirName, dirPath);
}
let result: DirectoryWatcher = {
close: () => {
watcher.close();
result.childWatches.forEach(closeFileWatcher);
result = undefined!;
},
if (callback) {
callbackCache.add(dirPath, callback);
}
return {
dirName,
childWatches: emptyArray
close: () => {
const directoryWatcher = Debug.assertDefined(cache.get(dirPath));
if (callback) callbackCache.remove(dirPath, callback);
directoryWatcher.refCount--;
if (directoryWatcher.refCount) return;
cache.delete(dirPath);
closeFileWatcherOf(directoryWatcher);
directoryWatcher.childWatches.forEach(closeFileWatcher);
}
};
updateChildWatches(result, callback);
return result;
}
function updateChildWatches(watcher: DirectoryWatcher, callback: DirectoryWatcherCallback) {
function updateChildWatches(dirName: string, dirPath: Path) {
// Iterate through existing children and update the watches if needed
if (watcher) {
watcher.childWatches = watchChildDirectories(watcher.dirName, watcher.childWatches, callback);
const parentWatcher = cache.get(dirPath);
if (parentWatcher) {
parentWatcher.childWatches = watchChildDirectories(dirName, parentWatcher.childWatches);
}
}
/**
* Watch the directories in the parentDir
*/
function watchChildDirectories(parentDir: string, existingChildWatches: ChildWatches, callback: DirectoryWatcherCallback): ChildWatches {
let newChildWatches: DirectoryWatcher[] | undefined;
enumerateInsertsAndDeletes<string, DirectoryWatcher>(
function watchChildDirectories(parentDir: string, existingChildWatches: ChildWatches): ChildWatches {
let newChildWatches: ChildDirectoryWatcher[] | undefined;
enumerateInsertsAndDeletes<string, ChildDirectoryWatcher>(
host.directoryExists(parentDir) ? mapDefined(host.getAccessibleSortedChildDirectories(parentDir), child => {
const childFullName = getNormalizedAbsolutePath(child, parentDir);
// Filter our the symbolic link directories since those arent included in recursive watch
// which is same behaviour when recursive: true is passed to fs.watch
return host.filePathComparer(childFullName, host.realpath(childFullName)) === Comparison.EqualTo ? childFullName : undefined;
return filePathComparer(childFullName, normalizePath(host.realpath(childFullName))) === Comparison.EqualTo ? childFullName : undefined;
}) : emptyArray,
existingChildWatches,
(child, childWatcher) => host.filePathComparer(child, childWatcher.dirName),
(child, childWatcher) => filePathComparer(child, childWatcher.dirName),
createAndAddChildDirectoryWatcher,
closeFileWatcher,
addChildDirectoryWatcher
@@ -410,14 +444,14 @@ namespace ts {
* Create new childDirectoryWatcher and add it to the new ChildDirectoryWatcher list
*/
function createAndAddChildDirectoryWatcher(childName: string) {
const result = createDirectoryWatcher(childName, callback);
const result = createDirectoryWatcher(childName);
addChildDirectoryWatcher(result);
}
/**
* Add child directory watcher to the new ChildDirectoryWatcher list
*/
function addChildDirectoryWatcher(childWatcher: DirectoryWatcher) {
function addChildDirectoryWatcher(childWatcher: ChildDirectoryWatcher) {
(newChildWatches || (newChildWatches = [])).push(childWatcher);
}
}
@@ -710,7 +744,7 @@ namespace ts {
createWatchDirectoryUsing(dynamicPollingWatchFile || createDynamicPriorityPollingWatchFile({ getModifiedTime, setTimeout })) :
watchDirectoryUsingFsWatch;
const watchDirectoryRecursively = createRecursiveDirectoryWatcher({
filePathComparer: getStringComparer(!useCaseSensitiveFileNames),
useCaseSensitiveFileNames,
directoryExists,
getAccessibleSortedChildDirectories: path => getAccessibleFileSystemEntries(path).directories,
watchDirectory,
+3 -2
View File
@@ -11,11 +11,12 @@ namespace ts {
const declarationEmitNodeBuilderFlags =
NodeBuilderFlags.MultilineObjectLiterals |
TypeFormatFlags.WriteClassExpressionAsTypeLiteral |
NodeBuilderFlags.WriteClassExpressionAsTypeLiteral |
NodeBuilderFlags.UseTypeOfFunction |
NodeBuilderFlags.UseStructuralFallback |
NodeBuilderFlags.AllowEmptyTuple |
NodeBuilderFlags.GenerateNamesForShadowedTypeParams;
NodeBuilderFlags.GenerateNamesForShadowedTypeParams |
NodeBuilderFlags.NoTruncation;
/**
* Transforms a ts file into a .d.ts file
+43 -40
View File
@@ -1982,18 +1982,16 @@ namespace ts {
const kind = resolver.getTypeReferenceSerializationKind(node.typeName, currentNameScope || currentLexicalScope);
switch (kind) {
case TypeReferenceSerializationKind.Unknown:
const serialized = serializeEntityNameAsExpression(node.typeName, /*useFallback*/ true);
const serialized = serializeEntityNameAsExpressionFallback(node.typeName);
const temp = createTempVariable(hoistVariableDeclaration);
return createLogicalOr(
createLogicalAnd(
createTypeCheck(createAssignment(temp, serialized), "function"),
temp
),
return createConditional(
createTypeCheck(createAssignment(temp, serialized), "function"),
temp,
createIdentifier("Object")
);
case TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue:
return serializeEntityNameAsExpression(node.typeName, /*useFallback*/ false);
return serializeEntityNameAsExpression(node.typeName);
case TypeReferenceSerializationKind.VoidNullableOrNeverType:
return createVoidZero();
@@ -2028,14 +2026,46 @@ namespace ts {
}
}
function createCheckedValue(left: Expression, right: Expression) {
return createLogicalAnd(
createStrictInequality(createTypeOf(left), createLiteral("undefined")),
right
);
}
/**
* Serializes an entity name which may not exist at runtime, but whose access shouldn't throw
*
* @param node The entity name to serialize.
*/
function serializeEntityNameAsExpressionFallback(node: EntityName): BinaryExpression {
if (node.kind === SyntaxKind.Identifier) {
// A -> typeof A !== undefined && A
const copied = serializeEntityNameAsExpression(node);
return createCheckedValue(copied, copied);
}
if (node.left.kind === SyntaxKind.Identifier) {
// A.B -> typeof A !== undefined && A.B
return createCheckedValue(serializeEntityNameAsExpression(node.left), serializeEntityNameAsExpression(node));
}
// A.B.C -> typeof A !== undefined && (_a = A.B) !== void 0 && _a.C
const left = serializeEntityNameAsExpressionFallback(node.left);
const temp = createTempVariable(hoistVariableDeclaration);
return createLogicalAnd(
createLogicalAnd(
left.left,
createStrictInequality(createAssignment(temp, left.right), createVoidZero())
),
createPropertyAccess(temp, node.right)
);
}
/**
* Serializes an entity name as an expression for decorator type metadata.
*
* @param node The entity name to serialize.
* @param useFallback A value indicating whether to use logical operators to test for the
* entity name at runtime.
*/
function serializeEntityNameAsExpression(node: EntityName, useFallback: boolean): SerializedEntityNameAsExpression {
function serializeEntityNameAsExpression(node: EntityName): SerializedEntityNameAsExpression {
switch (node.kind) {
case SyntaxKind.Identifier:
// Create a clone of the name with a new parent, and treat it as if it were
@@ -2044,20 +2074,11 @@ namespace ts {
name.flags &= ~NodeFlags.Synthesized;
name.original = undefined;
name.parent = getParseTreeNode(currentLexicalScope); // ensure the parent is set to a parse tree node.
if (useFallback) {
return createLogicalAnd(
createStrictInequality(
createTypeOf(name),
createLiteral("undefined")
),
name
);
}
return name;
case SyntaxKind.QualifiedName:
return serializeQualifiedNameAsExpression(node, useFallback);
return serializeQualifiedNameAsExpression(node);
}
}
@@ -2068,26 +2089,8 @@ namespace ts {
* @param useFallback A value indicating whether to use logical operators to test for the
* qualified name at runtime.
*/
function serializeQualifiedNameAsExpression(node: QualifiedName, useFallback: boolean): PropertyAccessExpression {
let left: SerializedEntityNameAsExpression;
if (node.left.kind === SyntaxKind.Identifier) {
left = serializeEntityNameAsExpression(node.left, useFallback);
}
else if (useFallback) {
const temp = createTempVariable(hoistVariableDeclaration);
left = createLogicalAnd(
createAssignment(
temp,
serializeEntityNameAsExpression(node.left, /*useFallback*/ true)
),
temp
);
}
else {
left = serializeEntityNameAsExpression(node.left, /*useFallback*/ false);
}
return createPropertyAccess(left, node.right);
function serializeQualifiedNameAsExpression(node: QualifiedName): SerializedEntityNameAsExpression {
return createPropertyAccess(serializeEntityNameAsExpression(node.left), node.right);
}
/**
+7 -4
View File
@@ -304,7 +304,7 @@ namespace ts {
const outputs: string[] = [];
outputs.push(getOutputJavaScriptFileName(inputFileName, configFile));
if (configFile.options.declaration && !fileExtensionIs(inputFileName, Extension.Json)) {
if (getEmitDeclarations(configFile.options) && !fileExtensionIs(inputFileName, Extension.Json)) {
const dts = getOutputDeclarationFileName(inputFileName, configFile);
outputs.push(dts);
if (configFile.options.declarationMap) {
@@ -320,7 +320,7 @@ namespace ts {
}
const outputs: string[] = [];
outputs.push(project.options.outFile);
if (project.options.declaration) {
if (getEmitDeclarations(project.options)) {
const dts = changeExtension(project.options.outFile, Extension.Dts);
outputs.push(dts);
if (project.options.declarationMap) {
@@ -769,7 +769,10 @@ namespace ts {
const program = createProgram(programOptions);
// Don't emit anything in the presence of syntactic errors or options diagnostics
const syntaxDiagnostics = [...program.getOptionsDiagnostics(), ...program.getSyntacticDiagnostics()];
const syntaxDiagnostics = [
...program.getOptionsDiagnostics(),
...program.getConfigFileParsingDiagnostics(),
...program.getSyntacticDiagnostics()];
if (syntaxDiagnostics.length) {
resultFlags |= BuildResultFlags.SyntaxErrors;
for (const diag of syntaxDiagnostics) {
@@ -780,7 +783,7 @@ namespace ts {
}
// Don't emit .d.ts if there are decl file errors
if (program.getCompilerOptions().declaration) {
if (getEmitDeclarations(program.getCompilerOptions())) {
const declDiagnostics = program.getDeclarationDiagnostics();
if (declDiagnostics.length) {
resultFlags |= BuildResultFlags.DeclarationEmitErrors;
+3 -3
View File
@@ -2994,9 +2994,9 @@ namespace ts {
*/
/* @internal */ tryGetMemberInModuleExportsAndProperties(memberName: string, moduleSymbol: Symbol): Symbol | undefined;
getApparentType(type: Type): Type;
getSuggestionForNonexistentProperty(name: Identifier | string, containingType: Type): string | undefined;
getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined;
getSuggestionForNonexistentModule(node: Identifier, target: Symbol): string | undefined;
/* @internal */ getSuggestionForNonexistentProperty(name: Identifier | string, containingType: Type): string | undefined;
/* @internal */ getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined;
/* @internal */ getSuggestionForNonexistentExport(node: Identifier, target: Symbol): string | undefined;
getBaseConstraintOfType(type: Type): Type | undefined;
getDefaultFromTypeParameter(type: Type): Type | undefined;
+40 -58
View File
@@ -21,6 +21,8 @@ namespace ts {
export const externalHelpersModuleNameText = "tslib";
export const defaultMaximumTruncationLength = 160;
export function getDeclarationOfKind<T extends Declaration>(symbol: Symbol, kind: T["kind"]): T | undefined {
const declarations = symbol.declarations;
if (declarations) {
@@ -3351,21 +3353,6 @@ namespace ts {
return node.type || (isInJavaScriptFile(node) ? getJSDocReturnType(node) : undefined);
}
/**
* Gets the effective type parameters. If the node was parsed in a
* JavaScript file, gets the type parameters from the `@template` tag from JSDoc.
*/
export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): ReadonlyArray<TypeParameterDeclaration> {
if (isJSDocSignature(node)) {
return emptyArray;
}
if (isJSDocTypeAlias(node)) {
Debug.assert(node.parent.kind === SyntaxKind.JSDocComment);
return flatMap(node.parent.tags, tag => isJSDocTemplateTag(tag) ? tag.typeParameters : undefined) as ReadonlyArray<TypeParameterDeclaration>;
}
return node.typeParameters || (isInJavaScriptFile(node) ? getJSDocTypeParameterDeclarations(node) : emptyArray);
}
export function getJSDocTypeParameterDeclarations(node: DeclarationWithTypeParameters): ReadonlyArray<TypeParameterDeclaration> {
return flatMap(getJSDocTags(node), tag => isNonTypeAliasTemplate(tag) ? tag.typeParameters : undefined);
}
@@ -5022,14 +5009,27 @@ namespace ts {
}
/**
* Gets the return type node for the node if provided via JSDoc's return tag.
* Gets the return type node for the node if provided via JSDoc return tag or type tag.
*
* @remarks `getJSDocReturnTag` just gets the whole JSDoc tag. This function
* gets the type from inside the braces.
* gets the type from inside the braces, after the fat arrow, etc.
*/
export function getJSDocReturnType(node: Node): TypeNode | undefined {
const returnTag = getJSDocReturnTag(node);
return returnTag && returnTag.typeExpression && returnTag.typeExpression.type;
if (returnTag && returnTag.typeExpression) {
return returnTag.typeExpression.type;
}
const typeTag = getJSDocTypeTag(node);
if (typeTag && typeTag.typeExpression) {
const type = typeTag.typeExpression.type;
if (isTypeLiteralNode(type)) {
const sig = find(type.members, isCallSignatureDeclaration);
return sig && sig.type;
}
if (isFunctionTypeNode(type)) {
return type.type;
}
}
}
/** Get all JSDoc tags related to a node, including those on parent nodes. */
@@ -5053,6 +5053,21 @@ namespace ts {
export function getAllJSDocTagsOfKind(node: Node, kind: SyntaxKind): ReadonlyArray<JSDocTag> {
return getJSDocTags(node).filter(doc => doc.kind === kind);
}
/**
* Gets the effective type parameters. If the node was parsed in a
* JavaScript file, gets the type parameters from the `@template` tag from JSDoc.
*/
export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): ReadonlyArray<TypeParameterDeclaration> {
if (isJSDocSignature(node)) {
return emptyArray;
}
if (isJSDocTypeAlias(node)) {
Debug.assert(node.parent.kind === SyntaxKind.JSDocComment);
return flatMap(node.parent.tags, tag => isJSDocTemplateTag(tag) ? tag.typeParameters : undefined) as ReadonlyArray<TypeParameterDeclaration>;
}
return node.typeParameters || (isInJavaScriptFile(node) ? getJSDocTypeParameterDeclarations(node) : emptyArray);
}
}
// Simple node tests of the form `node.kind === SyntaxKind.Foo`.
@@ -6572,45 +6587,6 @@ namespace ts {
return !!(node as HasType).type;
}
/* True if the node could have a type node a `.type` */
/* @internal */
export function couldHaveType(node: Node): node is HasType {
switch (node.kind) {
case SyntaxKind.Parameter:
case SyntaxKind.PropertySignature:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.MethodSignature:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.Constructor:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
case SyntaxKind.IndexSignature:
case SyntaxKind.TypePredicate:
case SyntaxKind.FunctionType:
case SyntaxKind.ConstructorType:
case SyntaxKind.ParenthesizedType:
case SyntaxKind.TypeOperator:
case SyntaxKind.MappedType:
case SyntaxKind.TypeAssertionExpression:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
case SyntaxKind.AsExpression:
case SyntaxKind.VariableDeclaration:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.TypeAliasDeclaration:
case SyntaxKind.JSDocTypeExpression:
case SyntaxKind.JSDocNullableType:
case SyntaxKind.JSDocNonNullableType:
case SyntaxKind.JSDocOptionalType:
case SyntaxKind.JSDocFunctionType:
case SyntaxKind.JSDocVariadicType:
return true;
}
return false;
}
/** True if has initializer node attached to it. */
/* @internal */
export function hasInitializer(node: Node): node is HasInitializer {
@@ -6939,7 +6915,7 @@ namespace ts {
}
export function getAreDeclarationMapsEnabled(options: CompilerOptions) {
return !!(options.declaration && options.declarationMap);
return !!(getEmitDeclarations(options) && options.declarationMap);
}
export function getAllowSyntheticDefaultImports(compilerOptions: CompilerOptions) {
@@ -8108,4 +8084,10 @@ namespace ts {
}
export type Mutable<T extends object> = { -readonly [K in keyof T]: T[K] };
export function sliceAfter<T>(arr: ReadonlyArray<T>, value: T): ReadonlyArray<T> {
const index = arr.indexOf(value);
Debug.assert(index !== -1);
return arr.slice(index);
}
}
+20 -1
View File
@@ -398,7 +398,7 @@ namespace ts {
case WatchLogLevel.TriggerOnly:
return createFileWatcherWithTriggerLogging;
case WatchLogLevel.Verbose:
return createFileWatcherWithLogging;
return addWatch === <any>watchDirectory ? createDirectoryWatcherWithLogging : createFileWatcherWithLogging;
}
}
@@ -413,6 +413,25 @@ namespace ts {
};
}
function createDirectoryWatcherWithLogging<H, T, U, V, X, Y>(host: H, file: string, cb: WatchCallback<U, V>, flags: T, passThrough: V | undefined, detailInfo1: X | undefined, detailInfo2: Y | undefined, addWatch: AddWatch<H, T, U, undefined>, log: (s: string) => void, watchCaption: string, getDetailWatchInfo: GetDetailWatchInfo<X, Y> | undefined): FileWatcher {
const watchInfo = `${watchCaption}:: Added:: ${getWatchInfo(file, flags, detailInfo1, detailInfo2, getDetailWatchInfo)}`;
log(watchInfo);
const start = timestamp();
const watcher = createFileWatcherWithTriggerLogging(host, file, cb, flags, passThrough, detailInfo1, detailInfo2, addWatch, log, watchCaption, getDetailWatchInfo);
const elapsed = timestamp() - start;
log(`Elapsed:: ${elapsed}ms ${watchInfo}`);
return {
close: () => {
const watchInfo = `${watchCaption}:: Close:: ${getWatchInfo(file, flags, detailInfo1, detailInfo2, getDetailWatchInfo)}`;
log(watchInfo);
const start = timestamp();
watcher.close();
const elapsed = timestamp() - start;
log(`Elapsed:: ${elapsed}ms ${watchInfo}`);
}
};
}
function createFileWatcherWithTriggerLogging<H, T, U, V, X, Y>(host: H, file: string, cb: WatchCallback<U, V>, flags: T, passThrough: V | undefined, detailInfo1: X | undefined, detailInfo2: Y | undefined, addWatch: AddWatch<H, T, U, undefined>, log: (s: string) => void, watchCaption: string, getDetailWatchInfo: GetDetailWatchInfo<X, Y> | undefined): FileWatcher {
return addWatch(host, file, (fileName, cbOptional) => {
const triggerredInfo = `${watchCaption}:: Triggered with ${fileName}${cbOptional !== undefined ? cbOptional : ""}:: ${getWatchInfo(file, flags, detailInfo1, detailInfo2, getDetailWatchInfo)}`;
+4 -2
View File
@@ -1515,7 +1515,9 @@ Actual: ${stringify(fullActual)}`);
"argumentCount",
];
for (const key in options) {
ts.Debug.assert(ts.contains(allKeys, key));
if (!ts.contains(allKeys, key)) {
ts.Debug.fail("Unexpected key " + key);
}
}
}
@@ -3367,7 +3369,7 @@ Actual: ${stringify(fullActual)}`);
this.languageServiceAdapterHost.renameFileOrDirectory(oldPath, newPath);
this.languageService.cleanupSemanticCache();
const pathUpdater = ts.getPathUpdater(oldPath, newPath, ts.createGetCanonicalFileName(/*useCaseSensitiveFileNames*/ false));
const pathUpdater = ts.getPathUpdater(oldPath, newPath, ts.createGetCanonicalFileName(/*useCaseSensitiveFileNames*/ false), /*sourceMapper*/ undefined);
test(renameKeys(newFileContents, key => pathUpdater(key) || key), "with file moved");
}
+1 -1
View File
@@ -155,7 +155,7 @@ namespace Harness.LanguageService {
this.vfs.mkdirpSync(ts.getDirectoryPath(newPath));
this.vfs.renameSync(oldPath, newPath);
const updater = ts.getPathUpdater(oldPath, newPath, ts.createGetCanonicalFileName(this.useCaseSensitiveFileNames()));
const updater = ts.getPathUpdater(oldPath, newPath, ts.createGetCanonicalFileName(this.useCaseSensitiveFileNames()), /*sourceMapper*/ undefined);
this.scriptInfos.forEach((scriptInfo, key) => {
const newFileName = updater(key);
if (newFileName !== undefined) {
+3 -3
View File
@@ -352,9 +352,9 @@ interface Array<T> {}`
if (tscWatchDirectory === Tsc_WatchDirectory.WatchFile) {
const watchDirectory: HostWatchDirectory = (directory, cb) => this.watchFile(directory, () => cb(directory), PollingInterval.Medium);
this.customRecursiveWatchDirectory = createRecursiveDirectoryWatcher({
useCaseSensitiveFileNames: this.useCaseSensitiveFileNames,
directoryExists: path => this.directoryExists(path),
getAccessibleSortedChildDirectories: path => this.getDirectories(path),
filePathComparer: this.useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive,
watchDirectory,
realpath: s => this.realpath(s)
});
@@ -362,9 +362,9 @@ interface Array<T> {}`
else if (tscWatchDirectory === Tsc_WatchDirectory.NonRecursiveWatchDirectory) {
const watchDirectory: HostWatchDirectory = (directory, cb) => this.watchDirectory(directory, fileName => cb(fileName), /*recursive*/ false);
this.customRecursiveWatchDirectory = createRecursiveDirectoryWatcher({
useCaseSensitiveFileNames: this.useCaseSensitiveFileNames,
directoryExists: path => this.directoryExists(path),
getAccessibleSortedChildDirectories: path => this.getDirectories(path),
filePathComparer: this.useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive,
watchDirectory,
realpath: s => this.realpath(s)
});
@@ -373,9 +373,9 @@ interface Array<T> {}`
const watchFile = createDynamicPriorityPollingWatchFile(this);
const watchDirectory: HostWatchDirectory = (directory, cb) => watchFile(directory, () => cb(directory), PollingInterval.Medium);
this.customRecursiveWatchDirectory = createRecursiveDirectoryWatcher({
useCaseSensitiveFileNames: this.useCaseSensitiveFileNames,
directoryExists: path => this.directoryExists(path),
getAccessibleSortedChildDirectories: path => this.getDirectories(path),
filePathComparer: this.useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive,
watchDirectory,
realpath: s => this.realpath(s)
});
-1
View File
@@ -1,4 +1,3 @@
/* @internal */
declare namespace ts.server {
export type ActionSet = "action::set";
export type ActionInvalidate = "action::invalidate";
-1
View File
@@ -1,5 +1,4 @@
namespace ts.server {
/*@internal*/
export interface ScriptInfoVersion {
svc: number;
text: number;
+40 -18
View File
@@ -286,6 +286,16 @@ namespace ts.server {
: deduplicate(outputs, areEqual);
}
function combineProjectOutputFromEveryProject<T>(projectService: ProjectService, action: (project: Project) => ReadonlyArray<T>, areEqual: (a: T, b: T) => boolean) {
const outputs: T[] = [];
projectService.forEachProject(project => {
if (project.isOrphan() || !project.languageServiceEnabled) return;
const theseOutputs = action(project);
outputs.push(...theseOutputs.filter(output => !outputs.some(o => areEqual(o, output))));
});
return outputs;
}
function combineProjectOutputWhileOpeningReferencedProjects<T>(
projects: Projects,
projectService: ProjectService,
@@ -1147,7 +1157,9 @@ namespace ts.server {
const refs: protocol.ReferencesResponseItem[] = flatMap(references, referencedSymbol =>
referencedSymbol.references.map(({ fileName, textSpan, isWriteAccess, isDefinition }): protocol.ReferencesResponseItem => {
const scriptInfo = Debug.assertDefined(this.projectService.getScriptInfo(fileName));
const lineText = scriptInfo.getSnapshot().getText(textSpan.start, textSpanEnd(textSpan));
const start = scriptInfo.positionToLineOffset(textSpan.start);
const lineSpan = scriptInfo.lineToTextSpan(start.line - 1);
const lineText = scriptInfo.getSnapshot().getText(lineSpan.start, textSpanEnd(lineSpan)).replace(/\r|\n/g, "");
return { ...toFileSpan(fileName, textSpan, scriptInfo), lineText, isWriteAccess, isDefinition };
}));
const result: protocol.ReferencesResponseBody = { refs, symbolName, symbolStartOffset, symbolDisplayString };
@@ -1747,19 +1759,11 @@ namespace ts.server {
const newPath = toNormalizedPath(args.newFilePath);
const formatOptions = this.getHostFormatOptions();
const preferences = this.getHostPreferences();
const changes: (protocol.FileCodeEdits | FileTextChanges)[] = [];
this.projectService.forEachProject(project => {
if (project.isOrphan() || !project.languageServiceEnabled) return;
for (const fileTextChanges of project.getLanguageService().getEditsForFileRename(oldPath, newPath, formatOptions, preferences)) {
// Subsequent projects may make conflicting edits to the same file -- just go with the first.
if (!changes.some(f => f.fileName === fileTextChanges.fileName)) {
changes.push(simplifiedResult ? this.mapTextChangeToCodeEdit(project, fileTextChanges) : fileTextChanges);
}
}
});
return changes as ReadonlyArray<protocol.FileCodeEdits> | ReadonlyArray<FileTextChanges>;
const changes = combineProjectOutputFromEveryProject(
this.projectService,
project => project.getLanguageService().getEditsForFileRename(oldPath, newPath, formatOptions, preferences),
(a, b) => a.fileName === b.fileName);
return simplifiedResult ? changes.map(c => this.mapTextChangeToCodeEditUsingScriptInfo(c)) : changes;
}
private getCodeFixes(args: protocol.CodeFixRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.CodeFixAction> | ReadonlyArray<CodeFixAction> | undefined {
@@ -1833,8 +1837,15 @@ namespace ts.server {
}
private mapTextChangeToCodeEdit(project: Project, change: FileTextChanges): protocol.FileCodeEdits {
const path = normalizedPathToPath(toNormalizedPath(change.fileName), this.host.getCurrentDirectory(), fileName => this.getCanonicalFileName(fileName));
return mapTextChangesToCodeEdits(change, project.getSourceFileOrConfigFile(path));
return mapTextChangesToCodeEditsForFile(change, project.getSourceFileOrConfigFile(this.normalizePath(change.fileName)));
}
private mapTextChangeToCodeEditUsingScriptInfo(change: FileTextChanges): protocol.FileCodeEdits {
return mapTextChangesToCodeEditsUsingScriptInfo(change, this.projectService.getScriptInfo(this.normalizePath(change.fileName)));
}
private normalizePath(fileName: string) {
return normalizedPathToPath(toNormalizedPath(fileName), this.host.getCurrentDirectory(), fileName => this.getCanonicalFileName(fileName));
}
private convertTextChangeToCodeEdit(change: TextChange, scriptInfo: ScriptInfo): protocol.CodeEdit {
@@ -2346,8 +2357,8 @@ namespace ts.server {
return { file: fileName, start: scriptInfo.positionToLineOffset(textSpan.start), end: scriptInfo.positionToLineOffset(textSpanEnd(textSpan)) };
}
function mapTextChangesToCodeEdits(textChanges: FileTextChanges, sourceFile: SourceFile | undefined): protocol.FileCodeEdits {
Debug.assert(!!textChanges.isNewFile === !sourceFile);
function mapTextChangesToCodeEditsForFile(textChanges: FileTextChanges, sourceFile: SourceFile | undefined): protocol.FileCodeEdits {
Debug.assert(!!textChanges.isNewFile === !sourceFile, "Expected isNewFile for (only) new files", () => JSON.stringify({ isNewFile: textChanges.isNewFile, hasSourceFile: !!sourceFile }));
if (sourceFile) {
return {
fileName: textChanges.fileName,
@@ -2359,6 +2370,13 @@ namespace ts.server {
}
}
function mapTextChangesToCodeEditsUsingScriptInfo(textChanges: FileTextChanges, scriptInfo: ScriptInfo | undefined): protocol.FileCodeEdits {
Debug.assert(!!textChanges.isNewFile === !scriptInfo);
return scriptInfo
? { fileName: textChanges.fileName, textChanges: textChanges.textChanges.map(textChange => convertTextChangeToCodeEditUsingScriptInfo(textChange, scriptInfo)) }
: convertNewFileTextChangeToCodeEdit(textChanges);
}
function convertTextChangeToCodeEdit(change: TextChange, sourceFile: SourceFile): protocol.CodeEdit {
return {
start: convertToLocation(sourceFile.getLineAndCharacterOfPosition(change.span.start)),
@@ -2367,6 +2385,10 @@ namespace ts.server {
};
}
function convertTextChangeToCodeEditUsingScriptInfo(change: TextChange, scriptInfo: ScriptInfo) {
return { start: scriptInfo.positionToLineOffset(change.span.start), end: scriptInfo.positionToLineOffset(textSpanEnd(change.span)), newText: change.newText };
}
function convertNewFileTextChangeToCodeEdit(textChanges: FileTextChanges): protocol.FileCodeEdits {
Debug.assert(textChanges.textChanges.length === 1);
const change = first(textChanges.textChanges);
+1 -1
View File
@@ -43,7 +43,7 @@ namespace ts.codefix {
const importDeclaration = findAncestor(node, isImportDeclaration)!;
const resolvedSourceFile = getResolvedSourceFileFromImportDeclaration(sourceFile, context, importDeclaration);
if (resolvedSourceFile && resolvedSourceFile.symbol) {
suggestion = checker.getSuggestionForNonexistentModule(node as Identifier, resolvedSourceFile.symbol);
suggestion = checker.getSuggestionForNonexistentExport(node as Identifier, resolvedSourceFile.symbol);
}
}
else {
+12 -33
View File
@@ -5,14 +5,14 @@ namespace ts.codefix {
registerCodeFix({
errorCodes,
getCodeActions(context) {
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, context.span.start));
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, context.span.start, context.span.length));
return [createCodeFixAction(fixId, changes, Diagnostics.Remove_unreachable_code, fixId, Diagnostics.Remove_all_unreachable_code)];
},
fixIds: [fixId],
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => doChange(changes, diag.file, diag.start)),
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => doChange(changes, diag.file, diag.start, diag.length)),
});
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, start: number): void {
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, start: number, length: number): void {
const token = getTokenAtPosition(sourceFile, start);
const statement = findAncestor(token, isStatement)!;
Debug.assert(statement.getStart(sourceFile) === token.getStart(sourceFile));
@@ -36,7 +36,9 @@ namespace ts.codefix {
break;
default:
if (isBlock(statement.parent)) {
split(sliceAfter(statement.parent.statements, statement), shouldRemove, (start, end) => changes.deleteNodeRange(sourceFile, start, end));
const end = start + length;
const lastStatement = Debug.assertDefined(lastWhere(sliceAfter(statement.parent.statements, statement), s => s.pos < end));
changes.deleteNodeRange(sourceFile, statement, lastStatement);
}
else {
changes.delete(sourceFile, statement);
@@ -44,35 +46,12 @@ namespace ts.codefix {
}
}
function shouldRemove(s: Statement): boolean {
// Don't remove statements that can validly be used before they appear.
return !isFunctionDeclaration(s) && !isPurelyTypeDeclaration(s) &&
// `var x;` may declare a variable used above
!(isVariableStatement(s) && !(getCombinedNodeFlags(s) & (NodeFlags.Let | NodeFlags.Const)) && s.declarationList.declarations.some(d => !d.initializer));
}
function isPurelyTypeDeclaration(s: Statement): boolean {
switch (s.kind) {
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.TypeAliasDeclaration:
return true;
case SyntaxKind.ModuleDeclaration:
return getModuleInstanceState(s as ModuleDeclaration) !== ModuleInstanceState.Instantiated;
case SyntaxKind.EnumDeclaration:
return hasModifier(s, ModifierFlags.Const);
default:
return false;
function lastWhere<T>(a: ReadonlyArray<T>, pred: (value: T) => boolean): T | undefined {
let last: T | undefined;
for (const value of a) {
if (!pred(value)) break;
last = value;
}
}
function sliceAfter<T>(arr: ReadonlyArray<T>, value: T): ReadonlyArray<T> {
const index = arr.indexOf(value);
Debug.assert(index !== -1);
return arr.slice(index);
}
// Calls 'cb' with the start and end of each range where 'pred' is true.
function split<T>(arr: ReadonlyArray<T>, pred: (t: T) => boolean, cb: (start: T, end: T) => void): void {
getRangesWhere(arr, pred, (start, afterEnd) => cb(arr[start], arr[afterEnd - 1]));
return last;
}
}
+33 -21
View File
@@ -2,12 +2,20 @@
namespace ts.Completions {
export type Log = (message: string) => void;
type SymbolOriginInfo = { type: "this-type" } | { type: "symbol-member" } | SymbolOriginInfoExport;
const enum SymbolOriginInfoKind { ThisType, SymbolMemberNoExport, SymbolMemberExport, Export }
type SymbolOriginInfo = { kind: SymbolOriginInfoKind.ThisType } | { kind: SymbolOriginInfoKind.SymbolMemberNoExport } | SymbolOriginInfoExport;
interface SymbolOriginInfoExport {
type: "export";
kind: SymbolOriginInfoKind.SymbolMemberExport | SymbolOriginInfoKind.Export;
moduleSymbol: Symbol;
isDefaultExport: boolean;
}
function originIsSymbolMember(origin: SymbolOriginInfo): boolean {
return origin.kind === SymbolOriginInfoKind.SymbolMemberExport || origin.kind === SymbolOriginInfoKind.SymbolMemberNoExport;
}
function originIsExport(origin: SymbolOriginInfo): origin is SymbolOriginInfoExport {
return origin.kind === SymbolOriginInfoKind.SymbolMemberExport || origin.kind === SymbolOriginInfoKind.Export;
}
/**
* Map from symbol id -> SymbolOriginInfo.
* Only populated for symbols that come from other modules.
@@ -103,20 +111,22 @@ namespace ts.Completions {
function completionInfoFromData(sourceFile: SourceFile, typeChecker: TypeChecker, compilerOptions: CompilerOptions, log: Log, completionData: CompletionData, preferences: UserPreferences): CompletionInfo | undefined {
const { symbols, completionKind, isInSnippetScope, isNewIdentifierLocation, location, propertyAccessToConvert, keywordFilters, literals, symbolToOriginInfoMap, recommendedCompletion, isJsxInitializer } = completionData;
if (sourceFile.languageVariant === LanguageVariant.JSX && location && location.parent && isJsxClosingElement(location.parent)) {
if (location && location.parent && isJsxClosingElement(location.parent)) {
// In the TypeScript JSX element, if such element is not defined. When users query for completion at closing tag,
// instead of simply giving unknown value, the completion will return the tag-name of an associated opening-element.
// For example:
// var x = <div> </ /*1*/>
// The completion list at "1" will contain "div" with type any
// var x = <div> </ /*1*/
// The completion list at "1" will contain "div>" with type any
// And at `<div> </ /*1*/ >` (with a closing `>`), the completion list will contain "div".
const tagName = location.parent.parent.openingElement.tagName;
return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: false,
entries: [{
name: tagName.getFullText(),
kind: ScriptElementKind.classElement,
kindModifiers: undefined,
sortText: "0",
}]};
const hasClosingAngleBracket = !!findChildOfKind(location.parent, SyntaxKind.GreaterThanToken, sourceFile);
const entry: CompletionEntry = {
name: tagName.getFullText(sourceFile) + (hasClosingAngleBracket ? "" : ">"),
kind: ScriptElementKind.classElement,
kindModifiers: undefined,
sortText: "0",
};
return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: false, entries: [entry] };
}
const entries: CompletionEntry[] = [];
@@ -214,12 +224,12 @@ namespace ts.Completions {
let insertText: string | undefined;
let replacementSpan: TextSpan | undefined;
if (origin && origin.type === "this-type") {
if (origin && origin.kind === SymbolOriginInfoKind.ThisType) {
insertText = needsConvertPropertyAccess ? `this[${quote(name, preferences)}]` : `this.${name}`;
}
// We should only have needsConvertPropertyAccess if there's a property access to convert. But see #21790.
// Somehow there was a global with a non-identifier name. Hopefully someone will complain about getting a "foo bar" global completion and provide a repro.
else if ((origin && origin.type === "symbol-member" || needsConvertPropertyAccess) && propertyAccessToConvert) {
else if ((origin && originIsSymbolMember(origin) || needsConvertPropertyAccess) && propertyAccessToConvert) {
insertText = needsConvertPropertyAccess ? `[${quote(name, preferences)}]` : `[${name}]`;
const dot = findChildOfKind(propertyAccessToConvert, SyntaxKind.DotToken, sourceFile)!;
// If the text after the '.' starts with this name, write over it. Else, add new text.
@@ -253,7 +263,7 @@ namespace ts.Completions {
kindModifiers: SymbolDisplay.getSymbolModifiers(symbol),
sortText: "0",
source: getSourceFromOrigin(origin),
hasAction: trueOrUndefined(!!origin && origin.type === "export"),
hasAction: trueOrUndefined(!!origin && originIsExport(origin)),
isRecommended: trueOrUndefined(isRecommendedCompletionMatch(symbol, recommendedCompletion, typeChecker)),
insertText,
replacementSpan,
@@ -283,7 +293,7 @@ namespace ts.Completions {
}
function getSourceFromOrigin(origin: SymbolOriginInfo | undefined): string | undefined {
return origin && origin.type === "export" ? stripQuotes(origin.moduleSymbol.name) : undefined;
return origin && originIsExport(origin) ? stripQuotes(origin.moduleSymbol.name) : undefined;
}
function getCompletionEntriesFromSymbols(
@@ -529,7 +539,7 @@ namespace ts.Completions {
}
function getSymbolName(symbol: Symbol, origin: SymbolOriginInfo | undefined, target: ScriptTarget): string {
return origin && origin.type === "export" && origin.isDefaultExport && symbol.escapedName === InternalSymbolName.Default
return origin && originIsExport(origin) && origin.isDefaultExport && symbol.escapedName === InternalSymbolName.Default
// Name of "export default foo;" is "foo". Name of "export default 0" is the filename converted to camelCase.
? firstDefined(symbol.declarations, d => isExportAssignment(d) && isIdentifier(d.expression) ? d.expression.text : undefined)
|| codefix.moduleSymbolToValidIdentifier(origin.moduleSymbol, target)
@@ -648,7 +658,7 @@ namespace ts.Completions {
preferences: UserPreferences,
): CodeActionsAndSourceDisplay {
const symbolOriginInfo = symbolToOriginInfoMap[getSymbolId(symbol)];
if (!symbolOriginInfo || symbolOriginInfo.type !== "export") {
if (!symbolOriginInfo || !originIsExport(symbolOriginInfo)) {
return { codeActions: undefined, sourceDisplay: undefined };
}
@@ -1124,7 +1134,9 @@ namespace ts.Completions {
const firstAccessibleSymbol = nameSymbol && getFirstSymbolInChain(nameSymbol, contextToken, typeChecker);
if (firstAccessibleSymbol && !symbolToOriginInfoMap[getSymbolId(firstAccessibleSymbol)]) {
symbols.push(firstAccessibleSymbol);
symbolToOriginInfoMap[getSymbolId(firstAccessibleSymbol)] = { type: "symbol-member" };
const moduleSymbol = firstAccessibleSymbol.parent;
symbolToOriginInfoMap[getSymbolId(firstAccessibleSymbol)] =
!moduleSymbol || !isExternalModuleSymbol(moduleSymbol) ? { kind: SymbolOriginInfoKind.SymbolMemberNoExport } : { kind: SymbolOriginInfoKind.SymbolMemberExport, moduleSymbol, isDefaultExport: false };
}
}
else {
@@ -1222,7 +1234,7 @@ namespace ts.Completions {
const thisType = typeChecker.tryGetThisTypeAt(scopeNode);
if (thisType) {
for (const symbol of getPropertiesForCompletion(thisType, typeChecker)) {
symbolToOriginInfoMap[getSymbolId(symbol)] = { type: "this-type" };
symbolToOriginInfoMap[getSymbolId(symbol)] = { kind: SymbolOriginInfoKind.ThisType };
symbols.push(symbol);
}
}
@@ -1374,7 +1386,7 @@ namespace ts.Completions {
symbol = getLocalSymbolForExportDefault(symbol) || symbol;
}
const origin: SymbolOriginInfo = { type: "export", moduleSymbol, isDefaultExport };
const origin: SymbolOriginInfoExport = { kind: SymbolOriginInfoKind.Export, moduleSymbol, isDefaultExport };
if (detailsEntryId || stringContainsCharactersInOrder(getSymbolName(symbol, origin, target).toLowerCase(), tokenTextLowerCase)) {
symbols.push(symbol);
symbolToOriginInfoMap[getSymbolId(symbol)] = origin;
+9 -6
View File
@@ -234,7 +234,8 @@ namespace ts.FindAllReferences.Core {
export function getReferencedSymbolsForNode(position: number, node: Node, program: Program, sourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken, options: Options = {}, sourceFilesSet: ReadonlyMap<true> = arrayToSet(sourceFiles, f => f.fileName)): SymbolAndEntries[] | undefined {
if (isSourceFile(node)) {
const reference = GoToDefinition.getReferenceAtPosition(node, position, program);
return reference && getReferencedSymbolsForModule(program, program.getTypeChecker().getMergedSymbol(reference.file.symbol), /*excludeImportTypeOfExportEquals*/ false, sourceFiles, sourceFilesSet);
const moduleSymbol = reference && program.getTypeChecker().getMergedSymbol(reference.file.symbol);
return moduleSymbol && getReferencedSymbolsForModule(program, moduleSymbol, /*excludeImportTypeOfExportEquals*/ false, sourceFiles, sourceFilesSet);
}
if (!options.implementations) {
@@ -703,7 +704,7 @@ namespace ts.FindAllReferences.Core {
- But if the parent has `export as namespace`, the symbol is globally visible through that namespace.
*/
const exposedByParent = parent && !(symbol.flags & SymbolFlags.TypeParameter);
if (exposedByParent && !((parent!.flags & SymbolFlags.Module) && isExternalModuleSymbol(parent!) && !parent!.globalExports)) {
if (exposedByParent && !(isExternalModuleSymbol(parent!) && !parent!.globalExports)) {
return undefined;
}
@@ -1462,12 +1463,14 @@ namespace ts.FindAllReferences.Core {
}
/** Gets all symbols for one property. Does not get symbols for every property. */
function getPropertySymbolsFromContextualType(node: ObjectLiteralElement, checker: TypeChecker): ReadonlyArray<Symbol> {
function getPropertySymbolsFromContextualType(node: ObjectLiteralElementWithName, checker: TypeChecker): ReadonlyArray<Symbol> {
const contextualType = checker.getContextualType(<ObjectLiteralExpression>node.parent);
const name = getNameFromPropertyName(node.name!);
const symbol = contextualType && name && contextualType.getProperty(name);
if (!contextualType) return emptyArray;
const name = getNameFromPropertyName(node.name);
if (!name) return emptyArray;
const symbol = contextualType.getProperty(name);
return symbol ? [symbol] :
contextualType && contextualType.isUnion() ? mapDefined(contextualType.types, t => t.getProperty(name!)) : emptyArray; // TODO: GH#18217
contextualType.isUnion() ? mapDefined(contextualType.types, t => t.getProperty(name)) : emptyArray;
}
/**
+29 -7
View File
@@ -1,10 +1,18 @@
/* @internal */
namespace ts {
export function getEditsForFileRename(program: Program, oldFileOrDirPath: string, newFileOrDirPath: string, host: LanguageServiceHost, formatContext: formatting.FormatContext, preferences: UserPreferences): ReadonlyArray<FileTextChanges> {
export function getEditsForFileRename(
program: Program,
oldFileOrDirPath: string,
newFileOrDirPath: string,
host: LanguageServiceHost,
formatContext: formatting.FormatContext,
preferences: UserPreferences,
sourceMapper: SourceMapper,
): ReadonlyArray<FileTextChanges> {
const useCaseSensitiveFileNames = hostUsesCaseSensitiveFileNames(host);
const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
const oldToNew = getPathUpdater(oldFileOrDirPath, newFileOrDirPath, getCanonicalFileName);
const newToOld = getPathUpdater(newFileOrDirPath, oldFileOrDirPath, getCanonicalFileName);
const oldToNew = getPathUpdater(oldFileOrDirPath, newFileOrDirPath, getCanonicalFileName, sourceMapper);
const newToOld = getPathUpdater(newFileOrDirPath, oldFileOrDirPath, getCanonicalFileName, sourceMapper);
return textChanges.ChangeTracker.with({ host, formatContext }, changeTracker => {
updateTsconfigFiles(program, changeTracker, oldToNew, newFileOrDirPath, host.getCurrentDirectory(), useCaseSensitiveFileNames);
updateImports(program, changeTracker, oldToNew, newToOld, host, getCanonicalFileName, preferences);
@@ -14,13 +22,27 @@ namespace ts {
/** If 'path' refers to an old directory, returns path in the new directory. */
type PathUpdater = (path: string) => string | undefined;
// exported for tests
export function getPathUpdater(oldFileOrDirPath: string, newFileOrDirPath: string, getCanonicalFileName: GetCanonicalFileName): PathUpdater {
export function getPathUpdater(oldFileOrDirPath: string, newFileOrDirPath: string, getCanonicalFileName: GetCanonicalFileName, sourceMapper: SourceMapper | undefined): PathUpdater {
const canonicalOldPath = getCanonicalFileName(oldFileOrDirPath);
return path => {
if (getCanonicalFileName(path) === canonicalOldPath) return newFileOrDirPath;
const suffix = tryRemoveDirectoryPrefix(path, canonicalOldPath, getCanonicalFileName);
return suffix === undefined ? undefined : newFileOrDirPath + "/" + suffix;
const originalPath = sourceMapper && sourceMapper.tryGetOriginalLocation({ fileName: path, position: 0 });
const updatedPath = getUpdatedPath(originalPath ? originalPath.fileName : path);
return originalPath
? updatedPath === undefined ? undefined : makeCorrespondingRelativeChange(originalPath.fileName, updatedPath, path, getCanonicalFileName)
: updatedPath;
};
function getUpdatedPath(pathToUpdate: string): string | undefined {
if (getCanonicalFileName(pathToUpdate) === canonicalOldPath) return newFileOrDirPath;
const suffix = tryRemoveDirectoryPrefix(pathToUpdate, canonicalOldPath, getCanonicalFileName);
return suffix === undefined ? undefined : newFileOrDirPath + "/" + suffix;
}
}
// Relative path from a0 to b0 should be same as relative path from a1 to b1. Returns b1.
function makeCorrespondingRelativeChange(a0: string, b0: string, a1: string, getCanonicalFileName: GetCanonicalFileName): string {
const rel = getRelativePathFromFile(a0, b0, getCanonicalFileName);
return combinePathsSafe(getDirectoryPath(a1), rel);
}
function updateTsconfigFiles(program: Program, changeTracker: textChanges.ChangeTracker, oldToNew: PathUpdater, newFileOrDirPath: string, currentDirectory: string, useCaseSensitiveFileNames: boolean): void {
@@ -183,6 +183,26 @@ namespace ts.OutliningElementsCollector {
return spanForObjectOrArrayLiteral(n);
case SyntaxKind.ArrayLiteralExpression:
return spanForObjectOrArrayLiteral(n, SyntaxKind.OpenBracketToken);
case SyntaxKind.JsxElement:
return spanForJSXElement(<JsxElement>n);
case SyntaxKind.JsxSelfClosingElement:
case SyntaxKind.JsxOpeningElement:
return spanForJSXAttributes((<JsxOpeningLikeElement>n).attributes);
}
function spanForJSXElement(node: JsxElement): OutliningSpan | undefined {
const textSpan = createTextSpanFromBounds(node.openingElement.getStart(sourceFile), node.closingElement.getEnd());
const tagName = node.openingElement.tagName.getText(sourceFile);
const bannerText = "<" + tagName + ">...</" + tagName + ">";
return createOutliningSpan(textSpan, OutliningSpanKind.Code, textSpan, /*autoCollapse*/ false, bannerText);
}
function spanForJSXAttributes(node: JsxAttributes): OutliningSpan | undefined {
if (node.properties.length === 0) {
return undefined;
}
return createOutliningSpanFromBounds(node.getStart(sourceFile), node.getEnd(), OutliningSpanKind.Code);
}
function spanForObjectOrArrayLiteral(node: Node, open: SyntaxKind.OpenBraceToken | SyntaxKind.OpenBracketToken = SyntaxKind.OpenBraceToken): OutliningSpan | undefined {
+14 -6
View File
@@ -1537,7 +1537,8 @@ namespace ts {
}
function getDocumentHighlights(fileName: string, position: number, filesToSearch: ReadonlyArray<string>): DocumentHighlights[] | undefined {
Debug.assert(filesToSearch.some(f => normalizePath(f) === fileName));
const normalizedFileName = normalizePath(fileName);
Debug.assert(filesToSearch.some(f => normalizePath(f) === normalizedFileName));
synchronizeHostData();
const sourceFilesToSearch = map(filesToSearch, f => Debug.assertDefined(program.getSourceFile(f)));
const sourceFile = getValidSourceFile(fileName);
@@ -1812,7 +1813,7 @@ namespace ts {
}
function getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences = emptyOptions): ReadonlyArray<FileTextChanges> {
return ts.getEditsForFileRename(getProgram()!, oldFilePath, newFilePath, host, formatting.getFormatContext(formatOptions), preferences);
return ts.getEditsForFileRename(getProgram()!, oldFilePath, newFilePath, host, formatting.getFormatContext(formatOptions), preferences, sourceMapper);
}
function applyCodeActionCommand(action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
@@ -1883,11 +1884,16 @@ namespace ts {
if (!token) return undefined;
const element = token.kind === SyntaxKind.GreaterThanToken && isJsxOpeningElement(token.parent) ? token.parent.parent
: isJsxText(token) ? token.parent : undefined;
if (element && !tagNamesAreEquivalent(element.openingElement.tagName, element.closingElement.tagName)) {
if (element && isUnclosedTag(element)) {
return { newText: `</${element.openingElement.tagName.getText(sourceFile)}>` };
}
}
function isUnclosedTag({ openingElement, closingElement, parent }: JsxElement): boolean {
return !tagNamesAreEquivalent(openingElement.tagName, closingElement.tagName) ||
isJsxElement(parent) && tagNamesAreEquivalent(openingElement.tagName, parent.openingElement.tagName) && isUnclosedTag(parent);
}
function getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined {
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
const range = formatting.getRangeOfEnclosingComment(sourceFile, position);
@@ -2180,21 +2186,23 @@ namespace ts {
* Returns the containing object literal property declaration given a possible name node, e.g. "a" in x = { "a": 1 }
*/
/* @internal */
export function getContainingObjectLiteralElement(node: Node): ObjectLiteralElement | undefined {
export function getContainingObjectLiteralElement(node: Node): ObjectLiteralElementWithName | undefined {
switch (node.kind) {
case SyntaxKind.StringLiteral:
case SyntaxKind.NumericLiteral:
if (node.parent.kind === SyntaxKind.ComputedPropertyName) {
return isObjectLiteralElement(node.parent.parent) ? node.parent.parent : undefined;
return isObjectLiteralElement(node.parent.parent) ? node.parent.parent as ObjectLiteralElementWithName : undefined;
}
// falls through
case SyntaxKind.Identifier:
return isObjectLiteralElement(node.parent) &&
(node.parent.parent.kind === SyntaxKind.ObjectLiteralExpression || node.parent.parent.kind === SyntaxKind.JsxAttributes) &&
node.parent.name === node ? node.parent : undefined;
node.parent.name === node ? node.parent as ObjectLiteralElementWithName : undefined;
}
return undefined;
}
/* @internal */
export type ObjectLiteralElementWithName = ObjectLiteralElement & { name: PropertyName };
/* @internal */
export function getPropertySymbolsFromContextualType(typeChecker: TypeChecker, node: ObjectLiteralElement): Symbol[] {
+55 -11
View File
@@ -29,9 +29,12 @@ namespace ts.SignatureHelp {
return undefined;
}
if (shouldCarefullyCheckContext(triggerReason)) {
// In the middle of a string, don't provide signature help unless the user explicitly requested it.
if (isInString(sourceFile, position, startingToken)) {
// Only need to be careful if the user typed a character and signature help wasn't showing.
const shouldCarefullyCheckContext = !!triggerReason && triggerReason.kind === "characterTyped";
// Bail out quickly in the middle of a string or comment, don't provide signature help unless the user explicitly requested it.
if (shouldCarefullyCheckContext) {
if (isInString(sourceFile, position, startingToken) || isInComment(sourceFile, position)) {
return undefined;
}
}
@@ -41,8 +44,8 @@ namespace ts.SignatureHelp {
cancellationToken.throwIfCancellationRequested();
// Semantic filtering of signature help
const candidateInfo = getCandidateInfo(argumentInfo, typeChecker);
// Extra syntactic and semantic filtering of signature help
const candidateInfo = getCandidateInfo(argumentInfo, typeChecker, sourceFile, startingToken, shouldCarefullyCheckContext);
cancellationToken.throwIfCancellationRequested();
if (!candidateInfo) {
@@ -57,24 +60,57 @@ namespace ts.SignatureHelp {
return typeChecker.runWithCancellationToken(cancellationToken, typeChecker => createSignatureHelpItems(candidateInfo.candidates, candidateInfo.resolvedSignature, argumentInfo, sourceFile, typeChecker));
}
function shouldCarefullyCheckContext(reason: SignatureHelpTriggerReason | undefined) {
// Only need to be careful if the user typed a character and signature help wasn't showing.
return !!reason && reason.kind === "characterTyped";
}
function getCandidateInfo(
argumentInfo: ArgumentListInfo, checker: TypeChecker, sourceFile: SourceFile, startingToken: Node, onlyUseSyntacticOwners: boolean):
{ readonly candidates: ReadonlyArray<Signature>, readonly resolvedSignature: Signature } | undefined {
function getCandidateInfo(argumentInfo: ArgumentListInfo, checker: TypeChecker): { readonly candidates: ReadonlyArray<Signature>, readonly resolvedSignature: Signature } | undefined {
const { invocation } = argumentInfo;
if (invocation.kind === InvocationKind.Call) {
if (onlyUseSyntacticOwners) {
if (isCallOrNewExpression(invocation.node)) {
const invocationChildren = invocation.node.getChildren(sourceFile);
switch (startingToken.kind) {
case SyntaxKind.OpenParenToken:
if (!contains(invocationChildren, startingToken)) {
return undefined;
}
break;
case SyntaxKind.CommaToken:
const containingList = findContainingList(startingToken);
if (!containingList || !contains(invocationChildren, findContainingList(startingToken))) {
return undefined;
}
break;
case SyntaxKind.LessThanToken:
if (!lessThanFollowsCalledExpression(startingToken, sourceFile, invocation.node.expression)) {
return undefined;
}
break;
default:
return undefined;
}
}
else {
return undefined;
}
}
const candidates: Signature[] = [];
const resolvedSignature = checker.getResolvedSignature(invocation.node, candidates, argumentInfo.argumentCount)!; // TODO: GH#18217
return candidates.length === 0 ? undefined : { candidates, resolvedSignature };
}
else {
else if (invocation.kind === InvocationKind.TypeArgs) {
if (onlyUseSyntacticOwners && !lessThanFollowsCalledExpression(startingToken, sourceFile, invocation.called)) {
return undefined;
}
const type = checker.getTypeAtLocation(invocation.called)!; // TODO: GH#18217
const signatures = isNewExpression(invocation.called.parent) ? type.getConstructSignatures() : type.getCallSignatures();
const candidates = signatures.filter(candidate => !!candidate.typeParameters && candidate.typeParameters.length >= argumentInfo.argumentCount);
return candidates.length === 0 ? undefined : { candidates, resolvedSignature: first(candidates) };
}
else {
Debug.assertNever(invocation);
}
}
function createJavaScriptSignatureHelpItems(argumentInfo: ArgumentListInfo, program: Program, cancellationToken: CancellationToken): SignatureHelpItems | undefined {
@@ -107,6 +143,14 @@ namespace ts.SignatureHelp {
}
}
function lessThanFollowsCalledExpression(startingToken: Node, sourceFile: SourceFile, calledExpression: Expression) {
const precedingToken = Debug.assertDefined(
findPrecedingToken(startingToken.getFullStart(), sourceFile, startingToken.parent, /*excludeJsdoc*/ true)
);
return rangeContainsRange(calledExpression, precedingToken);
}
export interface ArgumentInfoForCompletions {
readonly invocation: CallLikeExpression;
readonly argumentIndex: number;
+23 -4
View File
@@ -679,7 +679,7 @@ namespace ts {
let current: Node = sourceFile;
outer: while (true) {
// find the child that contains 'position'
for (const child of current.getChildren()) {
for (const child of current.getChildren(sourceFile)) {
const start = allowPositionInLeadingTrivia ? child.getFullStart() : child.getStart(sourceFile, /*includeJsDoc*/ true);
if (start > position) {
// If this child begins after position, then all subsequent children will as well.
@@ -1184,8 +1184,7 @@ namespace ts {
/** True if the symbol is for an external module, as opposed to a namespace. */
export function isExternalModuleSymbol(moduleSymbol: Symbol): boolean {
Debug.assert(!!(moduleSymbol.flags & SymbolFlags.Module));
return moduleSymbol.name.charCodeAt(0) === CharacterCodes.doubleQuote;
return !!(moduleSymbol.flags & SymbolFlags.Module) && moduleSymbol.name.charCodeAt(0) === CharacterCodes.doubleQuote;
}
/** Returns `true` the first time it encounters a node and `false` afterwards. */
@@ -1435,14 +1434,25 @@ namespace ts {
const displayPartWriter = getDisplayPartWriter();
function getDisplayPartWriter(): DisplayPartsSymbolWriter {
const absoluteMaximumLength = defaultMaximumTruncationLength * 10; // A hard cutoff to avoid overloading the messaging channel in worst-case scenarios
let displayParts: SymbolDisplayPart[];
let lineStart: boolean;
let indent: number;
let length: number;
resetWriter();
const unknownWrite = (text: string) => writeKind(text, SymbolDisplayPartKind.text);
return {
displayParts: () => displayParts,
displayParts: () => {
const finalText = displayParts.length && displayParts[displayParts.length - 1].text;
if (length > absoluteMaximumLength && finalText && finalText !== "...") {
if (!isWhiteSpaceLike(finalText.charCodeAt(finalText.length - 1))) {
displayParts.push(displayPart(" ", SymbolDisplayPartKind.space));
}
displayParts.push(displayPart("...", SymbolDisplayPartKind.punctuation));
}
return displayParts;
},
writeKeyword: text => writeKind(text, SymbolDisplayPartKind.keyword),
writeOperator: text => writeKind(text, SymbolDisplayPartKind.operator),
writePunctuation: text => writeKind(text, SymbolDisplayPartKind.punctuation),
@@ -1472,9 +1482,11 @@ namespace ts {
};
function writeIndent() {
if (length > absoluteMaximumLength) return;
if (lineStart) {
const indentString = getIndentString(indent);
if (indentString) {
length += indentString.length;
displayParts.push(displayPart(indentString, SymbolDisplayPartKind.space));
}
lineStart = false;
@@ -1482,16 +1494,22 @@ namespace ts {
}
function writeKind(text: string, kind: SymbolDisplayPartKind) {
if (length > absoluteMaximumLength) return;
writeIndent();
length += text.length;
displayParts.push(displayPart(text, kind));
}
function writeSymbol(text: string, symbol: Symbol) {
if (length > absoluteMaximumLength) return;
writeIndent();
length += text.length;
displayParts.push(symbolPart(text, symbol));
}
function writeLine() {
if (length > absoluteMaximumLength) return;
length += 1;
displayParts.push(lineBreakPart());
lineStart = true;
}
@@ -1500,6 +1518,7 @@ namespace ts {
displayParts = [];
lineStart = true;
indent = 0;
length = 0;
}
}
+27
View File
@@ -1,5 +1,32 @@
namespace ts {
describe("FactoryAPI", () => {
describe("createExportAssignment", () => {
it("parenthesizes default export if necessary", () => {
function checkExpression(expression: Expression) {
const node = createExportAssignment(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*isExportEquals*/ false,
expression,
);
assert.strictEqual(node.expression.kind, SyntaxKind.ParenthesizedExpression);
}
const clazz = createClassExpression(/*modifiers*/ undefined, "C", /*typeParameters*/ undefined, /*heritageClauses*/ undefined, [
createProperty(/*decorators*/ undefined, [createToken(SyntaxKind.StaticKeyword)], "prop", /*questionOrExclamationToken*/ undefined, /*type*/ undefined, createLiteral("1")),
]);
checkExpression(clazz);
checkExpression(createPropertyAccess(clazz, "prop"));
const func = createFunctionExpression(/*modifiers*/ undefined, /*asteriskToken*/ undefined, "fn", /*typeParameters*/ undefined, /*parameters*/ undefined, /*type*/ undefined, createBlock([]));
checkExpression(func);
checkExpression(createCall(func, /*typeArguments*/ undefined, /*argumentsArray*/ undefined));
checkExpression(createBinary(createLiteral("a"), SyntaxKind.CommaToken, createLiteral("b")));
checkExpression(createCommaList([createLiteral("a"), createLiteral("b")]));
});
});
describe("createArrowFunction", () => {
it("parenthesizes concise body if necessary", () => {
function checkBody(body: ConciseBody) {
@@ -285,4 +285,23 @@ namespace ts {
});
});
describe("errors when a file in a composite project occurs outside the root", () => {
it("Errors when a file is outside the rootdir", () => {
const spec: TestSpecification = {
"/alpha": {
files: { "/alpha/src/a.ts": "import * from '../../beta/b'", "/beta/b.ts": "export { }" },
options: {
declaration: true,
outDir: "bin"
},
references: []
}
};
testProjectReferences(spec, "/alpha/tsconfig.json", (program) => {
assertHasError("Issues an error about the rootDir", program.getOptionsDiagnostics(), Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files);
assertHasError("Issues an error about the fileList", program.getOptionsDiagnostics(), Diagnostics.File_0_is_not_in_project_file_list_Projects_must_list_all_files_or_use_an_include_pattern);
});
});
});
}
@@ -8486,7 +8486,7 @@ new C();`
});
});
it("when watching directories for failed lookup locations in amd resolution", () => {
describe("when watching directories for failed lookup locations in amd resolution", () => {
const projectRoot = "/user/username/projects/project";
const nodeFile: File = {
path: `${projectRoot}/src/typings/node.d.ts`,
@@ -8530,19 +8530,35 @@ export const x = 10;`
}
})
};
const files = [nodeFile, electronFile, srcFile, moduleFile, configFile, libFile];
const host = createServerHost(files);
const service = createProjectService(host);
service.openClientFile(srcFile.path, srcFile.content, ScriptKind.TS, projectRoot);
checkProjectActualFiles(service.configuredProjects.get(configFile.path)!, files.map(f => f.path));
checkWatchedFilesDetailed(host, mapDefined(files, f => f === srcFile ? undefined : f.path), 1);
checkWatchedDirectoriesDetailed(host, [`${projectRoot}`], 1, /*recursive*/ false); // failed lookup for fs
const expectedWatchedDirectories = createMap<number>();
expectedWatchedDirectories.set(`${projectRoot}/src`, 2); // Wild card and failed lookup
expectedWatchedDirectories.set(`${projectRoot}/somefolder`, 1); // failed lookup for somefolder/module2
expectedWatchedDirectories.set(`${projectRoot}/node_modules`, 1); // failed lookup for with node_modules/@types/fs
expectedWatchedDirectories.set(`${projectRoot}/src/typings`, 1); // typeroot directory
checkWatchedDirectoriesDetailed(host, expectedWatchedDirectories, /*recursive*/ true);
function verifyModuleResolution(useNodeFile: boolean) {
const files = [...(useNodeFile ? [nodeFile] : []), electronFile, srcFile, moduleFile, configFile, libFile];
const host = createServerHost(files);
const service = createProjectService(host);
service.openClientFile(srcFile.path, srcFile.content, ScriptKind.TS, projectRoot);
checkProjectActualFiles(service.configuredProjects.get(configFile.path)!, files.map(f => f.path));
checkWatchedFilesDetailed(host, mapDefined(files, f => f === srcFile ? undefined : f.path), 1);
if (useNodeFile) {
checkWatchedDirectories(host, emptyArray, /*recursive*/ false); // since fs resolves to ambient module, shouldnt watch failed lookup
}
else {
checkWatchedDirectoriesDetailed(host, [`${projectRoot}`], 1, /*recursive*/ false); // failed lookup for fs
}
const expectedWatchedDirectories = createMap<number>();
expectedWatchedDirectories.set(`${projectRoot}/src`, 2); // Wild card and failed lookup
expectedWatchedDirectories.set(`${projectRoot}/somefolder`, 1); // failed lookup for somefolder/module2
expectedWatchedDirectories.set(`${projectRoot}/node_modules`, 1); // failed lookup for with node_modules/@types/fs
expectedWatchedDirectories.set(`${projectRoot}/src/typings`, 1); // typeroot directory
checkWatchedDirectoriesDetailed(host, expectedWatchedDirectories, /*recursive*/ true);
}
it("when resolves to ambient module", () => {
verifyModuleResolution(/*useNodeFile*/ true);
});
it("when resolution fails", () => {
verifyModuleResolution(/*useNodeFile*/ false);
});
});
});
@@ -8573,10 +8589,10 @@ export const x = 10;`
tscWatchDirectory === Tsc_WatchDirectory.WatchFile ?
expectedWatchedFiles :
createMap();
// For failed resolution lookup and tsconfig files
mapOfDirectories.set(projectFolder, 2);
// For failed resolution lookup and tsconfig files => cached so only watched only once
mapOfDirectories.set(projectFolder, 1);
// Through above recursive watches
mapOfDirectories.set(projectSrcFolder, 2);
mapOfDirectories.set(projectSrcFolder, 1);
// node_modules/@types folder
mapOfDirectories.set(`${projectFolder}/${nodeModulesAtTypes}`, 1);
const expectedCompletions = ["file1"];
@@ -9042,9 +9058,9 @@ export function Test2() {
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(session, protocol.CommandTypes.References, protocolFileLocationFromSubstring(userTs, "fnA()"));
assert.deepEqual<protocol.ReferencesResponseBody | undefined>(response, {
refs: [
makeReferenceItem(userTs, /*isDefinition*/ true, "fnA"),
makeReferenceItem(userTs, /*isDefinition*/ false, "fnA", { index: 1 }),
makeReferenceItem(aTs, /*isDefinition*/ true, "fnA"),
makeReferenceItem(userTs, /*isDefinition*/ true, "fnA", "import { fnA, instanceA } from \"../a/bin/a\";"),
makeReferenceItem(userTs, /*isDefinition*/ false, "fnA", "export function fnUser() { fnA(); fnB(); instanceA; }", { index: 1 }),
makeReferenceItem(aTs, /*isDefinition*/ true, "fnA", "export function fnA() {}"),
],
symbolName: "fnA",
symbolStartOffset: protocolLocationFromSubstring(userTs.content, "fnA()").offset,
@@ -9118,9 +9134,9 @@ export function Test2() {
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(session, protocol.CommandTypes.References, protocolFileLocationFromSubstring(userTs, "fnB()"));
assert.deepEqual<protocol.ReferencesResponseBody | undefined>(response, {
refs: [
makeReferenceItem(userTs, /*isDefinition*/ true, "fnB"),
makeReferenceItem(userTs, /*isDefinition*/ false, "fnB", { index: 1 }),
makeReferenceItem(bDts, /*isDefinition*/ true, "fnB"),
makeReferenceItem(userTs, /*isDefinition*/ true, "fnB", "import { fnB } from \"../b/bin/b\";"),
makeReferenceItem(userTs, /*isDefinition*/ false, "fnB", "export function fnUser() { fnA(); fnB(); instanceA; }", { index: 1 }),
makeReferenceItem(bDts, /*isDefinition*/ true, "fnB", "export declare function fnB(): void;"),
],
symbolName: "fnB",
symbolStartOffset: protocolLocationFromSubstring(userTs.content, "fnB()").offset,
@@ -9194,14 +9210,30 @@ export function Test2() {
});
});
it("getEditsForFileRename", () => {
const { session, aTs, userTs } = makeSampleProjects();
const response = executeSessionRequest<protocol.GetEditsForFileRenameRequest, protocol.GetEditsForFileRenameResponse>(session, protocol.CommandTypes.GetEditsForFileRename, {
oldFilePath: aTs.path,
newFilePath: "/a/aNew.ts",
});
assert.deepEqual<ReadonlyArray<protocol.FileCodeEdits>>(response, [
{
fileName: userTs.path,
textChanges: [
{ ...protocolTextSpanFromSubstring(userTs.content, "../a/bin/a"), newText: "../a/bin/aNew" },
],
},
]);
});
});
function makeReferenceItem(file: File, isDefinition: boolean, text: string, options?: SpanFromSubstringOptions): protocol.ReferencesResponseItem {
function makeReferenceItem(file: File, isDefinition: boolean, text: string, lineText: string, options?: SpanFromSubstringOptions): protocol.ReferencesResponseItem {
return {
...protocolFileSpanFromSubstring(file, text, options),
isDefinition,
isWriteAccess: isDefinition,
lineText: text,
lineText,
};
}
@@ -7,7 +7,7 @@ tests/cases/conformance/statements/for-ofStatements/ES5For-of17.ts(3,20): error
for (let v of [v]) {
~
!!! error TS2448: Block-scoped variable 'v' used before its declaration.
!!! related TS2728 tests/cases/conformance/statements/for-ofStatements/ES5For-of17.ts:3:14: 'v' was declared here.
!!! related TS2728 tests/cases/conformance/statements/for-ofStatements/ES5For-of17.ts:3:14: 'v' is declared here.
var x = v;
v++;
}
@@ -8,7 +8,7 @@ tests/cases/conformance/statements/for-ofStatements/ES5For-of20.ts(4,15): error
for (let v of [v]) {
~
!!! error TS2448: Block-scoped variable 'v' used before its declaration.
!!! related TS2728 tests/cases/conformance/statements/for-ofStatements/ES5For-of20.ts:3:14: 'v' was declared here.
!!! related TS2728 tests/cases/conformance/statements/for-ofStatements/ES5For-of20.ts:3:14: 'v' is declared here.
const v;
~
!!! error TS1155: 'const' declarations must be initialized.
@@ -32,7 +32,7 @@ tests/cases/conformance/internalModules/DeclarationMerging/simple.ts(2,31): erro
export var Instance = new A();
~
!!! error TS2449: Class 'A' used before its declaration.
!!! related TS2728 tests/cases/conformance/internalModules/DeclarationMerging/simple.ts:6:7: 'A' was declared here.
!!! related TS2728 tests/cases/conformance/internalModules/DeclarationMerging/simple.ts:6:7: 'A' is declared here.
}
// duplicate identifier
@@ -35,4 +35,5 @@ tests/cases/conformance/internalModules/exportDeclarations/ModuleWithExportedAnd
!!! error TS2339: Property 'fn2' does not exist on type 'typeof A'.
var fng2 = A.fng2;
~~~~
!!! error TS2551: Property 'fng2' does not exist on type 'typeof A'. Did you mean 'fng'?
!!! error TS2551: Property 'fng2' does not exist on type 'typeof A'. Did you mean 'fng'?
!!! related TS2728 tests/cases/conformance/internalModules/exportDeclarations/ModuleWithExportedAndNonExportedFunctions.ts:7:21: 'fng' is declared here.
@@ -17,6 +17,7 @@ tests/cases/compiler/anonymousClassExpression2.ts(13,18): error TS2551: Property
this.methodA; // error
~~~~~~~
!!! error TS2551: Property 'methodA' does not exist on type 'B'. Did you mean 'methodB'?
!!! related TS2728 tests/cases/compiler/anonymousClassExpression2.ts:12:9: 'methodB' is declared here.
this.methodB; // ok
}
}
File diff suppressed because it is too large Load Diff
+98 -7
View File
@@ -1,3 +1,18 @@
/*! *****************************************************************************
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.
***************************************************************************** */
declare namespace ts {
const versionMajorMinor = "3.0";
/** The version of the TypeScript compiler release */
@@ -1918,9 +1933,6 @@ declare namespace ts {
getAmbientModules(): Symbol[];
tryGetMemberInModuleExports(memberName: string, moduleSymbol: Symbol): Symbol | undefined;
getApparentType(type: Type): Type;
getSuggestionForNonexistentProperty(name: Identifier | string, containingType: Type): string | undefined;
getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined;
getSuggestionForNonexistentModule(node: Identifier, target: Symbol): string | undefined;
getBaseConstraintOfType(type: Type): Type | undefined;
getDefaultFromTypeParameter(type: Type): Type | undefined;
/**
@@ -3227,16 +3239,21 @@ declare namespace ts {
*/
function getJSDocType(node: Node): TypeNode | undefined;
/**
* Gets the return type node for the node if provided via JSDoc's return tag.
* Gets the return type node for the node if provided via JSDoc return tag or type tag.
*
* @remarks `getJSDocReturnTag` just gets the whole JSDoc tag. This function
* gets the type from inside the braces.
* gets the type from inside the braces, after the fat arrow, etc.
*/
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>;
/** Gets all JSDoc tags of a specified kind, or undefined if not present. */
function getAllJSDocTagsOfKind(node: Node, kind: SyntaxKind): ReadonlyArray<JSDocTag>;
/**
* Gets the effective type parameters. If the node was parsed in a
* JavaScript file, gets the type parameters from the `@template` tag from JSDoc.
*/
function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): ReadonlyArray<TypeParameterDeclaration>;
}
declare namespace ts {
function isNumericLiteral(node: Node): node is NumericLiteral;
@@ -4565,6 +4582,80 @@ declare namespace ts {
function getAllProjectOutputs(project: ParsedCommandLine): ReadonlyArray<string>;
function formatUpToDateStatus<T>(configFileName: string, status: UpToDateStatus, relName: (fileName: string) => string, formatMessage: (message: DiagnosticMessage, ...args: string[]) => T): T | undefined;
}
declare namespace ts.server {
type ActionSet = "action::set";
type ActionInvalidate = "action::invalidate";
type ActionPackageInstalled = "action::packageInstalled";
type EventTypesRegistry = "event::typesRegistry";
type EventBeginInstallTypes = "event::beginInstallTypes";
type EventEndInstallTypes = "event::endInstallTypes";
type EventInitializationFailed = "event::initializationFailed";
interface SortedReadonlyArray<T> extends ReadonlyArray<T> {
" __sortedArrayBrand": any;
}
interface TypingInstallerResponse {
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
}
interface TypingInstallerRequestWithProjectName {
readonly projectName: string;
}
interface DiscoverTypings extends TypingInstallerRequestWithProjectName {
readonly fileNames: string[];
readonly projectRootPath: Path;
readonly compilerOptions: CompilerOptions;
readonly typeAcquisition: TypeAcquisition;
readonly unresolvedImports: SortedReadonlyArray<string>;
readonly cachePath?: string;
readonly kind: "discover";
}
interface CloseProject extends TypingInstallerRequestWithProjectName {
readonly kind: "closeProject";
}
interface TypesRegistryRequest {
readonly kind: "typesRegistry";
}
interface InstallPackageRequest extends TypingInstallerRequestWithProjectName {
readonly kind: "installPackage";
readonly fileName: Path;
readonly packageName: string;
readonly projectRootPath: Path;
}
interface PackageInstalledResponse extends ProjectResponse {
readonly kind: ActionPackageInstalled;
readonly success: boolean;
readonly message: string;
}
interface InitializationFailedResponse extends TypingInstallerResponse {
readonly kind: EventInitializationFailed;
readonly message: string;
}
interface ProjectResponse extends TypingInstallerResponse {
readonly projectName: string;
}
interface InvalidateCachedTypings extends ProjectResponse {
readonly kind: ActionInvalidate;
}
interface InstallTypes extends ProjectResponse {
readonly kind: EventBeginInstallTypes | EventEndInstallTypes;
readonly eventId: number;
readonly typingsInstallerVersion: string;
readonly packagesToInstall: ReadonlyArray<string>;
}
interface BeginInstallTypes extends InstallTypes {
readonly kind: EventBeginInstallTypes;
}
interface EndInstallTypes extends InstallTypes {
readonly kind: EventEndInstallTypes;
readonly installSuccess: boolean;
}
interface SetTypings extends ProjectResponse {
readonly typeAcquisition: TypeAcquisition;
readonly compilerOptions: CompilerOptions;
readonly typings: string[];
readonly unresolvedImports: SortedReadonlyArray<string>;
readonly kind: ActionSet;
}
}
declare namespace ts {
interface Node {
getSourceFile(): SourceFile;
@@ -5569,5 +5660,5 @@ declare namespace ts {
*/
function transform<T extends Node>(source: T | T[], transformers: TransformerFactory<T>[], compilerOptions?: CompilerOptions): TransformationResult<T>;
}
//# sourceMappingURL=typescriptServices.d.ts.map
export = ts
export = ts;
@@ -8,4 +8,5 @@ tests/cases/compiler/assignmentRestElementWithErrorSourceType.ts(2,10): error TS
~
!!! error TS2304: Cannot find name 'c'.
~~~~~
!!! error TS2552: Cannot find name 'tupel'. Did you mean 'tuple'?
!!! error TS2552: Cannot find name 'tupel'. Did you mean 'tuple'?
!!! related TS2728 tests/cases/compiler/assignmentRestElementWithErrorSourceType.ts:1:5: 'tuple' is declared here.
@@ -21,6 +21,7 @@ tests/cases/compiler/baseCheck.ts(26,9): error TS2304: Cannot find name 'x'.
super(0, loc);
~~~
!!! error TS2552: Cannot find name 'loc'. Did you mean 'ELoc'?
!!! related TS2728 tests/cases/compiler/baseCheck.ts:2:7: 'ELoc' is declared here.
}
m() {
@@ -8,16 +8,16 @@ tests/cases/compiler/blockScopedBindingUsedBeforeDef.ts(8,7): error TS2448: Bloc
for (let {[a]: a} of [{ }]) continue;
~
!!! error TS2448: Block-scoped variable 'a' used before its declaration.
!!! related TS2728 tests/cases/compiler/blockScopedBindingUsedBeforeDef.ts:2:16: 'a' was declared here.
!!! related TS2728 tests/cases/compiler/blockScopedBindingUsedBeforeDef.ts:2:16: 'a' is declared here.
// 2:
for (let {[a]: a} = { }; false; ) continue;
~
!!! error TS2448: Block-scoped variable 'a' used before its declaration.
!!! related TS2728 tests/cases/compiler/blockScopedBindingUsedBeforeDef.ts:5:16: 'a' was declared here.
!!! related TS2728 tests/cases/compiler/blockScopedBindingUsedBeforeDef.ts:5:16: 'a' is declared here.
// 3:
let {[b]: b} = { };
~
!!! error TS2448: Block-scoped variable 'b' used before its declaration.
!!! related TS2728 tests/cases/compiler/blockScopedBindingUsedBeforeDef.ts:8:11: 'b' was declared here.
!!! related TS2728 tests/cases/compiler/blockScopedBindingUsedBeforeDef.ts:8:11: 'b' is declared here.
@@ -9,7 +9,7 @@ tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(100,12): error TS2448:
let a = x;
~
!!! error TS2448: Block-scoped variable 'x' used before its declaration.
!!! related TS2728 tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts:3:9: 'x' was declared here.
!!! related TS2728 tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts:3:9: 'x' is declared here.
let x;
}
@@ -68,7 +68,7 @@ tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(100,12): error TS2448:
static a = x;
~
!!! error TS2448: Block-scoped variable 'x' used before its declaration.
!!! related TS2728 tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts:60:9: 'x' was declared here.
!!! related TS2728 tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts:60:9: 'x' is declared here.
}
let x;
}
@@ -78,7 +78,7 @@ tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(100,12): error TS2448:
static a = x;
~
!!! error TS2448: Block-scoped variable 'x' used before its declaration.
!!! related TS2728 tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts:67:9: 'x' was declared here.
!!! related TS2728 tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts:67:9: 'x' is declared here.
}
let x;
}
@@ -116,7 +116,7 @@ tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(100,12): error TS2448:
a: x
~
!!! error TS2448: Block-scoped variable 'x' used before its declaration.
!!! related TS2728 tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts:102:9: 'x' was declared here.
!!! related TS2728 tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts:102:9: 'x' is declared here.
}
let x
}
+4 -4
View File
@@ -14,7 +14,7 @@ tests/cases/compiler/cf.ts(36,13): error TS7027: Unreachable code detected.
if (y==7) {
continue L1;
x=11;
~
~~~~~
!!! error TS7027: Unreachable code detected.
}
if (y==3) {
@@ -28,7 +28,7 @@ tests/cases/compiler/cf.ts(36,13): error TS7027: Unreachable code detected.
if (y==20) {
break;
x=12;
~
~~~~~
!!! error TS7027: Unreachable code detected.
}
} while (y<41);
@@ -41,13 +41,13 @@ tests/cases/compiler/cf.ts(36,13): error TS7027: Unreachable code detected.
L3: if (x<y) {
break L2;
x=13;
~
~~~~~
!!! error TS7027: Unreachable code detected.
}
else {
break L3;
x=14;
~
~~~~~
!!! error TS7027: Unreachable code detected.
}
}
@@ -0,0 +1,11 @@
tests/cases/compiler/bug25434.js(4,9): error TS2304: Cannot find name 'b'.
==== tests/cases/compiler/bug25434.js (1 errors) ====
// should not crash while checking
function Test({ b = '' } = {}) {}
Test(({ b = '5' } = {}));
~
!!! error TS2304: Cannot find name 'b'.
@@ -0,0 +1,10 @@
=== tests/cases/compiler/bug25434.js ===
// should not crash while checking
function Test({ b = '' } = {}) {}
>Test : Symbol(Test, Decl(bug25434.js, 0, 0))
>b : Symbol(b, Decl(bug25434.js, 1, 15))
Test(({ b = '5' } = {}));
>Test : Symbol(Test, Decl(bug25434.js, 0, 0))
>b : Symbol(b, Decl(bug25434.js, 3, 7))
@@ -0,0 +1,17 @@
=== tests/cases/compiler/bug25434.js ===
// should not crash while checking
function Test({ b = '' } = {}) {}
>Test : ({ b }?: { [x: string]: any; }) => void
>b : string
>'' : ""
>{} : { b?: string; }
Test(({ b = '5' } = {}));
>Test(({ b = '5' } = {})) : void
>Test : ({ b }?: { [x: string]: any; }) => void
>({ b = '5' } = {}) : { b?: any; }
>{ b = '5' } = {} : { b?: any; }
>{ b = '5' } : { [x: string]: any; b?: any; }
>b : any
>{} : { b?: any; }
@@ -0,0 +1,36 @@
tests/cases/conformance/jsdoc/test.js(3,17): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/conformance/jsdoc/test.js(5,14): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/conformance/jsdoc/test.js(7,24): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/conformance/jsdoc/test.js(10,17): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/conformance/jsdoc/test.js(12,14): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/conformance/jsdoc/test.js(14,24): error TS2322: Type 'number' is not assignable to type 'string'.
==== tests/cases/conformance/jsdoc/test.js (6 errors) ====
// all 6 should error on return statement/expression
/** @type {(x: number) => string} */
function h(x) { return x }
~~~~~~~~
!!! error TS2322: Type 'number' is not assignable to type 'string'.
/** @type {(x: number) => string} */
var f = x => x
~
!!! error TS2322: Type 'number' is not assignable to type 'string'.
/** @type {(x: number) => string} */
var g = function (x) { return x }
~~~~~~~~
!!! error TS2322: Type 'number' is not assignable to type 'string'.
/** @type {{ (x: number): string }} */
function i(x) { return x }
~~~~~~~~
!!! error TS2322: Type 'number' is not assignable to type 'string'.
/** @type {{ (x: number): string }} */
var j = x => x
~
!!! error TS2322: Type 'number' is not assignable to type 'string'.
/** @type {{ (x: number): string }} */
var k = function (x) { return x }
~~~~~~~~
!!! error TS2322: Type 'number' is not assignable to type 'string'.
@@ -0,0 +1,38 @@
=== tests/cases/conformance/jsdoc/test.js ===
// all 6 should error on return statement/expression
/** @type {(x: number) => string} */
function h(x) { return x }
>h : Symbol(h, Decl(test.js, 0, 0))
>x : Symbol(x, Decl(test.js, 2, 11))
>x : Symbol(x, Decl(test.js, 2, 11))
/** @type {(x: number) => string} */
var f = x => x
>f : Symbol(f, Decl(test.js, 4, 3))
>x : Symbol(x, Decl(test.js, 4, 7))
>x : Symbol(x, Decl(test.js, 4, 7))
/** @type {(x: number) => string} */
var g = function (x) { return x }
>g : Symbol(g, Decl(test.js, 6, 3))
>x : Symbol(x, Decl(test.js, 6, 18))
>x : Symbol(x, Decl(test.js, 6, 18))
/** @type {{ (x: number): string }} */
function i(x) { return x }
>i : Symbol(i, Decl(test.js, 6, 33))
>x : Symbol(x, Decl(test.js, 9, 11))
>x : Symbol(x, Decl(test.js, 9, 11))
/** @type {{ (x: number): string }} */
var j = x => x
>j : Symbol(j, Decl(test.js, 11, 3))
>x : Symbol(x, Decl(test.js, 11, 7))
>x : Symbol(x, Decl(test.js, 11, 7))
/** @type {{ (x: number): string }} */
var k = function (x) { return x }
>k : Symbol(k, Decl(test.js, 13, 3))
>x : Symbol(x, Decl(test.js, 13, 18))
>x : Symbol(x, Decl(test.js, 13, 18))
@@ -0,0 +1,42 @@
=== tests/cases/conformance/jsdoc/test.js ===
// all 6 should error on return statement/expression
/** @type {(x: number) => string} */
function h(x) { return x }
>h : (x: number) => string
>x : number
>x : number
/** @type {(x: number) => string} */
var f = x => x
>f : (x: number) => string
>x => x : (x: number) => string
>x : number
>x : number
/** @type {(x: number) => string} */
var g = function (x) { return x }
>g : (x: number) => string
>function (x) { return x } : (x: number) => string
>x : number
>x : number
/** @type {{ (x: number): string }} */
function i(x) { return x }
>i : (x: number) => string
>x : number
>x : number
/** @type {{ (x: number): string }} */
var j = x => x
>j : (x: number) => string
>x => x : (x: number) => string
>x : number
>x : number
/** @type {{ (x: number): string }} */
var k = function (x) { return x }
>k : (x: number) => string
>function (x) { return x } : (x: number) => string
>x : number
>x : number
@@ -32,6 +32,7 @@ tests/cases/conformance/jsx/file.tsx(32,10): error TS2322: Type '{ children: ((u
<h1>{ user.NAme }</h1>
~~~~
!!! error TS2551: Property 'NAme' does not exist on type 'IUser'. Did you mean 'Name'?
!!! related TS2728 tests/cases/conformance/jsx/file.tsx:4:5: 'Name' is declared here.
) }
</FetchUser>
);
@@ -9,7 +9,7 @@ tests/cases/conformance/internalModules/importDeclarations/circularImportAlias.t
export class D extends a.C {
~
!!! error TS2449: Class 'C' used before its declaration.
!!! related TS2728 tests/cases/conformance/internalModules/importDeclarations/circularImportAlias.ts:11:18: 'C' was declared here.
!!! related TS2728 tests/cases/conformance/internalModules/importDeclarations/circularImportAlias.ts:11:18: 'C' is declared here.
id: number;
}
}
@@ -45,7 +45,7 @@ tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbst
var x : any = C;
~
!!! error TS2449: Class 'C' used before its declaration.
!!! related TS2728 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations2.ts:26:7: 'C' was declared here.
!!! related TS2728 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations2.ts:26:7: 'C' is declared here.
new x; // okay -- undefined behavior at runtime
class C extends B { } // error -- not declared abstract
@@ -12,18 +12,18 @@ tests/cases/compiler/classDeclarationShouldBeOutOfScopeInComputedNames.ts(8,6):
static readonly [A.p1] = 0;
~
!!! error TS2449: Class 'A' used before its declaration.
!!! related TS2728 tests/cases/compiler/classDeclarationShouldBeOutOfScopeInComputedNames.ts:1:7: 'A' was declared here.
!!! related TS2728 tests/cases/compiler/classDeclarationShouldBeOutOfScopeInComputedNames.ts:1:7: 'A' is declared here.
static [A.p2]() { return 0 };
~
!!! error TS2449: Class 'A' used before its declaration.
!!! related TS2728 tests/cases/compiler/classDeclarationShouldBeOutOfScopeInComputedNames.ts:1:7: 'A' was declared here.
!!! related TS2728 tests/cases/compiler/classDeclarationShouldBeOutOfScopeInComputedNames.ts:1:7: 'A' is declared here.
[A.p1]() { }
~
!!! error TS2449: Class 'A' used before its declaration.
!!! related TS2728 tests/cases/compiler/classDeclarationShouldBeOutOfScopeInComputedNames.ts:1:7: 'A' was declared here.
!!! related TS2728 tests/cases/compiler/classDeclarationShouldBeOutOfScopeInComputedNames.ts:1:7: 'A' is declared here.
[A.p2] = 0
~
!!! error TS2449: Class 'A' used before its declaration.
!!! related TS2728 tests/cases/compiler/classDeclarationShouldBeOutOfScopeInComputedNames.ts:1:7: 'A' was declared here.
!!! related TS2728 tests/cases/compiler/classDeclarationShouldBeOutOfScopeInComputedNames.ts:1:7: 'A' is declared here.
}
@@ -14,7 +14,7 @@ tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/cla
!!! error TS2506: 'C' is referenced directly or indirectly in its own base expression.
~
!!! error TS2449: Class 'E' used before its declaration.
!!! related TS2728 tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendsItselfIndirectly.ts:5:7: 'E' was declared here.
!!! related TS2728 tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendsItselfIndirectly.ts:5:7: 'E' is declared here.
class D extends C { bar: string; }
~
@@ -29,7 +29,7 @@ tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/cla
!!! error TS2506: 'C2' is referenced directly or indirectly in its own base expression.
~~
!!! error TS2449: Class 'E2' used before its declaration.
!!! related TS2728 tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendsItselfIndirectly.ts:11:7: 'E2' was declared here.
!!! related TS2728 tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendsItselfIndirectly.ts:11:7: 'E2' is declared here.
class D2<T> extends C2<T> { bar: T; }
~~
@@ -14,7 +14,7 @@ tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/cla
!!! error TS2506: 'C' is referenced directly or indirectly in its own base expression.
~
!!! error TS2449: Class 'E' used before its declaration.
!!! related TS2728 tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendsItselfIndirectly2.ts:9:18: 'E' was declared here.
!!! related TS2728 tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendsItselfIndirectly2.ts:9:18: 'E' is declared here.
module M {
export class D extends C { bar: string; }
@@ -35,7 +35,7 @@ tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/cla
!!! error TS2506: 'C2' is referenced directly or indirectly in its own base expression.
~~
!!! error TS2449: Class 'E2' used before its declaration.
!!! related TS2728 tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendsItselfIndirectly2.ts:20:22: 'E2' was declared here.
!!! related TS2728 tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendsItselfIndirectly2.ts:20:22: 'E2' is declared here.
module P {
export class D2<T> extends C2<T> { bar: T; }
@@ -6,7 +6,7 @@ tests/cases/compiler/classInheritence.ts(2,7): error TS2506: 'A' is referenced d
class B extends A { }
~
!!! error TS2449: Class 'A' used before its declaration.
!!! related TS2728 tests/cases/compiler/classInheritence.ts:2:7: 'A' was declared here.
!!! related TS2728 tests/cases/compiler/classInheritence.ts:2:7: 'A' is declared here.
class A extends A { }
~
!!! error TS2506: 'A' is referenced directly or indirectly in its own base expression.
@@ -12,6 +12,6 @@ tests/cases/compiler/classMergedWithInterfaceMultipleBasesNoError.ts(8,30): erro
readonly observer = this.handleIntersection;
~~~~~~~~~~~~~~~~~~
!!! error TS2729: Property 'handleIntersection' is used before its initialization.
!!! related TS2728 tests/cases/compiler/classMergedWithInterfaceMultipleBasesNoError.ts:9:14: 'handleIntersection' was declared here.
!!! related TS2728 tests/cases/compiler/classMergedWithInterfaceMultipleBasesNoError.ts:9:14: 'handleIntersection' is declared here.
readonly handleIntersection = () => { }
}
@@ -5,7 +5,7 @@ tests/cases/compiler/classOrder2.ts(1,17): error TS2449: Class 'B' used before i
class A extends B {
~
!!! error TS2449: Class 'B' used before its declaration.
!!! related TS2728 tests/cases/compiler/classOrder2.ts:7:7: 'B' was declared here.
!!! related TS2728 tests/cases/compiler/classOrder2.ts:7:7: 'B' is declared here.
foo() { this.bar(); }
@@ -11,7 +11,7 @@ tests/cases/compiler/classSideInheritance2.ts(7,23): error TS2449: Class 'TextBa
class SubText extends TextBase {
~~~~~~~~
!!! error TS2449: Class 'TextBase' used before its declaration.
!!! related TS2728 tests/cases/compiler/classSideInheritance2.ts:14:7: 'TextBase' was declared here.
!!! related TS2728 tests/cases/compiler/classSideInheritance2.ts:14:7: 'TextBase' is declared here.
constructor(text: IText, span: TextSpan) {
super();
@@ -10,21 +10,21 @@ tests/cases/compiler/classStaticInitializersUsePropertiesBeforeDeclaration.ts(4,
static enumMember = Enum.A;
~~~~
!!! error TS2450: Enum 'Enum' used before its declaration.
!!! related TS2728 tests/cases/compiler/classStaticInitializersUsePropertiesBeforeDeclaration.ts:7:6: 'Enum' was declared here.
!!! related TS2728 tests/cases/compiler/classStaticInitializersUsePropertiesBeforeDeclaration.ts:7:6: 'Enum' is declared here.
~
!!! error TS2729: Property 'A' is used before its initialization.
!!! related TS2728 tests/cases/compiler/classStaticInitializersUsePropertiesBeforeDeclaration.ts:8:5: 'A' was declared here.
!!! related TS2728 tests/cases/compiler/classStaticInitializersUsePropertiesBeforeDeclaration.ts:8:5: 'A' is declared here.
static objLiteralMember = ObjLiteral.A;
~~~~~~~~~~
!!! error TS2448: Block-scoped variable 'ObjLiteral' used before its declaration.
!!! related TS2728 tests/cases/compiler/classStaticInitializersUsePropertiesBeforeDeclaration.ts:11:7: 'ObjLiteral' was declared here.
!!! related TS2728 tests/cases/compiler/classStaticInitializersUsePropertiesBeforeDeclaration.ts:11:7: 'ObjLiteral' is declared here.
~
!!! error TS2729: Property 'A' is used before its initialization.
!!! related TS2728 tests/cases/compiler/classStaticInitializersUsePropertiesBeforeDeclaration.ts:12:5: 'A' was declared here.
!!! related TS2728 tests/cases/compiler/classStaticInitializersUsePropertiesBeforeDeclaration.ts:12:5: 'A' is declared here.
static namespaceMember = Namespace.A;
~
!!! error TS2729: Property 'A' is used before its initialization.
!!! related TS2728 tests/cases/compiler/classStaticInitializersUsePropertiesBeforeDeclaration.ts:16:16: 'A' was declared here.
!!! related TS2728 tests/cases/compiler/classStaticInitializersUsePropertiesBeforeDeclaration.ts:16:16: 'A' is declared here.
}
enum Enum {
@@ -6,7 +6,7 @@ tests/cases/compiler/complexClassRelationships.ts(2,23): error TS2449: Class 'Ba
class Derived extends Base {
~~~~
!!! error TS2449: Class 'Base' used before its declaration.
!!! related TS2728 tests/cases/compiler/complexClassRelationships.ts:13:7: 'Base' was declared here.
!!! related TS2728 tests/cases/compiler/complexClassRelationships.ts:13:7: 'Base' is declared here.
public static createEmpty(): Derived {
var item = new Derived();
return item;
@@ -9,17 +9,17 @@ tests/cases/conformance/es6/computedProperties/computedPropertyNamesWithStaticPr
get [C.staticProp]() {
~
!!! error TS2449: Class 'C' used before its declaration.
!!! related TS2728 tests/cases/conformance/es6/computedProperties/computedPropertyNamesWithStaticProperty.ts:1:7: 'C' was declared here.
!!! related TS2728 tests/cases/conformance/es6/computedProperties/computedPropertyNamesWithStaticProperty.ts:1:7: 'C' is declared here.
return "hello";
}
set [C.staticProp](x: string) {
~
!!! error TS2449: Class 'C' used before its declaration.
!!! related TS2728 tests/cases/conformance/es6/computedProperties/computedPropertyNamesWithStaticProperty.ts:1:7: 'C' was declared here.
!!! related TS2728 tests/cases/conformance/es6/computedProperties/computedPropertyNamesWithStaticProperty.ts:1:7: 'C' is declared here.
var y = x;
}
[C.staticProp]() { }
~
!!! error TS2449: Class 'C' used before its declaration.
!!! related TS2728 tests/cases/conformance/es6/computedProperties/computedPropertyNamesWithStaticProperty.ts:1:7: 'C' was declared here.
!!! related TS2728 tests/cases/conformance/es6/computedProperties/computedPropertyNamesWithStaticProperty.ts:1:7: 'C' is declared here.
}
@@ -7,7 +7,7 @@ tests/cases/compiler/constDeclarations-useBeforeDefinition.ts(8,5): error TS2448
c1;
~~
!!! error TS2448: Block-scoped variable 'c1' used before its declaration.
!!! related TS2728 tests/cases/compiler/constDeclarations-useBeforeDefinition.ts:3:11: 'c1' was declared here.
!!! related TS2728 tests/cases/compiler/constDeclarations-useBeforeDefinition.ts:3:11: 'c1' is declared here.
const c1 = 0;
}
@@ -16,7 +16,7 @@ tests/cases/compiler/constDeclarations-useBeforeDefinition.ts(8,5): error TS2448
v1;
~~
!!! error TS2448: Block-scoped variable 'v1' used before its declaration.
!!! related TS2728 tests/cases/compiler/constDeclarations-useBeforeDefinition.ts:9:11: 'v1' was declared here.
!!! related TS2728 tests/cases/compiler/constDeclarations-useBeforeDefinition.ts:9:11: 'v1' is declared here.
const v1 = 0;
}
@@ -5,7 +5,7 @@ tests/cases/compiler/file1.ts(1,1): error TS2448: Block-scoped variable 'c' used
c;
~
!!! error TS2448: Block-scoped variable 'c' used before its declaration.
!!! related TS2728 tests/cases/compiler/file2.ts:1:7: 'c' was declared here.
!!! related TS2728 tests/cases/compiler/file2.ts:1:7: 'c' is declared here.
==== tests/cases/compiler/file2.ts (0 errors) ====
const c = 0;
@@ -466,6 +466,7 @@ tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(261,1): error TS
return this.method1(2);
~~~~~~~
!!! error TS2551: Property 'method1' does not exist on type 'B'. Did you mean 'method2'?
!!! related TS2728 tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts:245:16: 'method2' is declared here.
}
}
@@ -23,7 +23,7 @@ var B = /** @class */ (function () {
var _a;
__decorate([
Decorate,
__metadata("design:type", typeof (_a = typeof Map !== "undefined" && Map) === "function" && _a || Object)
__metadata("design:type", typeof (_a = typeof Map !== "undefined" && Map) === "function" ? _a : Object)
], B.prototype, "member");
return B;
}());
@@ -49,7 +49,7 @@ var MyClass = /** @class */ (function () {
var _a;
MyClass = __decorate([
someDecorator,
__metadata("design:paramtypes", [typeof (_a = (typeof db_1.default !== "undefined" && db_1.default).db) === "function" && _a || Object])
__metadata("design:paramtypes", [typeof (_a = typeof db_1.default !== "undefined" && db_1.default.db) === "function" ? _a : Object])
], MyClass);
return MyClass;
}());
@@ -49,7 +49,7 @@ var MyClass = /** @class */ (function () {
var _a;
MyClass = __decorate([
someDecorator,
__metadata("design:paramtypes", [typeof (_a = (typeof db_1.default !== "undefined" && db_1.default).db) === "function" && _a || Object])
__metadata("design:paramtypes", [typeof (_a = typeof db_1.default !== "undefined" && db_1.default.db) === "function" ? _a : Object])
], MyClass);
return MyClass;
}());
@@ -5,7 +5,7 @@ tests/cases/compiler/derivedClasses.ts(1,19): error TS2449: Class 'Color' used b
class Red extends Color {
~~~~~
!!! error TS2449: Class 'Color' used before its declaration.
!!! related TS2728 tests/cases/compiler/derivedClasses.ts:8:7: 'Color' was declared here.
!!! related TS2728 tests/cases/compiler/derivedClasses.ts:8:7: 'Color' is declared here.
public shade() {
var getHue = () => { return this.hue(); };
return getHue() + " red";
@@ -9,11 +9,11 @@ tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAss
const [c, d = c, e = e] = [1]; // error for e = e
~
!!! error TS2448: Block-scoped variable 'e' used before its declaration.
!!! related TS2728 tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment3.ts:2:18: 'e' was declared here.
!!! related TS2728 tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment3.ts:2:18: 'e' is declared here.
const [f, g = f, h = i, i = f] = [1]; // error for h = i
~
!!! error TS2448: Block-scoped variable 'i' used before its declaration.
!!! related TS2728 tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment3.ts:3:25: 'i' was declared here.
!!! related TS2728 tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment3.ts:3:25: 'i' is declared here.
(function ([a, b = a]) { // ok
})([1]);
@@ -11,10 +11,10 @@ tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAs
e = f, // error
~
!!! error TS2448: Block-scoped variable 'f' used before its declaration.
!!! related TS2728 tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment4.ts:7:5: 'f' was declared here.
!!! related TS2728 tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment4.ts:7:5: 'f' is declared here.
f = f // error
~
!!! error TS2448: Block-scoped variable 'f' used before its declaration.
!!! related TS2728 tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment4.ts:7:5: 'f' was declared here.
!!! related TS2728 tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment4.ts:7:5: 'f' is declared here.
} = { } as any;
@@ -48,6 +48,7 @@ tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration4.ts(
a1(...array2); // Error parameter type is (number|string)[]
~~~~~~
!!! error TS2552: Cannot find name 'array2'. Did you mean 'Array'?
!!! related TS2728 /.ts/lib.es5.d.ts:1298:15: 'Array' is declared here.
a5([1, 2, "string", false, true]); // Error, parameter type is [any, any, [[any]]]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2345: Argument of type '[number, number, string, boolean, boolean]' is not assignable to parameter of type '[any, any, [[any]]]'.
@@ -5,7 +5,7 @@ tests/cases/compiler/enumUsedBeforeDeclaration.ts(1,18): error TS2450: Enum 'Col
const v: Color = Color.Green;
~~~~~
!!! error TS2450: Enum 'Color' used before its declaration.
!!! related TS2728 tests/cases/compiler/enumUsedBeforeDeclaration.ts:3:6: 'Color' was declared here.
!!! related TS2728 tests/cases/compiler/enumUsedBeforeDeclaration.ts:3:6: 'Color' is declared here.
const v2: ConstColor = ConstColor.Green;
enum Color { Red, Green, Blue }
const enum ConstColor { Red, Green, Blue }
@@ -2,9 +2,10 @@ tests/cases/compiler/errorElaboration.ts(12,5): error TS2345: Argument of type '
Type 'Container<Ref<string>>' is not assignable to type 'Container<Ref<number>>'.
Type 'Ref<string>' is not assignable to type 'Ref<number>'.
Type 'string' is not assignable to type 'number'.
tests/cases/compiler/errorElaboration.ts(17,11): error TS2322: Type '"bar"' is not assignable to type '"foo"'.
==== tests/cases/compiler/errorElaboration.ts (1 errors) ====
==== tests/cases/compiler/errorElaboration.ts (2 errors) ====
// Repro for #5712
interface Ref<T> {
@@ -22,4 +23,13 @@ tests/cases/compiler/errorElaboration.ts(12,5): error TS2345: Argument of type '
!!! error TS2345: Type 'Container<Ref<string>>' is not assignable to type 'Container<Ref<number>>'.
!!! error TS2345: Type 'Ref<string>' is not assignable to type 'Ref<number>'.
!!! error TS2345: Type 'string' is not assignable to type 'number'.
// Repro for #25498
function test(): {[A in "foo"]: A} {
return {foo: "bar"};
~~~
!!! error TS2322: Type '"bar"' is not assignable to type '"foo"'.
!!! related TS6500 tests/cases/compiler/errorElaboration.ts:16:18: The expected type comes from property 'foo' which is declared here on type '{ foo: "foo"; }'
}
@@ -11,9 +11,19 @@ interface Container<T> {
declare function foo(x: () => Container<Ref<number>>): void;
let a: () => Container<Ref<string>>;
foo(a);
// Repro for #25498
function test(): {[A in "foo"]: A} {
return {foo: "bar"};
}
//// [errorElaboration.js]
// Repro for #5712
var a;
foo(a);
// Repro for #25498
function test() {
return { foo: "bar" };
}
@@ -38,3 +38,14 @@ foo(a);
>foo : Symbol(foo, Decl(errorElaboration.ts, 8, 1))
>a : Symbol(a, Decl(errorElaboration.ts, 10, 3))
// Repro for #25498
function test(): {[A in "foo"]: A} {
>test : Symbol(test, Decl(errorElaboration.ts, 11, 7))
>A : Symbol(A, Decl(errorElaboration.ts, 15, 19))
>A : Symbol(A, Decl(errorElaboration.ts, 15, 19))
return {foo: "bar"};
>foo : Symbol(foo, Decl(errorElaboration.ts, 16, 10))
}
@@ -39,3 +39,16 @@ foo(a);
>foo : (x: () => Container<Ref<number>>) => void
>a : () => Container<Ref<string>>
// Repro for #25498
function test(): {[A in "foo"]: A} {
>test : () => { foo: "foo"; }
>A : A
>A : A
return {foo: "bar"};
>{foo: "bar"} : { foo: "bar"; }
>foo : "bar"
>"bar" : "bar"
}
@@ -12,4 +12,5 @@ tests/cases/compiler/errorMessageOnObjectLiteralType.ts(6,8): error TS2551: Prop
!!! error TS2339: Property 'getOwnPropertyNamess' does not exist on type '{ a: string; b: number; }'.
Object.getOwnPropertyNamess(null);
~~~~~~~~~~~~~~~~~~~~
!!! error TS2551: Property 'getOwnPropertyNamess' does not exist on type 'ObjectConstructor'. Did you mean 'getOwnPropertyNames'?
!!! error TS2551: Property 'getOwnPropertyNamess' does not exist on type 'ObjectConstructor'. Did you mean 'getOwnPropertyNames'?
!!! related TS2728 /.ts/lib.es5.d.ts:179:5: 'getOwnPropertyNames' is declared here.
@@ -1,4 +1,4 @@
tests/cases/compiler/errorWithTruncatedType.ts(10,5): error TS2322: Type '{ propertyWithAnExceedinglyLongName1: string; propertyWithAnExceedinglyLongName2: string; propert...' is not assignable to type 'string'.
tests/cases/compiler/errorWithTruncatedType.ts(10,5): error TS2322: Type '{ propertyWithAnExceedinglyLongName1: string; propertyWithAnExceedinglyLongName2: string; propertyWithAnExceedinglyLongName3: string; propertyWithAnExceedinglyLongName4: string; propertyWithAnExceedinglyLongName5: string; }' is not assignable to type 'string'.
==== tests/cases/compiler/errorWithTruncatedType.ts (1 errors) ====
@@ -13,5 +13,5 @@ tests/cases/compiler/errorWithTruncatedType.ts(10,5): error TS2322: Type '{ prop
// String representation of type of 'x' should be truncated in error message
var s: string = x;
~
!!! error TS2322: Type '{ propertyWithAnExceedinglyLongName1: string; propertyWithAnExceedinglyLongName2: string; propert...' is not assignable to type 'string'.
!!! error TS2322: Type '{ propertyWithAnExceedinglyLongName1: string; propertyWithAnExceedinglyLongName2: string; propertyWithAnExceedinglyLongName3: string; propertyWithAnExceedinglyLongName4: string; propertyWithAnExceedinglyLongName5: string; }' is not assignable to type 'string'.
@@ -5,7 +5,7 @@ tests/cases/compiler/es5ExportDefaultClassDeclaration3.ts(1,21): error TS2449: C
var before: C = new C();
~
!!! error TS2449: Class 'C' used before its declaration.
!!! related TS2728 tests/cases/compiler/es5ExportDefaultClassDeclaration3.ts:3:22: 'C' was declared here.
!!! related TS2728 tests/cases/compiler/es5ExportDefaultClassDeclaration3.ts:3:22: 'C' is declared here.
export default class C {
method(): C {
@@ -13,4 +13,5 @@ tests/cases/compiler/exactSpellingSuggestion.ts(9,4): error TS2551: Property 'bi
U8.bit_2
~~~~~
!!! error TS2551: Property 'bit_2' does not exist on type 'typeof U8'. Did you mean 'BIT_2'?
!!! related TS2728 tests/cases/compiler/exactSpellingSuggestion.ts:6:5: 'BIT_2' is declared here.

Some files were not shown because too many files have changed in this diff Show More