mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into watchImprovements
This commit is contained in:
@@ -59,3 +59,4 @@ internal/
|
||||
.idea
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
.parallelperf.*
|
||||
|
||||
+14
-29
@@ -31,8 +31,6 @@ import merge2 = require("merge2");
|
||||
import * as os from "os";
|
||||
import fold = require("travis-fold");
|
||||
const gulp = helpMaker(originalGulp);
|
||||
const mochaParallel = require("./scripts/mocha-parallel.js");
|
||||
const {runTestsInParallel} = mochaParallel;
|
||||
|
||||
Error.stackTraceLimit = 1000;
|
||||
|
||||
@@ -668,36 +666,18 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done:
|
||||
}
|
||||
else {
|
||||
// run task to load all tests and partition them between workers
|
||||
const args = [];
|
||||
args.push("-R", "min");
|
||||
if (colors) {
|
||||
args.push("--colors");
|
||||
}
|
||||
else {
|
||||
args.push("--no-colors");
|
||||
}
|
||||
args.push(run);
|
||||
setNodeEnvToDevelopment();
|
||||
runTestsInParallel(taskConfigsFolder, run, { testTimeout, noColors: colors === " --no-colors " }, function(err) {
|
||||
// last worker clean everything and runs linter in case if there were no errors
|
||||
del(taskConfigsFolder).then(() => {
|
||||
if (!err) {
|
||||
lintThenFinish();
|
||||
}
|
||||
else {
|
||||
finish(err);
|
||||
}
|
||||
});
|
||||
exec(host, [run], lintThenFinish, function(e, status) {
|
||||
finish(e, status);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function failWithStatus(err?: any, status?: number) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
if (err || status) {
|
||||
process.exit(typeof status === "number" ? status : 2);
|
||||
}
|
||||
done(err || status);
|
||||
process.exit(status);
|
||||
done();
|
||||
}
|
||||
|
||||
function lintThenFinish() {
|
||||
@@ -711,7 +691,7 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done:
|
||||
|
||||
function finish(error?: any, errorStatus?: number) {
|
||||
restoreSavedNodeEnv();
|
||||
deleteTemporaryProjectOutput().then(() => {
|
||||
deleteTestConfig().then(deleteTemporaryProjectOutput).then(() => {
|
||||
if (error !== undefined || errorStatus !== undefined) {
|
||||
failWithStatus(error, errorStatus);
|
||||
}
|
||||
@@ -720,6 +700,10 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done:
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deleteTestConfig() {
|
||||
return del("test.config");
|
||||
}
|
||||
}
|
||||
|
||||
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"], (done) => {
|
||||
@@ -836,7 +820,7 @@ function cleanTestDirs(done: (e?: any) => void) {
|
||||
|
||||
// used to pass data from jake command line directly to run.js
|
||||
function writeTestConfigFile(tests: string, light: boolean, taskConfigsFolder?: string, workerCount?: number, stackTraceLimit?: string) {
|
||||
const testConfigContents = JSON.stringify({ test: tests ? [tests] : undefined, light, workerCount, stackTraceLimit, taskConfigsFolder });
|
||||
const testConfigContents = JSON.stringify({ test: tests ? [tests] : undefined, light, workerCount, stackTraceLimit, taskConfigsFolder, noColor: !cmdLineOptions["colors"] });
|
||||
console.log("Running tests with config: " + testConfigContents);
|
||||
fs.writeFileSync("test.config", testConfigContents);
|
||||
}
|
||||
@@ -1066,10 +1050,11 @@ gulp.task("lint", "Runs tslint on the compiler sources. Optional arguments are:
|
||||
const fileMatcher = cmdLineOptions["files"];
|
||||
const files = fileMatcher
|
||||
? `src/**/${fileMatcher}`
|
||||
: "Gulpfile.ts 'scripts/tslint/*.ts' 'src/**/*.ts' --exclude src/lib/es5.d.ts --exclude 'src/lib/*.generated.d.ts'";
|
||||
const cmd = `node node_modules/tslint/bin/tslint ${files} --format stylish`;
|
||||
: "Gulpfile.ts 'scripts/tslint/**/*.ts' 'src/**/*.ts' --exclude src/lib/es5.d.ts --exclude 'src/lib/*.generated.d.ts'";
|
||||
const cmd = `node node_modules/tslint/bin/tslint ${files} --formatters-dir ./built/local/tslint/formatters --format autolinkableStylish`;
|
||||
console.log("Linting: " + cmd);
|
||||
child_process.execSync(cmd, { stdio: [0, 1, 2] });
|
||||
if (fold.isTravis()) console.log(fold.end("lint"));
|
||||
});
|
||||
|
||||
gulp.task("default", "Runs 'local'", ["local"]);
|
||||
|
||||
+44
-28
@@ -1,11 +1,11 @@
|
||||
// This file contains the build logic for the public repo
|
||||
// @ts-check
|
||||
|
||||
var fs = require("fs");
|
||||
var os = require("os");
|
||||
var path = require("path");
|
||||
var child_process = require("child_process");
|
||||
var fold = require("travis-fold");
|
||||
var runTestsInParallel = require("./scripts/mocha-parallel").runTestsInParallel;
|
||||
var ts = require("./lib/typescript");
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ else if (process.env.PATH !== undefined) {
|
||||
|
||||
function filesFromConfig(configPath) {
|
||||
var configText = fs.readFileSync(configPath).toString();
|
||||
var config = ts.parseConfigFileTextToJson(configPath, configText, /*stripComments*/ true);
|
||||
var config = ts.parseConfigFileTextToJson(configPath, configText);
|
||||
if (config.error) {
|
||||
throw new Error(diagnosticsToString([config.error]));
|
||||
}
|
||||
@@ -105,6 +105,9 @@ var harnessCoreSources = [
|
||||
"loggedIO.ts",
|
||||
"rwcRunner.ts",
|
||||
"test262Runner.ts",
|
||||
"./parallel/shared.ts",
|
||||
"./parallel/host.ts",
|
||||
"./parallel/worker.ts",
|
||||
"runner.ts"
|
||||
].map(function (f) {
|
||||
return path.join(harnessDirectory, f);
|
||||
@@ -596,7 +599,7 @@ file(typesMapOutputPath, function() {
|
||||
var content = fs.readFileSync(path.join(serverDirectory, 'typesMap.json'));
|
||||
// Validate that it's valid JSON
|
||||
try {
|
||||
JSON.parse(content);
|
||||
JSON.parse(content.toString());
|
||||
} catch (e) {
|
||||
console.log("Parse error in typesMap.json: " + e);
|
||||
}
|
||||
@@ -740,7 +743,7 @@ desc("Builds the test infrastructure using the built compiler");
|
||||
task("tests", ["local", run].concat(libraryTargets));
|
||||
|
||||
function exec(cmd, completeHandler, errorHandler) {
|
||||
var ex = jake.createExec([cmd], { windowsVerbatimArguments: true });
|
||||
var ex = jake.createExec([cmd], { windowsVerbatimArguments: true, interactive: true });
|
||||
// Add listeners for output and error
|
||||
ex.addListener("stdout", function (output) {
|
||||
process.stdout.write(output);
|
||||
@@ -766,15 +769,16 @@ function exec(cmd, completeHandler, errorHandler) {
|
||||
ex.run();
|
||||
}
|
||||
|
||||
const del = require("del");
|
||||
function cleanTestDirs() {
|
||||
// Clean the local baselines directory
|
||||
if (fs.existsSync(localBaseline)) {
|
||||
jake.rmRf(localBaseline);
|
||||
del.sync(localBaseline);
|
||||
}
|
||||
|
||||
// Clean the local Rwc baselines directory
|
||||
if (fs.existsSync(localRwcBaseline)) {
|
||||
jake.rmRf(localRwcBaseline);
|
||||
del.sync(localRwcBaseline);
|
||||
}
|
||||
|
||||
jake.mkdirP(localRwcBaseline);
|
||||
@@ -783,13 +787,14 @@ function cleanTestDirs() {
|
||||
}
|
||||
|
||||
// used to pass data from jake command line directly to run.js
|
||||
function writeTestConfigFile(tests, light, taskConfigsFolder, workerCount, stackTraceLimit) {
|
||||
function writeTestConfigFile(tests, light, taskConfigsFolder, workerCount, stackTraceLimit, colors) {
|
||||
var testConfigContents = JSON.stringify({
|
||||
test: tests ? [tests] : undefined,
|
||||
light: light,
|
||||
workerCount: workerCount,
|
||||
taskConfigsFolder: taskConfigsFolder,
|
||||
stackTraceLimit: stackTraceLimit
|
||||
stackTraceLimit: stackTraceLimit,
|
||||
noColor: !colors
|
||||
});
|
||||
fs.writeFileSync('test.config', testConfigContents);
|
||||
}
|
||||
@@ -831,7 +836,7 @@ function runConsoleTests(defaultReporter, runInParallel) {
|
||||
}
|
||||
|
||||
if (tests || light || taskConfigsFolder) {
|
||||
writeTestConfigFile(tests, light, taskConfigsFolder, workerCount, stackTraceLimit);
|
||||
writeTestConfigFile(tests, light, taskConfigsFolder, workerCount, stackTraceLimit, colors);
|
||||
}
|
||||
|
||||
if (tests && tests.toLocaleLowerCase() === "rwc") {
|
||||
@@ -894,19 +899,15 @@ function runConsoleTests(defaultReporter, runInParallel) {
|
||||
var savedNodeEnv = process.env.NODE_ENV;
|
||||
process.env.NODE_ENV = "development";
|
||||
var startTime = mark();
|
||||
runTestsInParallel(taskConfigsFolder, run, { testTimeout: testTimeout, noColors: !colors }, function (err) {
|
||||
exec(host + " " + run, function () {
|
||||
process.env.NODE_ENV = savedNodeEnv;
|
||||
measure(startTime);
|
||||
// last worker clean everything and runs linter in case if there were no errors
|
||||
deleteTemporaryProjectOutput();
|
||||
jake.rmRf(taskConfigsFolder);
|
||||
if (err) {
|
||||
fail(err);
|
||||
}
|
||||
else {
|
||||
runLinter();
|
||||
complete();
|
||||
}
|
||||
runLinter();
|
||||
finish();
|
||||
}, function (e, status) {
|
||||
process.env.NODE_ENV = savedNodeEnv;
|
||||
measure(startTime);
|
||||
finish(status);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -969,8 +970,8 @@ desc("Runs the tests using the built run.js file like 'jake runtests'. Syntax is
|
||||
task("runtests-browser", ["browserify", nodeServerOutFile], function () {
|
||||
cleanTestDirs();
|
||||
host = "node";
|
||||
browser = process.env.browser || process.env.b || (os.platform() === "linux" ? "chrome" : "IE");
|
||||
tests = process.env.test || process.env.tests || process.env.t;
|
||||
var browser = process.env.browser || process.env.b || (os.platform() === "linux" ? "chrome" : "IE");
|
||||
var tests = process.env.test || process.env.tests || process.env.t;
|
||||
var light = process.env.light || false;
|
||||
var testConfigFile = 'test.config';
|
||||
if (fs.existsSync(testConfigFile)) {
|
||||
@@ -1042,6 +1043,7 @@ function acceptBaseline(sourceFolder, targetFolder) {
|
||||
if (fs.existsSync(target)) {
|
||||
fs.unlinkSync(target);
|
||||
}
|
||||
jake.mkdirP(path.dirname(target));
|
||||
fs.renameSync(path.join(sourceFolder, filename), target);
|
||||
}
|
||||
}
|
||||
@@ -1119,7 +1121,7 @@ task("update-sublime", ["local", serverFile], function () {
|
||||
jake.cpR(serverFile + ".map", "../TypeScript-Sublime-Plugin/tsserver/");
|
||||
});
|
||||
|
||||
var tslintRuleDir = "scripts/tslint";
|
||||
var tslintRuleDir = "scripts/tslint/rules";
|
||||
var tslintRules = [
|
||||
"booleanTriviaRule",
|
||||
"debugAssertRule",
|
||||
@@ -1135,13 +1137,27 @@ var tslintRulesFiles = tslintRules.map(function (p) {
|
||||
return path.join(tslintRuleDir, p + ".ts");
|
||||
});
|
||||
var tslintRulesOutFiles = tslintRules.map(function (p) {
|
||||
return path.join(builtLocalDirectory, "tslint", p + ".js");
|
||||
return path.join(builtLocalDirectory, "tslint/rules", p + ".js");
|
||||
});
|
||||
var tslintFormattersDir = "scripts/tslint/formatters";
|
||||
var tslintFormatters = [
|
||||
"autolinkableStylishFormatter",
|
||||
];
|
||||
var tslintFormatterFiles = tslintFormatters.map(function (p) {
|
||||
return path.join(tslintFormattersDir, p + ".ts");
|
||||
});
|
||||
var tslintFormattersOutFiles = tslintFormatters.map(function (p) {
|
||||
return path.join(builtLocalDirectory, "tslint/formatters", p + ".js");
|
||||
});
|
||||
desc("Compiles tslint rules to js");
|
||||
task("build-rules", ["build-rules-start"].concat(tslintRulesOutFiles).concat(["build-rules-end"]));
|
||||
task("build-rules", ["build-rules-start"].concat(tslintRulesOutFiles).concat(tslintFormattersOutFiles).concat(["build-rules-end"]));
|
||||
tslintRulesFiles.forEach(function (ruleFile, i) {
|
||||
compileFile(tslintRulesOutFiles[i], [ruleFile], [ruleFile], [], /*useBuiltCompiler*/ false,
|
||||
{ noOutFile: true, generateDeclarations: false, outDir: path.join(builtLocalDirectory, "tslint"), lib: "es6" });
|
||||
{ noOutFile: true, generateDeclarations: false, outDir: path.join(builtLocalDirectory, "tslint/rules"), lib: "es6" });
|
||||
});
|
||||
tslintFormatterFiles.forEach(function (ruleFile, i) {
|
||||
compileFile(tslintFormattersOutFiles[i], [ruleFile], [ruleFile], [], /*useBuiltCompiler*/ false,
|
||||
{ noOutFile: true, generateDeclarations: false, outDir: path.join(builtLocalDirectory, "tslint/formatters"), lib: "es6" });
|
||||
});
|
||||
|
||||
desc("Emit the start of the build-rules fold");
|
||||
@@ -1209,8 +1225,8 @@ task("lint", ["build-rules"], () => {
|
||||
const fileMatcher = process.env.f || process.env.file || process.env.files;
|
||||
const files = fileMatcher
|
||||
? `src/**/${fileMatcher}`
|
||||
: "Gulpfile.ts 'scripts/tslint/*.ts' 'src/**/*.ts' --exclude src/lib/es5.d.ts --exclude 'src/lib/*.generated.d.ts'";
|
||||
const cmd = `node node_modules/tslint/bin/tslint ${files} --format stylish`;
|
||||
: "Gulpfile.ts 'scripts/tslint/**/*.ts' 'src/**/*.ts' --exclude src/lib/es5.d.ts --exclude 'src/lib/*.generated.d.ts'";
|
||||
const cmd = `node node_modules/tslint/bin/tslint ${files} --formatters-dir ./built/local/tslint/formatters --format autolinkableStylish`;
|
||||
console.log("Linting: " + cmd);
|
||||
jake.exec([cmd], { interactive: true }, () => {
|
||||
if (fold.isTravis()) console.log(fold.end("lint"));
|
||||
|
||||
+3
-1
@@ -31,6 +31,7 @@
|
||||
"devDependencies": {
|
||||
"@types/browserify": "latest",
|
||||
"@types/chai": "latest",
|
||||
"@types/colors": "latest",
|
||||
"@types/convert-source-map": "latest",
|
||||
"@types/del": "latest",
|
||||
"@types/glob": "latest",
|
||||
@@ -48,8 +49,8 @@
|
||||
"@types/q": "latest",
|
||||
"@types/run-sequence": "latest",
|
||||
"@types/through2": "latest",
|
||||
"browserify": "latest",
|
||||
"browser-resolve": "^1.11.2",
|
||||
"browserify": "latest",
|
||||
"chai": "latest",
|
||||
"convert-source-map": "latest",
|
||||
"del": "latest",
|
||||
@@ -75,6 +76,7 @@
|
||||
"travis-fold": "latest",
|
||||
"ts-node": "latest",
|
||||
"tslint": "latest",
|
||||
"colors": "latest",
|
||||
"typescript": "next"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Base = require('mocha').reporters.Base;
|
||||
|
||||
/**
|
||||
* Expose `None`.
|
||||
*/
|
||||
|
||||
exports = module.exports = None;
|
||||
|
||||
/**
|
||||
* Initialize a new `None` test reporter.
|
||||
*
|
||||
* @api public
|
||||
* @param {Runner} runner
|
||||
*/
|
||||
function None(runner) {
|
||||
Base.call(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherit from `Base.prototype`.
|
||||
*/
|
||||
None.prototype.__proto__ = Base.prototype;
|
||||
@@ -1,405 +0,0 @@
|
||||
var tty = require("tty")
|
||||
, readline = require("readline")
|
||||
, fs = require("fs")
|
||||
, path = require("path")
|
||||
, child_process = require("child_process")
|
||||
, os = require("os")
|
||||
, mocha = require("mocha")
|
||||
, Base = mocha.reporters.Base
|
||||
, color = Base.color
|
||||
, cursor = Base.cursor
|
||||
, ms = require("mocha/lib/ms");
|
||||
|
||||
var isatty = tty.isatty(1) && tty.isatty(2);
|
||||
var tapRangePattern = /^(\d+)\.\.(\d+)(?:$|\r\n?|\n)/;
|
||||
var tapTestPattern = /^(not\sok|ok)\s+(\d+)\s+(?:-\s+)?(.*)$/;
|
||||
var tapCommentPattern = /^#(?: (tests|pass|fail) (\d+)$)?/;
|
||||
|
||||
exports.runTestsInParallel = runTestsInParallel;
|
||||
exports.ProgressBars = ProgressBars;
|
||||
|
||||
function runTestsInParallel(taskConfigsFolder, run, options, cb) {
|
||||
if (options === undefined) options = { };
|
||||
|
||||
return discoverTests(run, options, function (error) {
|
||||
if (error) {
|
||||
return cb(error);
|
||||
}
|
||||
|
||||
return runTests(taskConfigsFolder, run, options, cb);
|
||||
});
|
||||
}
|
||||
|
||||
function discoverTests(run, options, cb) {
|
||||
console.log("Discovering tests...");
|
||||
|
||||
var cmd = "mocha -R " + require.resolve("./mocha-none-reporter.js") + " " + run;
|
||||
var p = spawnProcess(cmd);
|
||||
p.on("exit", function (status) {
|
||||
if (status) {
|
||||
cb(new Error("Process exited with code " + status));
|
||||
}
|
||||
else {
|
||||
cb();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function runTests(taskConfigsFolder, run, options, cb) {
|
||||
var configFiles = fs.readdirSync(taskConfigsFolder);
|
||||
var numPartitions = configFiles.length;
|
||||
if (numPartitions <= 0) {
|
||||
cb();
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Running tests on " + numPartitions + " threads...");
|
||||
|
||||
var partitions = Array(numPartitions);
|
||||
var progressBars = new ProgressBars();
|
||||
progressBars.enable();
|
||||
|
||||
var counter = numPartitions;
|
||||
configFiles.forEach(runTestsInPartition);
|
||||
|
||||
function runTestsInPartition(file, index) {
|
||||
var partition = {
|
||||
file: path.join(taskConfigsFolder, file),
|
||||
tests: 0,
|
||||
passed: 0,
|
||||
failed: 0,
|
||||
completed: 0,
|
||||
current: undefined,
|
||||
start: undefined,
|
||||
end: undefined,
|
||||
catastrophicError: "",
|
||||
failures: []
|
||||
};
|
||||
partitions[index] = partition;
|
||||
|
||||
// Set up the progress bar.
|
||||
updateProgress(0);
|
||||
|
||||
// Start the background process.
|
||||
var cmd = "mocha -t " + (options.testTimeout || 20000) + " -R tap --no-colors " + run + " --config='" + partition.file + "'";
|
||||
var p = spawnProcess(cmd);
|
||||
var rl = readline.createInterface({
|
||||
input: p.stdout,
|
||||
terminal: false
|
||||
});
|
||||
|
||||
var rlError = readline.createInterface({
|
||||
input: p.stderr,
|
||||
terminal: false
|
||||
});
|
||||
|
||||
rl.on("line", onmessage);
|
||||
rlError.on("line", onErrorMessage);
|
||||
p.on("exit", onexit)
|
||||
|
||||
function onErrorMessage(line) {
|
||||
partition.catastrophicError += line + os.EOL;
|
||||
}
|
||||
|
||||
function onmessage(line) {
|
||||
if (partition.start === undefined) {
|
||||
partition.start = Date.now();
|
||||
}
|
||||
|
||||
var rangeMatch = tapRangePattern.exec(line);
|
||||
if (rangeMatch) {
|
||||
partition.tests = parseInt(rangeMatch[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
var testMatch = tapTestPattern.exec(line);
|
||||
if (testMatch) {
|
||||
var test = {
|
||||
result: testMatch[1],
|
||||
id: parseInt(testMatch[2]),
|
||||
name: testMatch[3],
|
||||
output: []
|
||||
};
|
||||
|
||||
partition.current = test;
|
||||
partition.completed++;
|
||||
|
||||
if (test.result === "ok") {
|
||||
partition.passed++;
|
||||
}
|
||||
else {
|
||||
partition.failed++;
|
||||
partition.failures.push(test);
|
||||
}
|
||||
|
||||
var progress = partition.completed / partition.tests;
|
||||
if (progress < 1) {
|
||||
updateProgress(progress);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var commentMatch = tapCommentPattern.exec(line);
|
||||
if (commentMatch) {
|
||||
switch (commentMatch[1]) {
|
||||
case "tests":
|
||||
partition.current = undefined;
|
||||
partition.tests = parseInt(commentMatch[2]);
|
||||
break;
|
||||
|
||||
case "pass":
|
||||
partition.passed = parseInt(commentMatch[2]);
|
||||
break;
|
||||
|
||||
case "fail":
|
||||
partition.failed = parseInt(commentMatch[2]);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (partition.current) {
|
||||
partition.current.output.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
function onexit(code) {
|
||||
if (partition.end === undefined) {
|
||||
partition.end = Date.now();
|
||||
}
|
||||
|
||||
partition.duration = partition.end - partition.start;
|
||||
var isPartitionFail = partition.failed || code !== 0;
|
||||
var summaryColor = isPartitionFail ? "fail" : "green";
|
||||
var summarySymbol = isPartitionFail ? Base.symbols.err : Base.symbols.ok;
|
||||
|
||||
var summaryTests = (isPartitionFail ? partition.passed + "/" + partition.tests : partition.passed) + " passing";
|
||||
var summaryDuration = "(" + ms(partition.duration) + ")";
|
||||
var savedUseColors = Base.useColors;
|
||||
Base.useColors = !options.noColors;
|
||||
|
||||
var summary = color(summaryColor, summarySymbol + " " + summaryTests) + " " + color("light", summaryDuration);
|
||||
Base.useColors = savedUseColors;
|
||||
|
||||
updateProgress(1, summary);
|
||||
|
||||
signal();
|
||||
}
|
||||
|
||||
function updateProgress(percentComplete, title) {
|
||||
var progressColor = "pending";
|
||||
if (partition.failed) {
|
||||
progressColor = "fail";
|
||||
}
|
||||
|
||||
progressBars.update(
|
||||
index,
|
||||
percentComplete,
|
||||
progressColor,
|
||||
title
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function signal() {
|
||||
counter--;
|
||||
|
||||
if (counter <= 0) {
|
||||
var reporter = new Base(),
|
||||
stats = reporter.stats,
|
||||
failures = reporter.failures;
|
||||
|
||||
var duration = 0;
|
||||
var catastrophicError = "";
|
||||
for (var i = 0; i < numPartitions; i++) {
|
||||
var partition = partitions[i];
|
||||
stats.passes += partition.passed;
|
||||
stats.failures += partition.failed;
|
||||
stats.tests += partition.tests;
|
||||
duration += partition.duration;
|
||||
if (partition.catastrophicError !== "") {
|
||||
// Partition is written out to a temporary file as a JSON object.
|
||||
// Below is an example of how the partition JSON object looks like
|
||||
// {
|
||||
// "light":false,
|
||||
// "tasks":[
|
||||
// {
|
||||
// "runner":"compiler",
|
||||
// "files":["tests/cases/compiler/es6ImportNamedImportParsingError.ts"]
|
||||
// }
|
||||
// ],
|
||||
// "runUnitTests":false
|
||||
// }
|
||||
var jsonText = fs.readFileSync(partition.file);
|
||||
var configObj = JSON.parse(jsonText);
|
||||
if (configObj.tasks && configObj.tasks[0]) {
|
||||
catastrophicError += "Error from one or more of these files: " + configObj.tasks[0].files + os.EOL;
|
||||
catastrophicError += partition.catastrophicError;
|
||||
catastrophicError += os.EOL;
|
||||
}
|
||||
}
|
||||
for (var j = 0; j < partition.failures.length; j++) {
|
||||
var failure = partition.failures[j];
|
||||
failures.push(makeMochaTest(failure));
|
||||
}
|
||||
}
|
||||
|
||||
stats.duration = duration;
|
||||
progressBars.disable();
|
||||
|
||||
if (options.noColors) {
|
||||
var savedUseColors = Base.useColors;
|
||||
Base.useColors = false;
|
||||
reporter.epilogue();
|
||||
Base.useColors = savedUseColors;
|
||||
}
|
||||
else {
|
||||
reporter.epilogue();
|
||||
}
|
||||
|
||||
if (catastrophicError !== "") {
|
||||
return cb(new Error(catastrophicError));
|
||||
}
|
||||
if (stats.failures) {
|
||||
return cb(new Error("Test failures reported: " + stats.failures));
|
||||
}
|
||||
else {
|
||||
return cb();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function makeMochaTest(test) {
|
||||
return {
|
||||
fullTitle: function() {
|
||||
return test.name;
|
||||
},
|
||||
err: {
|
||||
message: test.output[0],
|
||||
stack: test.output.join(os.EOL)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var nodeModulesPathPrefix = path.resolve("./node_modules/.bin/") + path.delimiter;
|
||||
if (process.env.path !== undefined) {
|
||||
process.env.path = nodeModulesPathPrefix + process.env.path;
|
||||
} else if (process.env.PATH !== undefined) {
|
||||
process.env.PATH = nodeModulesPathPrefix + process.env.PATH;
|
||||
}
|
||||
|
||||
function spawnProcess(cmd, options) {
|
||||
var shell = process.platform === "win32" ? "cmd" : "/bin/sh";
|
||||
var prefix = process.platform === "win32" ? "/c" : "-c";
|
||||
return child_process.spawn(shell, [prefix, cmd], { windowsVerbatimArguments: true });
|
||||
}
|
||||
|
||||
function ProgressBars(options) {
|
||||
if (!options) options = {};
|
||||
var open = options.open || '[';
|
||||
var close = options.close || ']';
|
||||
var complete = options.complete || '▬';
|
||||
var incomplete = options.incomplete || Base.symbols.dot;
|
||||
var maxWidth = Math.floor(Base.window.width * .30) - open.length - close.length - 2;
|
||||
var width = minMax(options.width || maxWidth, 10, maxWidth);
|
||||
this._options = {
|
||||
open: open,
|
||||
complete: complete,
|
||||
incomplete: incomplete,
|
||||
close: close,
|
||||
width: width
|
||||
};
|
||||
|
||||
this._progressBars = [];
|
||||
this._lineCount = 0;
|
||||
this._enabled = false;
|
||||
}
|
||||
ProgressBars.prototype = {
|
||||
enable: function () {
|
||||
if (!this._enabled) {
|
||||
process.stdout.write(os.EOL);
|
||||
this._enabled = true;
|
||||
}
|
||||
},
|
||||
disable: function () {
|
||||
if (this._enabled) {
|
||||
process.stdout.write(os.EOL);
|
||||
this._enabled = false;
|
||||
}
|
||||
},
|
||||
update: function (index, percentComplete, color, title) {
|
||||
percentComplete = minMax(percentComplete, 0, 1);
|
||||
|
||||
var progressBar = this._progressBars[index] || (this._progressBars[index] = { });
|
||||
var width = this._options.width;
|
||||
var n = Math.floor(width * percentComplete);
|
||||
var i = width - n;
|
||||
if (n === progressBar.lastN && title === progressBar.title && color === progressBar.progressColor) {
|
||||
return;
|
||||
}
|
||||
|
||||
progressBar.lastN = n;
|
||||
progressBar.title = title;
|
||||
progressBar.progressColor = color;
|
||||
|
||||
var progress = " ";
|
||||
progress += this._color('progress', this._options.open);
|
||||
progress += this._color(color, fill(this._options.complete, n));
|
||||
progress += this._color('progress', fill(this._options.incomplete, i));
|
||||
progress += this._color('progress', this._options.close);
|
||||
|
||||
if (title) {
|
||||
progress += this._color('progress', ' ' + title);
|
||||
}
|
||||
|
||||
if (progressBar.text !== progress) {
|
||||
progressBar.text = progress;
|
||||
this._render(index);
|
||||
}
|
||||
},
|
||||
_render: function (index) {
|
||||
if (!this._enabled || !isatty) {
|
||||
return;
|
||||
}
|
||||
|
||||
cursor.hide();
|
||||
readline.moveCursor(process.stdout, -process.stdout.columns, -this._lineCount);
|
||||
var lineCount = 0;
|
||||
var numProgressBars = this._progressBars.length;
|
||||
for (var i = 0; i < numProgressBars; i++) {
|
||||
if (i === index) {
|
||||
readline.clearLine(process.stdout, 1);
|
||||
process.stdout.write(this._progressBars[i].text + os.EOL);
|
||||
}
|
||||
else {
|
||||
readline.moveCursor(process.stdout, -process.stdout.columns, +1);
|
||||
}
|
||||
|
||||
lineCount++;
|
||||
}
|
||||
|
||||
this._lineCount = lineCount;
|
||||
cursor.show();
|
||||
},
|
||||
_color: function (type, text) {
|
||||
return type && !this._options.noColors ? color(type, text) : text;
|
||||
}
|
||||
};
|
||||
|
||||
function fill(ch, size) {
|
||||
var s = "";
|
||||
while (s.length < size) {
|
||||
s += ch;
|
||||
}
|
||||
|
||||
return s.length > size ? s.substr(0, size) : s;
|
||||
}
|
||||
|
||||
function minMax(value, min, max) {
|
||||
if (value < min) return min;
|
||||
if (value > max) return max;
|
||||
return value;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import * as Lint from "tslint";
|
||||
import * as colors from "colors";
|
||||
import { sep } from "path";
|
||||
function groupBy<T>(array: ReadonlyArray<T> | undefined, getGroupId: (elem: T, index: number) => number | string): T[][] {
|
||||
if (!array) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const groupIdToGroup: { [index: string]: T[] } = {};
|
||||
let result: T[][] | undefined; // Compacted array for return value
|
||||
for (let index = 0; index < array.length; index++) {
|
||||
const value = array[index];
|
||||
const key = getGroupId(value, index);
|
||||
if (groupIdToGroup[key]) {
|
||||
groupIdToGroup[key].push(value);
|
||||
}
|
||||
else {
|
||||
const newGroup = [value];
|
||||
groupIdToGroup[key] = newGroup;
|
||||
if (!result) {
|
||||
result = [newGroup];
|
||||
}
|
||||
else {
|
||||
result.push(newGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result || [];
|
||||
}
|
||||
|
||||
function max<T>(array: ReadonlyArray<T> | undefined, selector: (elem: T) => number): number {
|
||||
if (!array) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let max = 0;
|
||||
for (const item of array) {
|
||||
const scalar = selector(item);
|
||||
if (scalar > max) {
|
||||
max = scalar;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
function getLink(failure: Lint.RuleFailure, color: boolean): string {
|
||||
const lineAndCharacter = failure.getStartPosition().getLineAndCharacter();
|
||||
const sev = failure.getRuleSeverity().toUpperCase();
|
||||
let path = failure.getFileName();
|
||||
// Most autolinks only become clickable if they contain a slash in some way; so we make a top level file into a relative path here
|
||||
if (path.indexOf("/") === -1 && path.indexOf("\\") === -1) {
|
||||
path = `.${sep}${path}`;
|
||||
}
|
||||
return `${color ? (sev === "WARNING" ? colors.blue(sev) : colors.red(sev)) : sev}: ${path}:${lineAndCharacter.line + 1}:${lineAndCharacter.character + 1}`;
|
||||
}
|
||||
|
||||
function getLinkMaxSize(failures: Lint.RuleFailure[]): number {
|
||||
return max(failures, f => getLink(f, /*color*/ false).length);
|
||||
}
|
||||
|
||||
function getNameMaxSize(failures: Lint.RuleFailure[]): number {
|
||||
return max(failures, f => f.getRuleName().length);
|
||||
}
|
||||
|
||||
function pad(str: string, visiblelen: number, len: number) {
|
||||
if (visiblelen >= len) return str;
|
||||
const count = len - visiblelen;
|
||||
for (let i = 0; i < count; i++) {
|
||||
str += " ";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
export class Formatter extends Lint.Formatters.AbstractFormatter {
|
||||
public static metadata: Lint.IFormatterMetadata = {
|
||||
formatterName: "autolinkableStylish",
|
||||
description: "Human-readable formatter which creates stylish messages with autolinkable filepaths.",
|
||||
descriptionDetails: Lint.Utils.dedent`
|
||||
Colorized output grouped by file, with autolinkable filepaths containing line and column information
|
||||
`,
|
||||
sample: Lint.Utils.dedent`
|
||||
src/myFile.ts
|
||||
ERROR: src/myFile.ts:1:14 semicolon Missing semicolon`,
|
||||
consumer: "human"
|
||||
};
|
||||
public format(failures: Lint.RuleFailure[]): string {
|
||||
return groupBy(failures, f => f.getFileName()).map(group => {
|
||||
const currentFile = group[0].getFileName();
|
||||
const linkMaxSize = getLinkMaxSize(group);
|
||||
const nameMaxSize = getNameMaxSize(group);
|
||||
return `
|
||||
${currentFile}
|
||||
${group.map(f => `${pad(getLink(f, /*color*/ true), getLink(f, /*color*/ false).length, linkMaxSize)} ${colors.grey(pad(f.getRuleName(), f.getRuleName().length, nameMaxSize))} ${colors.yellow(f.getFailure())}`).join("\n")}`;
|
||||
}).join("\n");
|
||||
}
|
||||
}
|
||||
@@ -1456,11 +1456,6 @@ namespace ts {
|
||||
}
|
||||
|
||||
function declareSymbolAndAddToSymbolTable(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol {
|
||||
// Just call this directly so that the return type of this function stays "void".
|
||||
return declareSymbolAndAddToSymbolTableWorker(node, symbolFlags, symbolExcludes);
|
||||
}
|
||||
|
||||
function declareSymbolAndAddToSymbolTableWorker(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol {
|
||||
switch (container.kind) {
|
||||
// Modules, source files, and classes need specialized handling for how their
|
||||
// members are declared (for example, a member of a class will go into a specific
|
||||
@@ -1683,6 +1678,9 @@ namespace ts {
|
||||
|
||||
function bindAnonymousDeclaration(node: Declaration, symbolFlags: SymbolFlags, name: __String) {
|
||||
const symbol = createSymbol(symbolFlags, name);
|
||||
if (symbolFlags & SymbolFlags.EnumMember) {
|
||||
symbol.parent = container.symbol;
|
||||
}
|
||||
addDeclarationToSymbol(symbol, node, symbolFlags);
|
||||
}
|
||||
|
||||
|
||||
+183
-124
@@ -225,7 +225,8 @@ namespace ts {
|
||||
return tryFindAmbientModule(moduleName, /*withAugmentations*/ false);
|
||||
},
|
||||
getApparentType,
|
||||
getAllPossiblePropertiesOfType,
|
||||
isArrayLikeType,
|
||||
getAllPossiblePropertiesOfTypes,
|
||||
getSuggestionForNonexistentProperty: (node, type) => unescapeLeadingUnderscores(getSuggestionForNonexistentProperty(node, type)),
|
||||
getSuggestionForNonexistentSymbol: (location, name, meaning) => unescapeLeadingUnderscores(getSuggestionForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning)),
|
||||
getBaseConstraintOfType,
|
||||
@@ -577,7 +578,7 @@ namespace ts {
|
||||
|
||||
function cloneSymbol(symbol: Symbol): Symbol {
|
||||
const result = createSymbol(symbol.flags, symbol.escapedName);
|
||||
result.declarations = symbol.declarations.slice(0);
|
||||
result.declarations = symbol.declarations ? symbol.declarations.slice() : [];
|
||||
result.parent = symbol.parent;
|
||||
if (symbol.valueDeclaration) result.valueDeclaration = symbol.valueDeclaration;
|
||||
if (symbol.constEnumOnlyModule) result.constEnumOnlyModule = true;
|
||||
@@ -1125,6 +1126,13 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
if (lastLocation) {
|
||||
Debug.assert(lastLocation.kind === SyntaxKind.SourceFile);
|
||||
if ((lastLocation as SourceFile).commonJsModuleIndicator && name === "exports") {
|
||||
return lastLocation.symbol;
|
||||
}
|
||||
}
|
||||
|
||||
result = lookup(globals, name, meaning);
|
||||
}
|
||||
|
||||
@@ -1751,13 +1759,13 @@ namespace ts {
|
||||
}
|
||||
|
||||
// May be an untyped module. If so, ignore resolutionDiagnostic.
|
||||
if (resolvedModule && resolvedModule.isExternalLibraryImport && !extensionIsTypeScript(resolvedModule.extension)) {
|
||||
if (resolvedModule && !extensionIsTypeScript(resolvedModule.extension) && resolutionDiagnostic === undefined || resolutionDiagnostic === Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type) {
|
||||
if (isForAugmentation) {
|
||||
const diag = Diagnostics.Invalid_module_name_in_augmentation_Module_0_resolves_to_an_untyped_module_at_1_which_cannot_be_augmented;
|
||||
error(errorNode, diag, moduleReference, resolvedModule.resolvedFileName);
|
||||
}
|
||||
else if (noImplicitAny && moduleNotFoundError) {
|
||||
let errorInfo = chainDiagnosticMessages(/*details*/ undefined,
|
||||
let errorInfo = !resolvedModule.isExternalLibraryImport ? undefined : chainDiagnosticMessages(/*details*/ undefined,
|
||||
Diagnostics.Try_npm_install_types_Slash_0_if_it_exists_or_add_a_new_declaration_d_ts_file_containing_declare_module_0,
|
||||
moduleReference);
|
||||
errorInfo = chainDiagnosticMessages(errorInfo,
|
||||
@@ -2417,15 +2425,6 @@ namespace ts {
|
||||
}
|
||||
};
|
||||
|
||||
interface NodeBuilderContext {
|
||||
enclosingDeclaration: Node | undefined;
|
||||
flags: NodeBuilderFlags | undefined;
|
||||
|
||||
// State
|
||||
encounteredError: boolean;
|
||||
symbolStack: Symbol[] | undefined;
|
||||
}
|
||||
|
||||
function createNodeBuilderContext(enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): NodeBuilderContext {
|
||||
return {
|
||||
enclosingDeclaration,
|
||||
@@ -3019,30 +3018,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getNameOfSymbol(symbol: Symbol, context: NodeBuilderContext): string {
|
||||
const declaration = firstOrUndefined(symbol.declarations);
|
||||
if (declaration) {
|
||||
const name = getNameOfDeclaration(declaration);
|
||||
if (name) {
|
||||
return declarationNameToString(name);
|
||||
}
|
||||
if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) {
|
||||
return declarationNameToString((<VariableDeclaration>declaration.parent).name);
|
||||
}
|
||||
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier)) {
|
||||
context.encounteredError = true;
|
||||
}
|
||||
switch (declaration.kind) {
|
||||
case SyntaxKind.ClassExpression:
|
||||
return "(Anonymous class)";
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
return "(Anonymous function)";
|
||||
}
|
||||
}
|
||||
return unescapeLeadingUnderscores(symbol.escapedName);
|
||||
}
|
||||
}
|
||||
|
||||
function typePredicateToString(typePredicate: TypePredicate, enclosingDeclaration?: Declaration, flags?: TypeFormatFlags): string {
|
||||
@@ -3107,7 +3082,16 @@ namespace ts {
|
||||
return type.flags & TypeFlags.StringLiteral ? '"' + escapeString((<StringLiteralType>type).value) + '"' : "" + (<NumberLiteralType>type).value;
|
||||
}
|
||||
|
||||
function getNameOfSymbol(symbol: Symbol): string {
|
||||
interface NodeBuilderContext {
|
||||
enclosingDeclaration: Node | undefined;
|
||||
flags: NodeBuilderFlags | undefined;
|
||||
|
||||
// State
|
||||
encounteredError: boolean;
|
||||
symbolStack: Symbol[] | undefined;
|
||||
}
|
||||
|
||||
function getNameOfSymbol(symbol: Symbol, context?: NodeBuilderContext): string {
|
||||
if (symbol.declarations && symbol.declarations.length) {
|
||||
const declaration = symbol.declarations[0];
|
||||
const name = getNameOfDeclaration(declaration);
|
||||
@@ -3117,6 +3101,9 @@ namespace ts {
|
||||
if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) {
|
||||
return declarationNameToString((<VariableDeclaration>declaration.parent).name);
|
||||
}
|
||||
if (context && !context.encounteredError && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier)) {
|
||||
context.encounteredError = true;
|
||||
}
|
||||
switch (declaration.kind) {
|
||||
case SyntaxKind.ClassExpression:
|
||||
return "(Anonymous class)";
|
||||
@@ -4908,7 +4895,7 @@ namespace ts {
|
||||
function getInstantiatedConstructorsForTypeArguments(type: Type, typeArgumentNodes: ReadonlyArray<TypeNode>, location: Node): Signature[] {
|
||||
const signatures = getConstructorsForTypeArguments(type, typeArgumentNodes, location);
|
||||
const typeArguments = map(typeArgumentNodes, getTypeFromTypeNode);
|
||||
return sameMap(signatures, sig => some(sig.typeParameters) ? getSignatureInstantiation(sig, typeArguments) : sig);
|
||||
return sameMap(signatures, sig => some(sig.typeParameters) ? getSignatureInstantiation(sig, typeArguments, isInJavaScriptFile(location)) : sig);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5003,7 +4990,7 @@ namespace ts {
|
||||
const valueDecl = type.symbol.valueDeclaration;
|
||||
if (valueDecl && isInJavaScriptFile(valueDecl)) {
|
||||
const augTag = getJSDocAugmentsTag(type.symbol.valueDeclaration);
|
||||
if (augTag) {
|
||||
if (augTag && augTag.typeExpression && augTag.typeExpression.type) {
|
||||
baseType = getTypeFromTypeNode(augTag.typeExpression.type);
|
||||
}
|
||||
}
|
||||
@@ -5137,7 +5124,9 @@ namespace ts {
|
||||
|
||||
const declaration = <JSDocTypedefTag | TypeAliasDeclaration>find(symbol.declarations, d =>
|
||||
d.kind === SyntaxKind.JSDocTypedefTag || d.kind === SyntaxKind.TypeAliasDeclaration);
|
||||
let type = getTypeFromTypeNode(declaration.kind === SyntaxKind.JSDocTypedefTag ? declaration.typeExpression : declaration.type);
|
||||
const typeNode = declaration.kind === SyntaxKind.JSDocTypedefTag ? declaration.typeExpression : declaration.type;
|
||||
// If typeNode is missing, we will error in checkJSDocTypedefTag.
|
||||
let type = typeNode ? getTypeFromTypeNode(typeNode) : unknownType;
|
||||
|
||||
if (popTypeResolution()) {
|
||||
const typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
|
||||
@@ -5504,7 +5493,7 @@ namespace ts {
|
||||
const minTypeArgumentCount = getMinTypeArgumentCount(baseSig.typeParameters);
|
||||
const typeParamCount = length(baseSig.typeParameters);
|
||||
if ((isJavaScript || typeArgCount >= minTypeArgumentCount) && typeArgCount <= typeParamCount) {
|
||||
const sig = typeParamCount ? createSignatureInstantiation(baseSig, fillMissingTypeArguments(typeArguments, baseSig.typeParameters, minTypeArgumentCount, baseTypeNode)) : cloneSignature(baseSig);
|
||||
const sig = typeParamCount ? createSignatureInstantiation(baseSig, fillMissingTypeArguments(typeArguments, baseSig.typeParameters, minTypeArgumentCount, isJavaScript)) : cloneSignature(baseSig);
|
||||
sig.typeParameters = classType.localTypeParameters;
|
||||
sig.resolvedReturnType = classType;
|
||||
result.push(sig);
|
||||
@@ -5918,25 +5907,21 @@ namespace ts {
|
||||
getPropertiesOfObjectType(type);
|
||||
}
|
||||
|
||||
function getAllPossiblePropertiesOfType(type: Type): Symbol[] {
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
const props = createSymbolTable();
|
||||
for (const memberType of (type as UnionType).types) {
|
||||
if (memberType.flags & TypeFlags.Primitive) {
|
||||
continue;
|
||||
}
|
||||
function getAllPossiblePropertiesOfTypes(types: Type[]): Symbol[] {
|
||||
const unionType = getUnionType(types);
|
||||
if (!(unionType.flags & TypeFlags.Union)) {
|
||||
return getPropertiesOfType(unionType);
|
||||
}
|
||||
|
||||
for (const { escapedName } of getPropertiesOfType(memberType)) {
|
||||
if (!props.has(escapedName)) {
|
||||
props.set(escapedName, createUnionOrIntersectionProperty(type as UnionType, escapedName));
|
||||
}
|
||||
const props = createSymbolTable();
|
||||
for (const memberType of types) {
|
||||
for (const { escapedName } of getPropertiesOfType(memberType)) {
|
||||
if (!props.has(escapedName)) {
|
||||
props.set(escapedName, createUnionOrIntersectionProperty(unionType as UnionType, escapedName));
|
||||
}
|
||||
}
|
||||
return arrayFrom(props.values());
|
||||
}
|
||||
else {
|
||||
return getPropertiesOfType(type);
|
||||
}
|
||||
return arrayFrom(props.values());
|
||||
}
|
||||
|
||||
function getConstraintOfType(type: TypeVariable | UnionOrIntersectionType): Type {
|
||||
@@ -6367,11 +6352,10 @@ namespace ts {
|
||||
* @param typeParameters The requested type parameters.
|
||||
* @param minTypeArgumentCount The minimum number of required type arguments.
|
||||
*/
|
||||
function fillMissingTypeArguments(typeArguments: Type[] | undefined, typeParameters: TypeParameter[] | undefined, minTypeArgumentCount: number, location?: Node) {
|
||||
function fillMissingTypeArguments(typeArguments: Type[] | undefined, typeParameters: TypeParameter[] | undefined, minTypeArgumentCount: number, isJavaScript: boolean) {
|
||||
const numTypeParameters = length(typeParameters);
|
||||
if (numTypeParameters) {
|
||||
const numTypeArguments = length(typeArguments);
|
||||
const isJavaScript = isInJavaScriptFile(location);
|
||||
if ((isJavaScript || numTypeArguments >= minTypeArgumentCount) && numTypeArguments <= numTypeParameters) {
|
||||
if (!typeArguments) {
|
||||
typeArguments = [];
|
||||
@@ -6629,8 +6613,8 @@ namespace ts {
|
||||
return anyType;
|
||||
}
|
||||
|
||||
function getSignatureInstantiation(signature: Signature, typeArguments: Type[]): Signature {
|
||||
typeArguments = fillMissingTypeArguments(typeArguments, signature.typeParameters, getMinTypeArgumentCount(signature.typeParameters));
|
||||
function getSignatureInstantiation(signature: Signature, typeArguments: Type[], isJavascript: boolean): Signature {
|
||||
typeArguments = fillMissingTypeArguments(typeArguments, signature.typeParameters, getMinTypeArgumentCount(signature.typeParameters), isJavascript);
|
||||
const instantiations = signature.instantiations || (signature.instantiations = createMap<Signature>());
|
||||
const id = getTypeListId(typeArguments);
|
||||
let instantiation = instantiations.get(id);
|
||||
@@ -6668,7 +6652,10 @@ namespace ts {
|
||||
// where different generations of the same type parameter are in scope). This leads to a lot of new type
|
||||
// identities, and potentially a lot of work comparing those identities, so here we create an instantiation
|
||||
// that uses the original type identities for all unconstrained type parameters.
|
||||
return getSignatureInstantiation(signature, map(signature.typeParameters, tp => tp.target && !getConstraintOfTypeParameter(tp.target) ? tp.target : tp));
|
||||
return getSignatureInstantiation(
|
||||
signature,
|
||||
map(signature.typeParameters, tp => tp.target && !getConstraintOfTypeParameter(tp.target) ? tp.target : tp),
|
||||
isInJavaScriptFile(signature.declaration));
|
||||
}
|
||||
|
||||
function getOrCreateTypeFromSignature(signature: Signature): ObjectType {
|
||||
@@ -6819,7 +6806,8 @@ namespace ts {
|
||||
if (typeParameters) {
|
||||
const numTypeArguments = length(node.typeArguments);
|
||||
const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters);
|
||||
if (!isInJavaScriptFile(node) && (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length)) {
|
||||
const isJavascript = isInJavaScriptFile(node);
|
||||
if (!isJavascript && (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length)) {
|
||||
error(node,
|
||||
minTypeArgumentCount === typeParameters.length
|
||||
? Diagnostics.Generic_type_0_requires_1_type_argument_s
|
||||
@@ -6832,7 +6820,7 @@ namespace ts {
|
||||
// In a type reference, the outer type parameters of the referenced class or interface are automatically
|
||||
// supplied as type arguments and the type reference only specifies arguments for the local type parameters
|
||||
// of the class or interface.
|
||||
const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgs, typeParameters, minTypeArgumentCount, node));
|
||||
const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgs, typeParameters, minTypeArgumentCount, isJavascript));
|
||||
return createTypeReference(<GenericType>type, typeArguments);
|
||||
}
|
||||
if (node.typeArguments) {
|
||||
@@ -6849,7 +6837,7 @@ namespace ts {
|
||||
const id = getTypeListId(typeArguments);
|
||||
let instantiation = links.instantiations.get(id);
|
||||
if (!instantiation) {
|
||||
links.instantiations.set(id, instantiation = instantiateType(type, createTypeMapper(typeParameters, fillMissingTypeArguments(typeArguments, typeParameters, getMinTypeArgumentCount(typeParameters)))));
|
||||
links.instantiations.set(id, instantiation = instantiateType(type, createTypeMapper(typeParameters, fillMissingTypeArguments(typeArguments, typeParameters, getMinTypeArgumentCount(typeParameters), isInJavaScriptFile(symbol.valueDeclaration)))));
|
||||
}
|
||||
return instantiation;
|
||||
}
|
||||
@@ -7298,6 +7286,22 @@ namespace ts {
|
||||
return binarySearchTypes(types, type) >= 0;
|
||||
}
|
||||
|
||||
// Return true if the given intersection type contains (a) more than one unit type or (b) an object
|
||||
// type and a nullable type (null or undefined).
|
||||
function isEmptyIntersectionType(type: IntersectionType) {
|
||||
let combined: TypeFlags = 0;
|
||||
for (const t of type.types) {
|
||||
if (t.flags & TypeFlags.Unit && combined & TypeFlags.Unit) {
|
||||
return true;
|
||||
}
|
||||
combined |= t.flags;
|
||||
if (combined & TypeFlags.Nullable && combined & (TypeFlags.Object | TypeFlags.NonPrimitive)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function addTypeToUnion(typeSet: TypeSet, type: Type) {
|
||||
const flags = type.flags;
|
||||
if (flags & TypeFlags.Union) {
|
||||
@@ -7311,7 +7315,11 @@ namespace ts {
|
||||
if (flags & TypeFlags.Null) typeSet.containsNull = true;
|
||||
if (!(flags & TypeFlags.ContainsWideningType)) typeSet.containsNonWideningType = true;
|
||||
}
|
||||
else if (!(flags & TypeFlags.Never)) {
|
||||
else if (!(flags & TypeFlags.Never || flags & TypeFlags.Intersection && isEmptyIntersectionType(<IntersectionType>type))) {
|
||||
// We ignore 'never' types in unions. Likewise, we ignore intersections of unit types as they are
|
||||
// another form of 'never' (in that they have an empty value domain). We could in theory turn
|
||||
// intersections of unit types into 'never' upon construction, but deferring the reduction makes it
|
||||
// easier to reason about their origin.
|
||||
if (flags & TypeFlags.String) typeSet.containsString = true;
|
||||
if (flags & TypeFlags.Number) typeSet.containsNumber = true;
|
||||
if (flags & TypeFlags.StringOrNumberLiteral) typeSet.containsStringOrNumberLiteral = true;
|
||||
@@ -7838,7 +7846,10 @@ namespace ts {
|
||||
return mapType(right, t => getSpreadType(left, t));
|
||||
}
|
||||
if (right.flags & TypeFlags.NonPrimitive) {
|
||||
return emptyObjectType;
|
||||
return nonPrimitiveType;
|
||||
}
|
||||
if (right.flags & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.StringLike | TypeFlags.EnumLike)) {
|
||||
return left;
|
||||
}
|
||||
|
||||
const members = createSymbolTable();
|
||||
@@ -7865,6 +7876,7 @@ namespace ts {
|
||||
members.set(rightProp.escapedName, getNonReadonlySymbol(rightProp));
|
||||
}
|
||||
}
|
||||
|
||||
for (const leftProp of getPropertiesOfType(left)) {
|
||||
if (leftProp.flags & SymbolFlags.SetAccessor && !(leftProp.flags & SymbolFlags.GetAccessor)
|
||||
|| skippedPrivateMembers.has(leftProp.escapedName)
|
||||
@@ -7976,7 +7988,7 @@ namespace ts {
|
||||
return unknownType;
|
||||
}
|
||||
|
||||
function getTypeFromThisTypeNode(node: TypeNode): Type {
|
||||
function getTypeFromThisTypeNode(node: ThisExpression | ThisTypeNode): Type {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
links.resolvedType = getThisType(node);
|
||||
@@ -8010,7 +8022,7 @@ namespace ts {
|
||||
return node.flags & NodeFlags.JavaScriptFile ? anyType : nonPrimitiveType;
|
||||
case SyntaxKind.ThisType:
|
||||
case SyntaxKind.ThisKeyword:
|
||||
return getTypeFromThisTypeNode(node);
|
||||
return getTypeFromThisTypeNode(node as ThisExpression | ThisTypeNode);
|
||||
case SyntaxKind.LiteralType:
|
||||
return getTypeFromLiteralTypeNode(<LiteralTypeNode>node);
|
||||
case SyntaxKind.TypeReference:
|
||||
@@ -10048,7 +10060,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isUnitType(type: Type): boolean {
|
||||
return (type.flags & (TypeFlags.Literal | TypeFlags.Undefined | TypeFlags.Null)) !== 0;
|
||||
return !!(type.flags & TypeFlags.Unit);
|
||||
}
|
||||
|
||||
function isLiteralType(type: Type): boolean {
|
||||
@@ -12865,7 +12877,8 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (noImplicitThis || isInJavaScriptFile(func)) {
|
||||
const inJs = isInJavaScriptFile(func);
|
||||
if (noImplicitThis || inJs) {
|
||||
const containingLiteral = getContainingObjectLiteral(func);
|
||||
if (containingLiteral) {
|
||||
// We have an object literal method. Check if the containing object literal has a contextual type
|
||||
@@ -12892,10 +12905,20 @@ namespace ts {
|
||||
}
|
||||
// In an assignment of the form 'obj.xxx = function(...)' or 'obj[xxx] = function(...)', the
|
||||
// contextual type for 'this' is 'obj'.
|
||||
if (func.parent.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>func.parent).operatorToken.kind === SyntaxKind.EqualsToken) {
|
||||
const target = (<BinaryExpression>func.parent).left;
|
||||
const { parent } = func;
|
||||
if (parent.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>parent).operatorToken.kind === SyntaxKind.EqualsToken) {
|
||||
const target = (<BinaryExpression>parent).left;
|
||||
if (target.kind === SyntaxKind.PropertyAccessExpression || target.kind === SyntaxKind.ElementAccessExpression) {
|
||||
return checkExpressionCached((<PropertyAccessExpression | ElementAccessExpression>target).expression);
|
||||
const { expression } = target as PropertyAccessExpression | ElementAccessExpression;
|
||||
// Don't contextually type `this` as `exports` in `exports.Point = function(x, y) { this.x = x; this.y = y; }`
|
||||
if (inJs && isIdentifier(expression)) {
|
||||
const sourceFile = getSourceFileOfNode(parent);
|
||||
if (sourceFile.commonJsModuleIndicator && getResolvedSymbol(expression) === sourceFile.symbol) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return checkExpressionCached(expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13156,16 +13179,11 @@ namespace ts {
|
||||
// the type of the property with the numeric name N in T, if one exists. Otherwise, if T has a numeric index signature,
|
||||
// it is the type of the numeric index signature in T. Otherwise, in ES6 and higher, the contextual type is the iterated
|
||||
// type of T.
|
||||
function getContextualTypeForElementExpression(node: Expression): Type {
|
||||
const arrayLiteral = <ArrayLiteralExpression>node.parent;
|
||||
const type = getApparentTypeOfContextualType(arrayLiteral);
|
||||
if (type) {
|
||||
const index = indexOf(arrayLiteral.elements, node);
|
||||
return getTypeOfPropertyOfContextualType(type, "" + index as __String)
|
||||
|| getIndexTypeOfContextualType(type, IndexKind.Number)
|
||||
|| getIteratedTypeOrElementType(type, /*errorNode*/ undefined, /*allowStringInput*/ false, /*allowAsyncIterables*/ false, /*checkAssignability*/ false);
|
||||
}
|
||||
return undefined;
|
||||
function getContextualTypeForElementExpression(arrayContextualType: Type | undefined, index: number): Type | undefined {
|
||||
return arrayContextualType && (
|
||||
getTypeOfPropertyOfContextualType(arrayContextualType, "" + index as __String)
|
||||
|| getIndexTypeOfContextualType(arrayContextualType, IndexKind.Number)
|
||||
|| getIteratedTypeOrElementType(arrayContextualType, /*errorNode*/ undefined, /*allowStringInput*/ false, /*allowAsyncIterables*/ false, /*checkAssignability*/ false));
|
||||
}
|
||||
|
||||
// In a contextually typed conditional expression, the true/false expressions are contextually typed by the same type.
|
||||
@@ -13279,15 +13297,21 @@ namespace ts {
|
||||
return getContextualTypeForObjectLiteralElement(<ObjectLiteralElementLike>parent);
|
||||
case SyntaxKind.SpreadAssignment:
|
||||
return getApparentTypeOfContextualType(parent.parent as ObjectLiteralExpression);
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
return getContextualTypeForElementExpression(node);
|
||||
case SyntaxKind.ArrayLiteralExpression: {
|
||||
const arrayLiteral = <ArrayLiteralExpression>parent;
|
||||
const type = getApparentTypeOfContextualType(arrayLiteral);
|
||||
return getContextualTypeForElementExpression(type, indexOfNode(arrayLiteral.elements, node));
|
||||
}
|
||||
case SyntaxKind.ConditionalExpression:
|
||||
return getContextualTypeForConditionalOperand(node);
|
||||
case SyntaxKind.TemplateSpan:
|
||||
Debug.assert(parent.parent.kind === SyntaxKind.TemplateExpression);
|
||||
return getContextualTypeForSubstitutionExpression(<TemplateExpression>parent.parent, node);
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
return getContextualType(<ParenthesizedExpression>parent);
|
||||
case SyntaxKind.ParenthesizedExpression: {
|
||||
// Like in `checkParenthesizedExpression`, an `/** @type {xyz} */` comment before a parenthesized expression acts as a type cast.
|
||||
const tag = isInJavaScriptFile(parent) ? getJSDocTypeTag(parent) : undefined;
|
||||
return tag ? getTypeFromTypeNode(tag.typeExpression.type) : getContextualType(<ParenthesizedExpression>parent);
|
||||
}
|
||||
case SyntaxKind.JsxExpression:
|
||||
return getContextualTypeForJsxExpression(<JsxExpression>parent);
|
||||
case SyntaxKind.JsxAttribute:
|
||||
@@ -13409,12 +13433,14 @@ namespace ts {
|
||||
(node.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>node).operatorToken.kind === SyntaxKind.EqualsToken);
|
||||
}
|
||||
|
||||
function checkArrayLiteral(node: ArrayLiteralExpression, checkMode?: CheckMode): Type {
|
||||
function checkArrayLiteral(node: ArrayLiteralExpression, checkMode: CheckMode | undefined): Type {
|
||||
const elements = node.elements;
|
||||
let hasSpreadElement = false;
|
||||
const elementTypes: Type[] = [];
|
||||
const inDestructuringPattern = isAssignmentTarget(node);
|
||||
for (const e of elements) {
|
||||
const contextualType = getApparentTypeOfContextualType(node);
|
||||
for (let index = 0; index < elements.length; index++) {
|
||||
const e = elements[index];
|
||||
if (inDestructuringPattern && e.kind === SyntaxKind.SpreadElement) {
|
||||
// Given the following situation:
|
||||
// var c: {};
|
||||
@@ -13436,7 +13462,8 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else {
|
||||
const type = checkExpressionForMutableLocation(e, checkMode);
|
||||
const elementContextualType = getContextualTypeForElementExpression(contextualType, index);
|
||||
const type = checkExpressionForMutableLocation(e, checkMode, elementContextualType);
|
||||
elementTypes.push(type);
|
||||
}
|
||||
hasSpreadElement = hasSpreadElement || e.kind === SyntaxKind.SpreadElement;
|
||||
@@ -13749,7 +13776,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isValidSpreadType(type: Type): boolean {
|
||||
return !!(type.flags & (TypeFlags.Any | TypeFlags.Null | TypeFlags.Undefined | TypeFlags.NonPrimitive) ||
|
||||
return !!(type.flags & (TypeFlags.Any | TypeFlags.NonPrimitive) ||
|
||||
getFalsyFlags(type) & TypeFlags.DefinitelyFalsy && isValidSpreadType(removeDefinitelyFalsyTypes(type)) ||
|
||||
type.flags & TypeFlags.Object && !isGenericMappedType(type) ||
|
||||
type.flags & TypeFlags.UnionOrIntersection && !forEach((<UnionOrIntersectionType>type).types, t => !isValidSpreadType(t)));
|
||||
}
|
||||
@@ -14014,8 +14042,9 @@ namespace ts {
|
||||
const instantiatedSignatures = [];
|
||||
for (const signature of signatures) {
|
||||
if (signature.typeParameters) {
|
||||
const typeArguments = fillMissingTypeArguments(/*typeArguments*/ undefined, signature.typeParameters, /*minTypeArgumentCount*/ 0);
|
||||
instantiatedSignatures.push(getSignatureInstantiation(signature, typeArguments));
|
||||
const isJavascript = isInJavaScriptFile(node);
|
||||
const typeArguments = fillMissingTypeArguments(/*typeArguments*/ undefined, signature.typeParameters, /*minTypeArgumentCount*/ 0, isJavascript);
|
||||
instantiatedSignatures.push(getSignatureInstantiation(signature, typeArguments, isJavascript));
|
||||
}
|
||||
else {
|
||||
instantiatedSignatures.push(signature);
|
||||
@@ -14753,7 +14782,7 @@ namespace ts {
|
||||
return;
|
||||
}
|
||||
|
||||
if (findAncestor(node, node => node.kind === SyntaxKind.PropertyDeclaration ? true : isExpression(node) ? false : "quit") &&
|
||||
if (isInPropertyInitializer(node) &&
|
||||
!isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right)
|
||||
&& !isPropertyDeclaredInAncestorClass(prop)) {
|
||||
error(right, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, unescapeLeadingUnderscores(right.escapedText));
|
||||
@@ -14766,6 +14795,20 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function isInPropertyInitializer(node: Node): boolean {
|
||||
return !!findAncestor(node, node => {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
return true;
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
// We might be in `a = { b: this.b }`, so keep looking. See `tests/cases/compiler/useBeforeDeclaration_propertyAssignment.ts`.
|
||||
return false;
|
||||
default:
|
||||
return isPartOfExpression(node) ? false : "quit";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* It's possible that "prop.valueDeclaration" is a local declaration, but the property was also declared in a superclass.
|
||||
* In that case we won't consider it used before its declaration, because it gets its value from the superclass' declaration.
|
||||
@@ -15271,7 +15314,7 @@ namespace ts {
|
||||
if (!contextualMapper) {
|
||||
inferTypes(context.inferences, getReturnTypeOfSignature(contextualSignature), getReturnTypeOfSignature(signature), InferencePriority.ReturnType);
|
||||
}
|
||||
return getSignatureInstantiation(signature, getInferredTypes(context));
|
||||
return getSignatureInstantiation(signature, getInferredTypes(context), isInJavaScriptFile(contextualSignature.declaration));
|
||||
}
|
||||
|
||||
function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: ReadonlyArray<Expression>, excludeArgument: boolean[], context: InferenceContext): Type[] {
|
||||
@@ -15306,7 +15349,7 @@ namespace ts {
|
||||
// Above, the type of the 'value' parameter is inferred to be 'A'.
|
||||
const contextualSignature = getSingleCallSignature(instantiatedType);
|
||||
const inferenceSourceType = contextualSignature && contextualSignature.typeParameters ?
|
||||
getOrCreateTypeFromSignature(getSignatureInstantiation(contextualSignature, contextualSignature.typeParameters)) :
|
||||
getOrCreateTypeFromSignature(getSignatureInstantiation(contextualSignature, contextualSignature.typeParameters, isInJavaScriptFile(node))) :
|
||||
instantiatedType;
|
||||
const inferenceTargetType = getReturnTypeOfSignature(signature);
|
||||
// Inferences made from return types have lower priority than all other inferences.
|
||||
@@ -16022,8 +16065,9 @@ namespace ts {
|
||||
candidate = originalCandidate;
|
||||
if (candidate.typeParameters) {
|
||||
let typeArgumentTypes: Type[];
|
||||
const isJavascript = isInJavaScriptFile(candidate.declaration);
|
||||
if (typeArguments) {
|
||||
typeArgumentTypes = fillMissingTypeArguments(map(typeArguments, getTypeFromTypeNode), candidate.typeParameters, getMinTypeArgumentCount(candidate.typeParameters));
|
||||
typeArgumentTypes = fillMissingTypeArguments(map(typeArguments, getTypeFromTypeNode), candidate.typeParameters, getMinTypeArgumentCount(candidate.typeParameters), isJavascript);
|
||||
if (!checkTypeArguments(candidate, typeArguments, typeArgumentTypes, /*reportErrors*/ false)) {
|
||||
candidateForTypeArgumentError = originalCandidate;
|
||||
break;
|
||||
@@ -16032,7 +16076,7 @@ namespace ts {
|
||||
else {
|
||||
typeArgumentTypes = inferTypeArguments(node, candidate, args, excludeArgument, inferenceContext);
|
||||
}
|
||||
candidate = getSignatureInstantiation(candidate, typeArgumentTypes);
|
||||
candidate = getSignatureInstantiation(candidate, typeArgumentTypes, isJavascript);
|
||||
}
|
||||
if (!checkApplicableSignature(node, args, candidate, relation, excludeArgument, /*reportErrors*/ false)) {
|
||||
candidateForArgumentError = candidate;
|
||||
@@ -16449,7 +16493,7 @@ namespace ts {
|
||||
|
||||
// If the symbol of the node has members, treat it like a constructor.
|
||||
const symbol = isFunctionDeclaration(node) || isFunctionExpression(node) ? getSymbolOfNode(node) :
|
||||
isVariableDeclaration(node) && isFunctionExpression(node.initializer) ? getSymbolOfNode(node.initializer) :
|
||||
isVariableDeclaration(node) && node.initializer && isFunctionExpression(node.initializer) ? getSymbolOfNode(node.initializer) :
|
||||
undefined;
|
||||
|
||||
return symbol && symbol.members !== undefined;
|
||||
@@ -17964,9 +18008,13 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function checkExpressionForMutableLocation(node: Expression, checkMode?: CheckMode): Type {
|
||||
function checkExpressionForMutableLocation(node: Expression, checkMode: CheckMode, contextualType?: Type): Type {
|
||||
if (arguments.length === 2) {
|
||||
contextualType = getContextualType(node);
|
||||
}
|
||||
const type = checkExpression(node, checkMode);
|
||||
return isTypeAssertion(node) || isLiteralContextualType(getContextualType(node)) ? type : getWidenedLiteralType(type);
|
||||
const shouldWiden = isTypeAssertion(node) || isLiteralContextualType(contextualType);
|
||||
return shouldWiden ? type : getWidenedLiteralType(type);
|
||||
}
|
||||
|
||||
function checkPropertyAssignment(node: PropertyAssignment, checkMode?: CheckMode): Type {
|
||||
@@ -18084,13 +18132,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkParenthesizedExpression(node: ParenthesizedExpression, checkMode?: CheckMode): Type {
|
||||
if (isInJavaScriptFile(node) && node.jsDoc) {
|
||||
const typecasts = flatMap(node.jsDoc, doc => filter(doc.tags, tag => tag.kind === SyntaxKind.JSDocTypeTag && !!(tag as JSDocTypeTag).typeExpression && !!(tag as JSDocTypeTag).typeExpression.type));
|
||||
if (typecasts && typecasts.length) {
|
||||
// We should have already issued an error if there were multiple type jsdocs
|
||||
const cast = typecasts[0] as JSDocTypeTag;
|
||||
return checkAssertionWorker(cast, cast.typeExpression.type, node.expression, checkMode);
|
||||
}
|
||||
const tag = isInJavaScriptFile(node) ? getJSDocTypeTag(node) : undefined;
|
||||
if (tag) {
|
||||
return checkAssertionWorker(tag, tag.typeExpression.type, node.expression, checkMode);
|
||||
}
|
||||
return checkExpression(node.expression, checkMode);
|
||||
}
|
||||
@@ -18796,7 +18840,7 @@ namespace ts {
|
||||
const constraint = getConstraintOfTypeParameter(typeParameters[i]);
|
||||
if (constraint) {
|
||||
if (!typeArguments) {
|
||||
typeArguments = fillMissingTypeArguments(map(typeArgumentNodes, getTypeFromTypeNode), typeParameters, minTypeArgumentCount);
|
||||
typeArguments = fillMissingTypeArguments(map(typeArgumentNodes, getTypeFromTypeNode), typeParameters, minTypeArgumentCount, isInJavaScriptFile(typeArgumentNodes[i]));
|
||||
mapper = createTypeMapper(typeParameters, typeArguments);
|
||||
}
|
||||
const typeArgument = typeArguments[i];
|
||||
@@ -19230,10 +19274,11 @@ namespace ts {
|
||||
: DeclarationSpaces.ExportNamespace;
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
// A NamespaceImport declares an Alias, which is allowed to merge with other values within the module
|
||||
case SyntaxKind.NamespaceImport:
|
||||
return DeclarationSpaces.ExportType | DeclarationSpaces.ExportValue;
|
||||
// The below options all declare an Alias, which is allowed to merge with other values within the importing module
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
case SyntaxKind.NamespaceImport:
|
||||
case SyntaxKind.ImportClause:
|
||||
let result = DeclarationSpaces.None;
|
||||
const target = resolveAlias(getSymbolOfNode(d));
|
||||
forEach(target.declarations, d => { result |= getDeclarationSpaces(d); });
|
||||
@@ -19737,11 +19782,11 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function checkJSDoc(node: FunctionDeclaration | MethodDeclaration) {
|
||||
if (!isInJavaScriptFile(node)) {
|
||||
return;
|
||||
function checkJSDocTypedefTag(node: JSDocTypedefTag) {
|
||||
if (!node.typeExpression) {
|
||||
// If the node had `@property` tags, `typeExpression` would have been set to the first property tag.
|
||||
error(node.name, Diagnostics.JSDoc_typedef_tag_should_either_have_a_type_annotation_or_be_followed_by_property_or_member_tags);
|
||||
}
|
||||
forEach(node.jsDoc, checkSourceElement);
|
||||
}
|
||||
|
||||
function checkJSDocComment(node: JSDoc) {
|
||||
@@ -19753,7 +19798,6 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkFunctionOrMethodDeclaration(node: FunctionDeclaration | MethodDeclaration): void {
|
||||
checkJSDoc(node);
|
||||
checkDecorators(node);
|
||||
checkSignatureDeclaration(node);
|
||||
const functionFlags = getFunctionFlags(node);
|
||||
@@ -19914,7 +19958,8 @@ namespace ts {
|
||||
const node = getNameOfDeclaration(declaration) || declaration;
|
||||
if (isIdentifierThatStartsWithUnderScore(node)) {
|
||||
const declaration = getRootDeclaration(node.parent);
|
||||
if (declaration.kind === SyntaxKind.VariableDeclaration && isForInOrOfStatement(declaration.parent.parent)) {
|
||||
if ((declaration.kind === SyntaxKind.VariableDeclaration && isForInOrOfStatement(declaration.parent.parent)) ||
|
||||
declaration.kind === SyntaxKind.TypeParameter) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -19964,7 +20009,7 @@ namespace ts {
|
||||
return;
|
||||
}
|
||||
for (const typeParameter of node.typeParameters) {
|
||||
if (!getMergedSymbol(typeParameter.symbol).isReferenced) {
|
||||
if (!getMergedSymbol(typeParameter.symbol).isReferenced && !isIdentifierThatStartsWithUnderScore(typeParameter.name)) {
|
||||
error(typeParameter.name, Diagnostics._0_is_declared_but_its_value_is_never_read, unescapeLeadingUnderscores(typeParameter.symbol.escapedName));
|
||||
}
|
||||
}
|
||||
@@ -22311,6 +22356,10 @@ namespace ts {
|
||||
|
||||
checkExternalModuleExports(container);
|
||||
|
||||
if (isInAmbientContext(node) && !isEntityNameExpression(node.expression)) {
|
||||
grammarErrorOnNode(node.expression, Diagnostics.The_expression_of_an_export_assignment_must_be_an_identifier_or_qualified_name_in_an_ambient_context);
|
||||
}
|
||||
|
||||
if (node.isExportEquals && !isInAmbientContext(node)) {
|
||||
if (modulekind >= ModuleKind.ES2015) {
|
||||
// export assignment is not supported in es6 modules
|
||||
@@ -22382,6 +22431,12 @@ namespace ts {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isInJavaScriptFile(node) && (node as JSDocContainer).jsDoc) {
|
||||
for (const jsdoc of (node as JSDocContainer).jsDoc) {
|
||||
checkJSDocComment(jsdoc);
|
||||
}
|
||||
}
|
||||
|
||||
const kind = node.kind;
|
||||
if (cancellationToken) {
|
||||
// Only bother checking on a few construct kinds. We don't want to be excessively
|
||||
@@ -22436,6 +22491,8 @@ namespace ts {
|
||||
case SyntaxKind.ParenthesizedType:
|
||||
case SyntaxKind.TypeOperator:
|
||||
return checkSourceElement((<ParenthesizedTypeNode | TypeOperatorNode>node).type);
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
return checkJSDocTypedefTag(node as JSDocTypedefTag);
|
||||
case SyntaxKind.JSDocComment:
|
||||
return checkJSDocComment(node as JSDoc);
|
||||
case SyntaxKind.JSDocParameterTag:
|
||||
@@ -23027,14 +23084,16 @@ namespace ts {
|
||||
return sig.thisParameter;
|
||||
}
|
||||
}
|
||||
if (isInExpressionContext(node)) {
|
||||
return checkExpression(node as Expression).symbol;
|
||||
}
|
||||
// falls through
|
||||
|
||||
case SyntaxKind.SuperKeyword:
|
||||
const type = isPartOfExpression(node) ? getTypeOfExpression(<Expression>node) : getTypeFromTypeNode(<TypeNode>node);
|
||||
return type.symbol;
|
||||
|
||||
case SyntaxKind.ThisType:
|
||||
return getTypeFromTypeNode(<TypeNode>node).symbol;
|
||||
return getTypeFromThisTypeNode(node as ThisExpression | ThisTypeNode).symbol;
|
||||
|
||||
case SyntaxKind.SuperKeyword:
|
||||
return checkExpression(node as Expression).symbol;
|
||||
|
||||
case SyntaxKind.ConstructorKeyword:
|
||||
// constructor keyword for an overload, should take us to the definition if it exist
|
||||
|
||||
+12
-6
@@ -1014,11 +1014,6 @@ namespace ts {
|
||||
|
||||
/**
|
||||
* Gets the owned, enumerable property keys of a map-like.
|
||||
*
|
||||
* NOTE: This is intended for use with MapLike<T> objects. For Map<T> objects, use
|
||||
* Object.keys instead as it offers better performance.
|
||||
*
|
||||
* @param map A map-like.
|
||||
*/
|
||||
export function getOwnKeys<T>(map: MapLike<T>): string[] {
|
||||
const keys: string[] = [];
|
||||
@@ -1031,6 +1026,17 @@ namespace ts {
|
||||
return keys;
|
||||
}
|
||||
|
||||
export function getOwnValues<T>(sparseArray: T[]): T[] {
|
||||
const values: T[] = [];
|
||||
for (const key in sparseArray) {
|
||||
if (hasOwnProperty.call(sparseArray, key)) {
|
||||
values.push(sparseArray[key]);
|
||||
}
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
/** Shims `Array.from`. */
|
||||
export function arrayFrom<T, U>(iterator: Iterator<T>, map: (t: T) => U): U[];
|
||||
export function arrayFrom<T>(iterator: Iterator<T>): T[];
|
||||
@@ -1692,7 +1698,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function isRootedDiskPath(path: string) {
|
||||
return getRootLength(path) !== 0;
|
||||
return path && getRootLength(path) !== 0;
|
||||
}
|
||||
|
||||
export function convertToRelativePath(absoluteOrRelativePath: string, basePath: string, getCanonicalFileName: (path: string) => string): string {
|
||||
|
||||
@@ -2212,6 +2212,10 @@
|
||||
"category": "Error",
|
||||
"code": 2713
|
||||
},
|
||||
"The expression of an export assignment must be an identifier or qualified name in an ambient context.": {
|
||||
"category": "Error",
|
||||
"code": 2714
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
@@ -2682,7 +2686,7 @@
|
||||
"category": "Message",
|
||||
"code": 6015
|
||||
},
|
||||
"Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.": {
|
||||
"Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.": {
|
||||
"category": "Message",
|
||||
"code": 6016
|
||||
},
|
||||
@@ -3138,10 +3142,6 @@
|
||||
"category": "Error",
|
||||
"code": 6142
|
||||
},
|
||||
"Module '{0}' was resolved to '{1}', but '--allowJs' is not set.": {
|
||||
"category": "Error",
|
||||
"code": 6143
|
||||
},
|
||||
"Module '{0}' was resolved as locally declared ambient module in file '{1}'.": {
|
||||
"category": "Message",
|
||||
"code": 6144
|
||||
@@ -3503,6 +3503,10 @@
|
||||
"category": "Error",
|
||||
"code": 8020
|
||||
},
|
||||
"JSDoc '@typedef' tag should either have a type annotation or be followed by '@property' or '@member' tags.": {
|
||||
"category": "Error",
|
||||
"code": 8021
|
||||
},
|
||||
"Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clause.": {
|
||||
"category": "Error",
|
||||
"code": 9002
|
||||
|
||||
Regular → Executable
+24
-37
@@ -1440,29 +1440,18 @@ namespace ts {
|
||||
//
|
||||
|
||||
function emitBlock(node: Block) {
|
||||
if (isSingleLineEmptyBlock(node)) {
|
||||
writeToken(SyntaxKind.OpenBraceToken, node.pos, /*contextNode*/ node);
|
||||
write(" ");
|
||||
writeToken(SyntaxKind.CloseBraceToken, node.statements.end, /*contextNode*/ node);
|
||||
}
|
||||
else {
|
||||
writeToken(SyntaxKind.OpenBraceToken, node.pos, /*contextNode*/ node);
|
||||
emitBlockStatements(node);
|
||||
// We have to call emitLeadingComments explicitly here because otherwise leading comments of the close brace token will not be emitted
|
||||
increaseIndent();
|
||||
emitLeadingCommentsOfPosition(node.statements.end);
|
||||
decreaseIndent();
|
||||
writeToken(SyntaxKind.CloseBraceToken, node.statements.end, /*contextNode*/ node);
|
||||
}
|
||||
writeToken(SyntaxKind.OpenBraceToken, node.pos, /*contextNode*/ node);
|
||||
emitBlockStatements(node, /*forceSingleLine*/ !node.multiLine && isEmptyBlock(node));
|
||||
// We have to call emitLeadingComments explicitly here because otherwise leading comments of the close brace token will not be emitted
|
||||
increaseIndent();
|
||||
emitLeadingCommentsOfPosition(node.statements.end);
|
||||
decreaseIndent();
|
||||
writeToken(SyntaxKind.CloseBraceToken, node.statements.end, /*contextNode*/ node);
|
||||
}
|
||||
|
||||
function emitBlockStatements(node: BlockLike) {
|
||||
if (getEmitFlags(node) & EmitFlags.SingleLine) {
|
||||
emitList(node, node.statements, ListFormat.SingleLineBlockStatements);
|
||||
}
|
||||
else {
|
||||
emitList(node, node.statements, ListFormat.MultiLineBlockStatements);
|
||||
}
|
||||
function emitBlockStatements(node: BlockLike, forceSingleLine: boolean) {
|
||||
const format = forceSingleLine || getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineBlockStatements : ListFormat.MultiLineBlockStatements;
|
||||
emitList(node, node.statements, format);
|
||||
}
|
||||
|
||||
function emitVariableStatement(node: VariableStatement) {
|
||||
@@ -1874,7 +1863,9 @@ namespace ts {
|
||||
|
||||
function emitModuleDeclaration(node: ModuleDeclaration) {
|
||||
emitModifiers(node, node.modifiers);
|
||||
write(node.flags & NodeFlags.Namespace ? "namespace " : "module ");
|
||||
if (~node.flags & NodeFlags.GlobalAugmentation) {
|
||||
write(node.flags & NodeFlags.Namespace ? "namespace " : "module ");
|
||||
}
|
||||
emit(node.name);
|
||||
|
||||
let body = node.body;
|
||||
@@ -1889,16 +1880,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
function emitModuleBlock(node: ModuleBlock) {
|
||||
if (isEmptyBlock(node)) {
|
||||
write("{ }");
|
||||
}
|
||||
else {
|
||||
pushNameGenerationScope();
|
||||
write("{");
|
||||
emitBlockStatements(node);
|
||||
write("}");
|
||||
popNameGenerationScope();
|
||||
}
|
||||
pushNameGenerationScope();
|
||||
write("{");
|
||||
emitBlockStatements(node, /*forceSingleLine*/ isEmptyBlock(node));
|
||||
write("}");
|
||||
popNameGenerationScope();
|
||||
}
|
||||
|
||||
function emitCaseBlock(node: CaseBlock) {
|
||||
@@ -2417,6 +2403,12 @@ namespace ts {
|
||||
|
||||
const isEmpty = isUndefined || start >= children.length || count === 0;
|
||||
if (isEmpty && format & ListFormat.OptionalIfEmpty) {
|
||||
if (onBeforeEmitNodeArray) {
|
||||
onBeforeEmitNodeArray(children);
|
||||
}
|
||||
if (onAfterEmitNodeArray) {
|
||||
onAfterEmitNodeArray(children);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2756,11 +2748,6 @@ namespace ts {
|
||||
&& !rangeEndIsOnSameLineAsRangeStart(node1, node2, currentSourceFile);
|
||||
}
|
||||
|
||||
function isSingleLineEmptyBlock(block: Block) {
|
||||
return !block.multiLine
|
||||
&& isEmptyBlock(block);
|
||||
}
|
||||
|
||||
function isEmptyBlock(block: BlockLike) {
|
||||
return block.statements.length === 0
|
||||
&& rangeEndIsOnSameLineAsRangeStart(block, block, currentSourceFile);
|
||||
|
||||
+30
-7
@@ -773,13 +773,13 @@ namespace ts {
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createLiteralTypeNode(literal: Expression) {
|
||||
export function createLiteralTypeNode(literal: LiteralTypeNode["literal"]) {
|
||||
const node = createSynthesizedNode(SyntaxKind.LiteralType) as LiteralTypeNode;
|
||||
node.literal = literal;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function updateLiteralTypeNode(node: LiteralTypeNode, literal: Expression) {
|
||||
export function updateLiteralTypeNode(node: LiteralTypeNode, literal: LiteralTypeNode["literal"]) {
|
||||
return node.literal !== literal
|
||||
? updateNode(createLiteralTypeNode(literal), node)
|
||||
: node;
|
||||
@@ -1207,6 +1207,30 @@ namespace ts {
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createTemplateHead(text: string) {
|
||||
const node = <TemplateHead>createSynthesizedNode(SyntaxKind.TemplateHead);
|
||||
node.text = text;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createTemplateMiddle(text: string) {
|
||||
const node = <TemplateMiddle>createSynthesizedNode(SyntaxKind.TemplateMiddle);
|
||||
node.text = text;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createTemplateTail(text: string) {
|
||||
const node = <TemplateTail>createSynthesizedNode(SyntaxKind.TemplateTail);
|
||||
node.text = text;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createNoSubstitutionTemplateLiteral(text: string) {
|
||||
const node = <NoSubstitutionTemplateLiteral>createSynthesizedNode(SyntaxKind.NoSubstitutionTemplateLiteral);
|
||||
node.text = text;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createYield(expression?: Expression): YieldExpression;
|
||||
export function createYield(asteriskToken: AsteriskToken, expression: Expression): YieldExpression;
|
||||
export function createYield(asteriskTokenOrExpression?: AsteriskToken | Expression, expression?: Expression) {
|
||||
@@ -3941,11 +3965,10 @@ namespace ts {
|
||||
return recreateOuterExpressions(expression, mutableCall, OuterExpressionKinds.PartiallyEmittedExpressions);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const leftmostExpressionKind = getLeftmostExpression(emittedExpression).kind;
|
||||
if (leftmostExpressionKind === SyntaxKind.ObjectLiteralExpression || leftmostExpressionKind === SyntaxKind.FunctionExpression) {
|
||||
return setTextRange(createParen(expression), expression);
|
||||
}
|
||||
|
||||
const leftmostExpressionKind = getLeftmostExpression(emittedExpression).kind;
|
||||
if (leftmostExpressionKind === SyntaxKind.ObjectLiteralExpression || leftmostExpressionKind === SyntaxKind.FunctionExpression) {
|
||||
return setTextRange(createParen(expression), expression);
|
||||
}
|
||||
|
||||
return expression;
|
||||
|
||||
@@ -976,8 +976,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
function loadModuleFromNodeModulesFolder(extensions: Extensions, moduleName: string, nodeModulesFolder: string, nodeModulesFolderExists: boolean, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
|
||||
const { top, rest } = getNameOfTopDirectory(moduleName);
|
||||
const packageRootPath = combinePaths(nodeModulesFolder, top);
|
||||
const { packageName, rest } = getPackageName(moduleName);
|
||||
const packageRootPath = combinePaths(nodeModulesFolder, packageName);
|
||||
const { packageJsonContent, packageId } = getPackageJsonInfo(packageRootPath, rest, failedLookupLocations, !nodeModulesFolderExists, state);
|
||||
const candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName));
|
||||
const pathAndExtension = loadModuleFromFile(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state) ||
|
||||
@@ -985,9 +985,12 @@ namespace ts {
|
||||
return withPackageId(packageId, pathAndExtension);
|
||||
}
|
||||
|
||||
function getNameOfTopDirectory(name: string): { top: string, rest: string } {
|
||||
const idx = name.indexOf(directorySeparator);
|
||||
return idx === -1 ? { top: name, rest: "" } : { top: name.slice(0, idx), rest: name.slice(idx + 1) };
|
||||
function getPackageName(moduleName: string): { packageName: string, rest: string } {
|
||||
let idx = moduleName.indexOf(directorySeparator);
|
||||
if (moduleName[0] === "@") {
|
||||
idx = moduleName.indexOf(directorySeparator, idx + 1);
|
||||
}
|
||||
return idx === -1 ? { packageName: moduleName, rest: "" } : { packageName: moduleName.slice(0, idx), rest: moduleName.slice(idx + 1) };
|
||||
}
|
||||
|
||||
function loadModuleFromNodeModules(extensions: Extensions, moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState, cache: NonRelativeModuleNameResolutionCache): SearchResult<Resolved> {
|
||||
|
||||
+36
-44
@@ -1207,7 +1207,10 @@ namespace ts {
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, diagnosticMessage || Diagnostics.Identifier_expected);
|
||||
// Only for end of file because the error gets reported incorrectly on embedded script tags.
|
||||
const reportAtCurrentPosition = token() === SyntaxKind.EndOfFileToken;
|
||||
|
||||
return createMissingNode<Identifier>(SyntaxKind.Identifier, reportAtCurrentPosition, diagnosticMessage || Diagnostics.Identifier_expected);
|
||||
}
|
||||
|
||||
function parseIdentifier(diagnosticMessage?: DiagnosticMessage): Identifier {
|
||||
@@ -2240,7 +2243,7 @@ namespace ts {
|
||||
isStartOfType(/*inStartOfParameter*/ true);
|
||||
}
|
||||
|
||||
function parseParameter(): ParameterDeclaration {
|
||||
function parseParameter(requireEqualsToken?: boolean): ParameterDeclaration {
|
||||
const node = <ParameterDeclaration>createNode(SyntaxKind.Parameter);
|
||||
if (token() === SyntaxKind.ThisKeyword) {
|
||||
node.name = createIdentifier(/*isIdentifier*/ true);
|
||||
@@ -2269,19 +2272,11 @@ namespace ts {
|
||||
|
||||
node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
|
||||
node.type = parseParameterType();
|
||||
node.initializer = parseBindingElementInitializer(/*inParameter*/ true);
|
||||
node.initializer = parseInitializer(/*inParameter*/ true, requireEqualsToken);
|
||||
|
||||
return addJSDocComment(finishNode(node));
|
||||
}
|
||||
|
||||
function parseBindingElementInitializer(inParameter: boolean) {
|
||||
return inParameter ? parseParameterInitializer() : parseNonParameterInitializer();
|
||||
}
|
||||
|
||||
function parseParameterInitializer() {
|
||||
return parseInitializer(/*inParameter*/ true);
|
||||
}
|
||||
|
||||
function fillSignature(
|
||||
returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken,
|
||||
flags: SignatureFlags,
|
||||
@@ -2334,7 +2329,8 @@ namespace ts {
|
||||
setYieldContext(!!(flags & SignatureFlags.Yield));
|
||||
setAwaitContext(!!(flags & SignatureFlags.Await));
|
||||
|
||||
const result = parseDelimitedList(ParsingContext.Parameters, flags & SignatureFlags.JSDoc ? parseJSDocParameter : parseParameter);
|
||||
const result = parseDelimitedList(ParsingContext.Parameters,
|
||||
flags & SignatureFlags.JSDoc ? parseJSDocParameter : () => parseParameter(!!(flags & SignatureFlags.RequireCompleteParameterList)));
|
||||
|
||||
setYieldContext(savedYieldContext);
|
||||
setAwaitContext(savedAwaitContext);
|
||||
@@ -2621,16 +2617,9 @@ namespace ts {
|
||||
unaryMinusExpression.operator = SyntaxKind.MinusToken;
|
||||
nextToken();
|
||||
}
|
||||
let expression: UnaryExpression;
|
||||
switch (token()) {
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.NumericLiteral:
|
||||
expression = parseLiteralLikeNode(token()) as LiteralExpression;
|
||||
break;
|
||||
case SyntaxKind.TrueKeyword:
|
||||
case SyntaxKind.FalseKeyword:
|
||||
expression = parseTokenNode();
|
||||
}
|
||||
let expression: BooleanLiteral | LiteralExpression | PrefixUnaryExpression = token() === SyntaxKind.TrueKeyword || token() === SyntaxKind.FalseKeyword
|
||||
? parseTokenNode<BooleanLiteral>()
|
||||
: parseLiteralLikeNode(token()) as LiteralExpression;
|
||||
if (negative) {
|
||||
unaryMinusExpression.operand = expression;
|
||||
finishNode(unaryMinusExpression);
|
||||
@@ -2666,6 +2655,7 @@ namespace ts {
|
||||
return parseJSDocNodeWithType(SyntaxKind.JSDocVariadicType);
|
||||
case SyntaxKind.ExclamationToken:
|
||||
return parseJSDocNodeWithType(SyntaxKind.JSDocNonNullableType);
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.TrueKeyword:
|
||||
@@ -3017,7 +3007,7 @@ namespace ts {
|
||||
return expr;
|
||||
}
|
||||
|
||||
function parseInitializer(inParameter: boolean): Expression {
|
||||
function parseInitializer(inParameter: boolean, requireEqualsToken?: boolean): Expression {
|
||||
if (token() !== SyntaxKind.EqualsToken) {
|
||||
// It's not uncommon during typing for the user to miss writing the '=' token. Check if
|
||||
// there is no newline after the last token and if we're on an expression. If so, parse
|
||||
@@ -3032,11 +3022,17 @@ namespace ts {
|
||||
// do not try to parse initializer
|
||||
return undefined;
|
||||
}
|
||||
if (inParameter && requireEqualsToken) {
|
||||
// = is required when speculatively parsing arrow function parameters,
|
||||
// so return a fake initializer as a signal that the equals token was missing
|
||||
const result = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics._0_expected, "=") as Identifier;
|
||||
result.escapedText = "= not found" as __String;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Initializer[In, Yield] :
|
||||
// = AssignmentExpression[?In, ?Yield]
|
||||
|
||||
parseExpected(SyntaxKind.EqualsToken);
|
||||
return parseAssignmentExpressionOrHigher();
|
||||
}
|
||||
@@ -3351,8 +3347,7 @@ namespace ts {
|
||||
function tryParseAsyncSimpleArrowFunctionExpression(): ArrowFunction | undefined {
|
||||
// We do a check here so that we won't be doing unnecessarily call to "lookAhead"
|
||||
if (token() === SyntaxKind.AsyncKeyword) {
|
||||
const isUnParenthesizedAsyncArrowFunction = lookAhead(isUnParenthesizedAsyncArrowFunctionWorker);
|
||||
if (isUnParenthesizedAsyncArrowFunction === Tristate.True) {
|
||||
if (lookAhead(isUnParenthesizedAsyncArrowFunctionWorker) === Tristate.True) {
|
||||
const asyncModifier = parseModifiersForArrowFunction();
|
||||
const expr = parseBinaryExpressionOrHigher(/*precedence*/ 0);
|
||||
return parseSimpleArrowFunctionExpression(<Identifier>expr, asyncModifier);
|
||||
@@ -3386,7 +3381,6 @@ namespace ts {
|
||||
const node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction);
|
||||
node.modifiers = parseModifiersForArrowFunction();
|
||||
const isAsync = hasModifier(node, ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None;
|
||||
|
||||
// Arrow functions are never generators.
|
||||
//
|
||||
// If we're speculatively parsing a signature for a parenthesized arrow function, then
|
||||
@@ -3409,7 +3403,8 @@ namespace ts {
|
||||
// - "a ? (b): c" will have "(b):" parsed as a signature with a return type annotation.
|
||||
//
|
||||
// So we need just a bit of lookahead to ensure that it can only be a signature.
|
||||
if (!allowAmbiguity && token() !== SyntaxKind.EqualsGreaterThanToken && token() !== SyntaxKind.OpenBraceToken) {
|
||||
if (!allowAmbiguity && ((token() !== SyntaxKind.EqualsGreaterThanToken && token() !== SyntaxKind.OpenBraceToken) ||
|
||||
find(node.parameters, p => p.initializer && ts.isIdentifier(p.initializer) && p.initializer.escapedText === "= not found"))) {
|
||||
// Returning undefined here will cause our caller to rewind to where we started from.
|
||||
return undefined;
|
||||
}
|
||||
@@ -5158,7 +5153,7 @@ namespace ts {
|
||||
const node = <BindingElement>createNode(SyntaxKind.BindingElement);
|
||||
node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
|
||||
node.name = parseIdentifierOrPattern();
|
||||
node.initializer = parseBindingElementInitializer(/*inParameter*/ false);
|
||||
node.initializer = parseInitializer(/*inParameter*/ false);
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
@@ -5175,7 +5170,7 @@ namespace ts {
|
||||
node.propertyName = propertyName;
|
||||
node.name = parseIdentifierOrPattern();
|
||||
}
|
||||
node.initializer = parseBindingElementInitializer(/*inParameter*/ false);
|
||||
node.initializer = parseInitializer(/*inParameter*/ false);
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
@@ -5214,7 +5209,7 @@ namespace ts {
|
||||
node.name = parseIdentifierOrPattern();
|
||||
node.type = parseTypeAnnotation();
|
||||
if (!isInOrOfKeyword(token())) {
|
||||
node.initializer = parseInitializer(/*inParameter*/ false);
|
||||
node.initializer = parseNonParameterInitializer();
|
||||
}
|
||||
return finishNode(node);
|
||||
}
|
||||
@@ -6140,11 +6135,14 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Parses out a JSDoc type expression.
|
||||
/* @internal */
|
||||
export function parseJSDocTypeExpression(): JSDocTypeExpression {
|
||||
export function parseJSDocTypeExpression(): JSDocTypeExpression;
|
||||
export function parseJSDocTypeExpression(requireBraces: true): JSDocTypeExpression | undefined;
|
||||
export function parseJSDocTypeExpression(requireBraces?: boolean): JSDocTypeExpression | undefined {
|
||||
const result = <JSDocTypeExpression>createNode(SyntaxKind.JSDocTypeExpression, scanner.getTokenPos());
|
||||
|
||||
parseExpected(SyntaxKind.OpenBraceToken);
|
||||
if (!parseExpected(SyntaxKind.OpenBraceToken) && requireBraces) {
|
||||
return undefined;
|
||||
}
|
||||
result.type = doInsideOfContext(NodeFlags.JSDoc, parseType);
|
||||
parseExpected(SyntaxKind.CloseBraceToken);
|
||||
|
||||
@@ -6491,14 +6489,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
function tryParseTypeExpression(): JSDocTypeExpression | undefined {
|
||||
return tryParse(() => {
|
||||
skipWhitespace();
|
||||
if (token() !== SyntaxKind.OpenBraceToken) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return parseJSDocTypeExpression();
|
||||
});
|
||||
skipWhitespace();
|
||||
return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined;
|
||||
}
|
||||
|
||||
function parseBracketNameInPropertyAndParamTag(): { name: EntityName, isBracketed: boolean } {
|
||||
@@ -6607,12 +6599,12 @@ namespace ts {
|
||||
const result = <JSDocTypeTag>createNode(SyntaxKind.JSDocTypeTag, atToken.pos);
|
||||
result.atToken = atToken;
|
||||
result.tagName = tagName;
|
||||
result.typeExpression = tryParseTypeExpression();
|
||||
result.typeExpression = parseJSDocTypeExpression(/*requireBraces*/ true);
|
||||
return finishNode(result);
|
||||
}
|
||||
|
||||
function parseAugmentsTag(atToken: AtToken, tagName: Identifier): JSDocAugmentsTag {
|
||||
const typeExpression = tryParseTypeExpression();
|
||||
const typeExpression = parseJSDocTypeExpression(/*requireBraces*/ true);
|
||||
|
||||
const result = <JSDocAugmentsTag>createNode(SyntaxKind.JSDocAugmentsTag, atToken.pos);
|
||||
result.atToken = atToken;
|
||||
|
||||
+36
-18
@@ -586,6 +586,8 @@ namespace ts {
|
||||
host = host || createCompilerHost(options);
|
||||
|
||||
let skipDefaultLib = options.noLib;
|
||||
const getDefaultLibraryFileName = memoize(() => host.getDefaultLibFileName(options));
|
||||
const defaultLibraryPath = host.getDefaultLibLocation ? host.getDefaultLibLocation() : getDirectoryPath(getDefaultLibraryFileName());
|
||||
const programDiagnostics = createDiagnosticCollection();
|
||||
const currentDirectory = host.getCurrentDirectory();
|
||||
const supportedExtensions = getSupportedExtensions(options);
|
||||
@@ -665,12 +667,11 @@ namespace ts {
|
||||
// If '--lib' is not specified, include default library file according to '--target'
|
||||
// otherwise, using options specified in '--lib' instead of '--target' default library file
|
||||
if (!options.lib) {
|
||||
processRootFile(host.getDefaultLibFileName(options), /*isDefaultLib*/ true);
|
||||
processRootFile(getDefaultLibraryFileName(), /*isDefaultLib*/ true);
|
||||
}
|
||||
else {
|
||||
const libDirectory = host.getDefaultLibLocation ? host.getDefaultLibLocation() : getDirectoryPath(host.getDefaultLibFileName(options));
|
||||
forEach(options.lib, libFileName => {
|
||||
processRootFile(combinePaths(libDirectory, libFileName), /*isDefaultLib*/ true);
|
||||
processRootFile(combinePaths(defaultLibraryPath, libFileName), /*isDefaultLib*/ true);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -722,6 +723,7 @@ namespace ts {
|
||||
getFileProcessingDiagnostics: () => fileProcessingDiagnostics,
|
||||
getResolvedTypeReferenceDirectives: () => resolvedTypeReferenceDirectives,
|
||||
isSourceFileFromExternalLibrary,
|
||||
isSourceFileDefaultLibrary,
|
||||
dropDiagnosticsProducingTypeChecker,
|
||||
getSourceFileFromReference,
|
||||
sourceFileToPackageName,
|
||||
@@ -1149,6 +1151,18 @@ namespace ts {
|
||||
return sourceFilesFoundSearchingNodeModules.get(file.path);
|
||||
}
|
||||
|
||||
function isSourceFileDefaultLibrary(file: SourceFile): boolean {
|
||||
if (file.hasNoDefaultLib) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (defaultLibraryPath && defaultLibraryPath.length !== 0) {
|
||||
return containsPath(defaultLibraryPath, file.path, currentDirectory, /*ignoreCase*/ !host.useCaseSensitiveFileNames());
|
||||
}
|
||||
|
||||
return compareStrings(file.fileName, getDefaultLibraryFileName(), /*ignoreCase*/ !host.useCaseSensitiveFileNames()) === Comparison.EqualTo;
|
||||
}
|
||||
|
||||
function getDiagnosticsProducingTypeChecker() {
|
||||
return diagnosticsProducingTypeChecker || (diagnosticsProducingTypeChecker = createTypeChecker(program, /*produceDiagnostics:*/ true));
|
||||
}
|
||||
@@ -1330,9 +1344,7 @@ namespace ts {
|
||||
const programDiagnosticsInFile = programDiagnostics.getDiagnostics(sourceFile.fileName);
|
||||
|
||||
const diagnostics = bindDiagnostics.concat(checkDiagnostics, fileProcessingDiagnosticsInFile, programDiagnosticsInFile);
|
||||
return isSourceFileJavaScript(sourceFile)
|
||||
? filter(diagnostics, shouldReportDiagnostic)
|
||||
: diagnostics;
|
||||
return filter(diagnostics, shouldReportDiagnostic);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1380,7 +1392,7 @@ namespace ts {
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_can_only_be_used_in_a_ts_file, "?"));
|
||||
return;
|
||||
}
|
||||
// falls through
|
||||
// falls through
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.Constructor:
|
||||
@@ -1462,7 +1474,7 @@ namespace ts {
|
||||
diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.type_parameter_declarations_can_only_be_used_in_a_ts_file));
|
||||
return;
|
||||
}
|
||||
// falls through
|
||||
// falls through
|
||||
case SyntaxKind.VariableStatement:
|
||||
// Check modifiers
|
||||
if (nodes === (<ClassDeclaration | FunctionLikeDeclaration | VariableStatement>parent).modifiers) {
|
||||
@@ -1510,8 +1522,8 @@ namespace ts {
|
||||
if (isConstValid) {
|
||||
continue;
|
||||
}
|
||||
// to report error,
|
||||
// falls through
|
||||
// to report error,
|
||||
// falls through
|
||||
case SyntaxKind.PublicKeyword:
|
||||
case SyntaxKind.PrivateKeyword:
|
||||
case SyntaxKind.ProtectedKeyword:
|
||||
@@ -1622,7 +1634,7 @@ namespace ts {
|
||||
|
||||
// file.imports may not be undefined if there exists dynamic import
|
||||
let imports: StringLiteral[];
|
||||
let moduleAugmentations: Array<StringLiteral | Identifier>;
|
||||
let moduleAugmentations: (StringLiteral | Identifier)[];
|
||||
let ambientModules: string[];
|
||||
|
||||
// If we are importing helpers, we need to add a synthetic reference to resolve the
|
||||
@@ -1725,10 +1737,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getSourceFileFromReferenceWorker(
|
||||
fileName: string,
|
||||
getSourceFile: (fileName: string) => SourceFile | undefined,
|
||||
fail?: (diagnostic: DiagnosticMessage, ...argument: string[]) => void,
|
||||
refFile?: SourceFile): SourceFile | undefined {
|
||||
fileName: string,
|
||||
getSourceFile: (fileName: string) => SourceFile | undefined,
|
||||
fail?: (diagnostic: DiagnosticMessage, ...argument: string[]) => void,
|
||||
refFile?: SourceFile): SourceFile | undefined {
|
||||
|
||||
if (hasExtension(fileName)) {
|
||||
if (!options.allowNonTsExtensions && !forEach(supportedExtensions, extension => fileExtensionIs(host.getCanonicalFileName(fileName), extension))) {
|
||||
@@ -2004,7 +2016,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
const isFromNodeModulesSearch = resolution.isExternalLibraryImport;
|
||||
const isJsFileFromNodeModules = isFromNodeModulesSearch && !extensionIsTypeScript(resolution.extension);
|
||||
const isJsFile = !extensionIsTypeScript(resolution.extension);
|
||||
const isJsFileFromNodeModules = isFromNodeModulesSearch && isJsFile;
|
||||
const resolvedFileName = resolution.resolvedFileName;
|
||||
|
||||
if (isFromNodeModulesSearch) {
|
||||
@@ -2019,7 +2032,12 @@ namespace ts {
|
||||
const elideImport = isJsFileFromNodeModules && currentNodeModulesDepth > maxNodeModuleJsDepth;
|
||||
// Don't add the file if it has a bad extension (e.g. 'tsx' if we don't have '--allowJs')
|
||||
// This may still end up being an untyped module -- the file won't be included but imports will be allowed.
|
||||
const shouldAddFile = resolvedFileName && !getResolutionDiagnostic(options, resolution) && !options.noResolve && i < file.imports.length && !elideImport;
|
||||
const shouldAddFile = resolvedFileName
|
||||
&& !getResolutionDiagnostic(options, resolution)
|
||||
&& !options.noResolve
|
||||
&& i < file.imports.length
|
||||
&& !elideImport
|
||||
&& !(isJsFile && !options.allowJs);
|
||||
|
||||
if (elideImport) {
|
||||
modulesWithElidedImports.set(file.path, true);
|
||||
@@ -2394,7 +2412,7 @@ namespace ts {
|
||||
return options.jsx ? undefined : Diagnostics.Module_0_was_resolved_to_1_but_jsx_is_not_set;
|
||||
}
|
||||
function needAllowJs() {
|
||||
return options.allowJs ? undefined : Diagnostics.Module_0_was_resolved_to_1_but_allowJs_is_not_set;
|
||||
return options.allowJs || !options.noImplicitAny ? undefined : Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@ namespace ts {
|
||||
// if it will fail and we've already found something during the first pass - we don't want to pollute its results
|
||||
const { resolvedModule, failedLookupLocations } = loadModuleFromGlobalCache(moduleName, resolutionHost.projectName, compilerOptions, host, globalCache);
|
||||
if (resolvedModule) {
|
||||
return { resolvedModule, failedLookupLocations: addRange(primaryResult.failedLookupLocations as Array<string>, failedLookupLocations) };
|
||||
return { resolvedModule, failedLookupLocations: addRange(primaryResult.failedLookupLocations as string[], failedLookupLocations) };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,21 +14,29 @@ namespace ts {
|
||||
return getSymbolWalker;
|
||||
|
||||
function getSymbolWalker(accept: (symbol: Symbol) => boolean = () => true): SymbolWalker {
|
||||
const visitedTypes = createMap<Type>(); // Key is id as string
|
||||
const visitedSymbols = createMap<Symbol>(); // Key is id as string
|
||||
const visitedTypes: Type[] = []; // Sparse array from id to type
|
||||
const visitedSymbols: Symbol[] = []; // Sparse array from id to symbol
|
||||
|
||||
return {
|
||||
walkType: type => {
|
||||
visitedTypes.clear();
|
||||
visitedSymbols.clear();
|
||||
visitType(type);
|
||||
return { visitedTypes: arrayFrom(visitedTypes.values()), visitedSymbols: arrayFrom(visitedSymbols.values()) };
|
||||
try {
|
||||
visitType(type);
|
||||
return { visitedTypes: getOwnValues(visitedTypes), visitedSymbols: getOwnValues(visitedSymbols) };
|
||||
}
|
||||
finally {
|
||||
clear(visitedTypes);
|
||||
clear(visitedSymbols);
|
||||
}
|
||||
},
|
||||
walkSymbol: symbol => {
|
||||
visitedTypes.clear();
|
||||
visitedSymbols.clear();
|
||||
visitSymbol(symbol);
|
||||
return { visitedTypes: arrayFrom(visitedTypes.values()), visitedSymbols: arrayFrom(visitedSymbols.values()) };
|
||||
try {
|
||||
visitSymbol(symbol);
|
||||
return { visitedTypes: getOwnValues(visitedTypes), visitedSymbols: getOwnValues(visitedSymbols) };
|
||||
}
|
||||
finally {
|
||||
clear(visitedTypes);
|
||||
clear(visitedSymbols);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -37,11 +45,10 @@ namespace ts {
|
||||
return;
|
||||
}
|
||||
|
||||
const typeIdString = type.id.toString();
|
||||
if (visitedTypes.has(typeIdString)) {
|
||||
if (visitedTypes[type.id]) {
|
||||
return;
|
||||
}
|
||||
visitedTypes.set(typeIdString, type);
|
||||
visitedTypes[type.id] = type;
|
||||
|
||||
// Reuse visitSymbol to visit the type's symbol,
|
||||
// but be sure to bail on recuring into the type if accept declines the symbol.
|
||||
@@ -79,18 +86,9 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function visitTypeList(types: Type[]): void {
|
||||
if (!types) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < types.length; i++) {
|
||||
visitType(types[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function visitTypeReference(type: TypeReference): void {
|
||||
visitType(type.target);
|
||||
visitTypeList(type.typeArguments);
|
||||
forEach(type.typeArguments, visitType);
|
||||
}
|
||||
|
||||
function visitTypeParameter(type: TypeParameter): void {
|
||||
@@ -98,7 +96,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function visitUnionOrIntersectionType(type: UnionOrIntersectionType): void {
|
||||
visitTypeList(type.types);
|
||||
forEach(type.types, visitType);
|
||||
}
|
||||
|
||||
function visitIndexType(type: IndexType): void {
|
||||
@@ -122,7 +120,7 @@ namespace ts {
|
||||
if (signature.typePredicate) {
|
||||
visitType(signature.typePredicate.type);
|
||||
}
|
||||
visitTypeList(signature.typeParameters);
|
||||
forEach(signature.typeParameters, visitType);
|
||||
|
||||
for (const parameter of signature.parameters){
|
||||
visitSymbol(parameter);
|
||||
@@ -133,8 +131,8 @@ namespace ts {
|
||||
|
||||
function visitInterfaceType(interfaceT: InterfaceType): void {
|
||||
visitObjectType(interfaceT);
|
||||
visitTypeList(interfaceT.typeParameters);
|
||||
visitTypeList(getBaseTypes(interfaceT));
|
||||
forEach(interfaceT.typeParameters, visitType);
|
||||
forEach(getBaseTypes(interfaceT), visitType);
|
||||
visitType(interfaceT.thisType);
|
||||
}
|
||||
|
||||
@@ -161,11 +159,11 @@ namespace ts {
|
||||
if (!symbol) {
|
||||
return;
|
||||
}
|
||||
const symbolIdString = getSymbolId(symbol).toString();
|
||||
if (visitedSymbols.has(symbolIdString)) {
|
||||
const symbolId = getSymbolId(symbol);
|
||||
if (visitedSymbols[symbolId]) {
|
||||
return;
|
||||
}
|
||||
visitedSymbols.set(symbolIdString, symbol);
|
||||
visitedSymbols[symbolId] = symbol;
|
||||
if (!accept(symbol)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -200,6 +200,7 @@ namespace ts {
|
||||
*/
|
||||
function transformUMDModule(node: SourceFile) {
|
||||
const { aliasedModuleNames, unaliasedModuleNames, importAliasNames } = collectAsynchronousDependencies(node, /*includeNonAmdDependencies*/ false);
|
||||
const moduleName = tryGetModuleNameFromFile(node, host, compilerOptions);
|
||||
const umdHeader = createFunctionExpression(
|
||||
/*modifiers*/ undefined,
|
||||
/*asteriskToken*/ undefined,
|
||||
@@ -260,6 +261,8 @@ namespace ts {
|
||||
createIdentifier("define"),
|
||||
/*typeArguments*/ undefined,
|
||||
[
|
||||
// Add the module name (if provided).
|
||||
...(moduleName ? [moduleName] : []),
|
||||
createArrayLiteral([
|
||||
createLiteral("require"),
|
||||
createLiteral("exports"),
|
||||
|
||||
@@ -1049,7 +1049,7 @@ namespace ts {
|
||||
|
||||
export interface LiteralTypeNode extends TypeNode {
|
||||
kind: SyntaxKind.LiteralType;
|
||||
literal: Expression;
|
||||
literal: BooleanLiteral | LiteralExpression | PrefixUnaryExpression;
|
||||
}
|
||||
|
||||
export interface StringLiteral extends LiteralExpression {
|
||||
@@ -2514,6 +2514,8 @@ namespace ts {
|
||||
/* @internal */ getFileProcessingDiagnostics(): DiagnosticCollection;
|
||||
/* @internal */ getResolvedTypeReferenceDirectives(): Map<ResolvedTypeReferenceDirective>;
|
||||
isSourceFileFromExternalLibrary(file: SourceFile): boolean;
|
||||
/* @internal */ isSourceFileDefaultLibrary(file: SourceFile): boolean;
|
||||
|
||||
// For testing purposes only.
|
||||
/* @internal */ structureIsReused?: StructureIsReused;
|
||||
|
||||
@@ -2704,7 +2706,8 @@ namespace ts {
|
||||
* So for `{ a } | { b }`, this will include both `a` and `b`.
|
||||
* Does not include properties of primitive types.
|
||||
*/
|
||||
/* @internal */ getAllPossiblePropertiesOfType(type: Type): Symbol[];
|
||||
/* @internal */ isArrayLikeType(type: Type): boolean;
|
||||
/* @internal */ getAllPossiblePropertiesOfTypes(type: ReadonlyArray<Type>): Symbol[];
|
||||
/* @internal */ resolveName(name: string, location: Node, meaning: SymbolFlags): Symbol | undefined;
|
||||
/* @internal */ getJsxNamespace(): string;
|
||||
}
|
||||
@@ -3217,6 +3220,7 @@ namespace ts {
|
||||
/* @internal */
|
||||
Nullable = Undefined | Null,
|
||||
Literal = StringLiteral | NumberLiteral | BooleanLiteral,
|
||||
Unit = Literal | Nullable,
|
||||
StringOrNumberLiteral = StringLiteral | NumberLiteral,
|
||||
/* @internal */
|
||||
DefinitelyFalsy = StringLiteral | NumberLiteral | BooleanLiteral | Void | Undefined | Null,
|
||||
@@ -4119,8 +4123,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
export interface CompilerHost extends ModuleResolutionHost {
|
||||
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile;
|
||||
getSourceFileByPath?(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile;
|
||||
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined;
|
||||
getSourceFileByPath?(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined;
|
||||
getCancellationToken?(): CancellationToken;
|
||||
getDefaultLibFileName(options: CompilerOptions): string;
|
||||
getDefaultLibLocation?(): string;
|
||||
|
||||
+182
-114
@@ -321,6 +321,18 @@ namespace ts {
|
||||
return getSourceTextOfNodeFromSourceFile(getSourceFileOfNode(node), node, includeTrivia);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: it is expected that the `nodeArray` and the `node` are within the same file.
|
||||
* For example, searching for a `SourceFile` in a `SourceFile[]` wouldn't work.
|
||||
*/
|
||||
export function indexOfNode(nodeArray: ReadonlyArray<Node>, node: Node) {
|
||||
return binarySearch(nodeArray, node, compareNodePos);
|
||||
}
|
||||
|
||||
function compareNodePos({ pos: aPos }: Node, { pos: bPos}: Node) {
|
||||
return aPos < bPos ? Comparison.LessThan : bPos < aPos ? Comparison.GreaterThan : Comparison.EqualTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets flags that control emit behavior of a node.
|
||||
*/
|
||||
@@ -1256,57 +1268,60 @@ namespace ts {
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.ThisKeyword:
|
||||
const parent = node.parent;
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.PropertySignature:
|
||||
case SyntaxKind.EnumMember:
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
case SyntaxKind.BindingElement:
|
||||
return (<VariableLikeDeclaration>parent).initializer === node;
|
||||
case SyntaxKind.ExpressionStatement:
|
||||
case SyntaxKind.IfStatement:
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.WhileStatement:
|
||||
case SyntaxKind.ReturnStatement:
|
||||
case SyntaxKind.WithStatement:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
case SyntaxKind.CaseClause:
|
||||
case SyntaxKind.ThrowStatement:
|
||||
return (<ExpressionStatement>parent).expression === node;
|
||||
case SyntaxKind.ForStatement:
|
||||
const forStatement = <ForStatement>parent;
|
||||
return (forStatement.initializer === node && forStatement.initializer.kind !== SyntaxKind.VariableDeclarationList) ||
|
||||
forStatement.condition === node ||
|
||||
forStatement.incrementor === node;
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.ForOfStatement:
|
||||
const forInStatement = <ForInStatement | ForOfStatement>parent;
|
||||
return (forInStatement.initializer === node && forInStatement.initializer.kind !== SyntaxKind.VariableDeclarationList) ||
|
||||
forInStatement.expression === node;
|
||||
case SyntaxKind.TypeAssertionExpression:
|
||||
case SyntaxKind.AsExpression:
|
||||
return node === (<AssertionExpression>parent).expression;
|
||||
case SyntaxKind.TemplateSpan:
|
||||
return node === (<TemplateSpan>parent).expression;
|
||||
case SyntaxKind.ComputedPropertyName:
|
||||
return node === (<ComputedPropertyName>parent).expression;
|
||||
case SyntaxKind.Decorator:
|
||||
case SyntaxKind.JsxExpression:
|
||||
case SyntaxKind.JsxSpreadAttribute:
|
||||
case SyntaxKind.SpreadAssignment:
|
||||
return true;
|
||||
case SyntaxKind.ExpressionWithTypeArguments:
|
||||
return (<ExpressionWithTypeArguments>parent).expression === node && isExpressionWithTypeArgumentsInClassExtendsClause(parent);
|
||||
default:
|
||||
if (isPartOfExpression(parent)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return isInExpressionContext(node);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function isInExpressionContext(node: Node): boolean {
|
||||
const parent = node.parent;
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.PropertySignature:
|
||||
case SyntaxKind.EnumMember:
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
case SyntaxKind.BindingElement:
|
||||
return (<VariableLikeDeclaration>parent).initializer === node;
|
||||
case SyntaxKind.ExpressionStatement:
|
||||
case SyntaxKind.IfStatement:
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.WhileStatement:
|
||||
case SyntaxKind.ReturnStatement:
|
||||
case SyntaxKind.WithStatement:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
case SyntaxKind.CaseClause:
|
||||
case SyntaxKind.ThrowStatement:
|
||||
return (<ExpressionStatement>parent).expression === node;
|
||||
case SyntaxKind.ForStatement:
|
||||
const forStatement = <ForStatement>parent;
|
||||
return (forStatement.initializer === node && forStatement.initializer.kind !== SyntaxKind.VariableDeclarationList) ||
|
||||
forStatement.condition === node ||
|
||||
forStatement.incrementor === node;
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.ForOfStatement:
|
||||
const forInStatement = <ForInStatement | ForOfStatement>parent;
|
||||
return (forInStatement.initializer === node && forInStatement.initializer.kind !== SyntaxKind.VariableDeclarationList) ||
|
||||
forInStatement.expression === node;
|
||||
case SyntaxKind.TypeAssertionExpression:
|
||||
case SyntaxKind.AsExpression:
|
||||
return node === (<AssertionExpression>parent).expression;
|
||||
case SyntaxKind.TemplateSpan:
|
||||
return node === (<TemplateSpan>parent).expression;
|
||||
case SyntaxKind.ComputedPropertyName:
|
||||
return node === (<ComputedPropertyName>parent).expression;
|
||||
case SyntaxKind.Decorator:
|
||||
case SyntaxKind.JsxExpression:
|
||||
case SyntaxKind.JsxSpreadAttribute:
|
||||
case SyntaxKind.SpreadAssignment:
|
||||
return true;
|
||||
case SyntaxKind.ExpressionWithTypeArguments:
|
||||
return (<ExpressionWithTypeArguments>parent).expression === node && isExpressionWithTypeArgumentsInClassExtendsClause(parent);
|
||||
default:
|
||||
return isPartOfExpression(parent);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isExternalModuleImportEqualsDeclaration(node: Node) {
|
||||
@@ -1326,11 +1341,11 @@ namespace ts {
|
||||
return isInJavaScriptFile(file);
|
||||
}
|
||||
|
||||
export function isInJavaScriptFile(node: Node): boolean {
|
||||
export function isInJavaScriptFile(node: Node | undefined): boolean {
|
||||
return node && !!(node.flags & NodeFlags.JavaScriptFile);
|
||||
}
|
||||
|
||||
export function isInJSDoc(node: Node): boolean {
|
||||
export function isInJSDoc(node: Node | undefined): boolean {
|
||||
return node && !!(node.flags & NodeFlags.JSDoc);
|
||||
}
|
||||
|
||||
@@ -1494,15 +1509,6 @@ namespace ts {
|
||||
((node as JSDocFunctionType).parameters[0].name as Identifier).escapedText === "new";
|
||||
}
|
||||
|
||||
export function hasJSDocParameterTags(node: FunctionLikeDeclaration | SignatureDeclaration): boolean {
|
||||
return !!getFirstJSDocTag(node, SyntaxKind.JSDocParameterTag);
|
||||
}
|
||||
|
||||
function getFirstJSDocTag(node: Node, kind: SyntaxKind): JSDocTag | undefined {
|
||||
const tags = getJSDocTags(node);
|
||||
return find(tags, doc => doc.kind === kind);
|
||||
}
|
||||
|
||||
export function getAllJSDocs(node: Node): (JSDoc | JSDocTag)[] {
|
||||
if (isJSDocTypedefTag(node)) {
|
||||
return [node.parent];
|
||||
@@ -1510,17 +1516,8 @@ namespace ts {
|
||||
return getJSDocCommentsAndTags(node);
|
||||
}
|
||||
|
||||
export function getJSDocTags(node: Node): ReadonlyArray<JSDocTag> | undefined {
|
||||
let tags = (node as JSDocContainer).jsDocCache;
|
||||
// If cache is 'null', that means we did the work of searching for JSDoc tags and came up with nothing.
|
||||
if (tags === undefined) {
|
||||
(node as JSDocContainer).jsDocCache = tags = flatMap(getJSDocCommentsAndTags(node), j => isJSDoc(j) ? j.tags : j);
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
function getJSDocCommentsAndTags(node: Node): (JSDoc | JSDocTag)[] {
|
||||
let result: Array<JSDoc | JSDocTag> | undefined;
|
||||
export function getJSDocCommentsAndTags(node: Node): (JSDoc | JSDocTag)[] {
|
||||
let result: (JSDoc | JSDocTag)[] | undefined;
|
||||
getJSDocCommentsAndTagsWorker(node);
|
||||
return result || emptyArray;
|
||||
|
||||
@@ -1578,15 +1575,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function getJSDocParameterTags(param: ParameterDeclaration): JSDocParameterTag[] | undefined {
|
||||
if (param.name && isIdentifier(param.name)) {
|
||||
const name = param.name.escapedText;
|
||||
return getJSDocTags(param.parent).filter((tag): tag is JSDocParameterTag => isJSDocParameterTag(tag) && isIdentifier(tag.name) && tag.name.escapedText === name) as JSDocParameterTag[];
|
||||
}
|
||||
// a binding pattern doesn't have a name, so it's not possible to match it a jsdoc parameter, which is identified by name
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** Does the opposite of `getJSDocParameterTags`: given a JSDoc parameter, finds the parameter corresponding to it. */
|
||||
export function getParameterSymbolFromJSDoc(node: JSDocParameterTag): Symbol | undefined {
|
||||
if (node.symbol) {
|
||||
@@ -1612,39 +1600,6 @@ namespace ts {
|
||||
return find(typeParameters, p => p.name.escapedText === name);
|
||||
}
|
||||
|
||||
export function getJSDocType(node: Node): TypeNode {
|
||||
let tag: JSDocTypeTag | JSDocParameterTag = getFirstJSDocTag(node, SyntaxKind.JSDocTypeTag) as JSDocTypeTag;
|
||||
if (!tag && node.kind === SyntaxKind.Parameter) {
|
||||
const paramTags = getJSDocParameterTags(node as ParameterDeclaration);
|
||||
if (paramTags) {
|
||||
tag = find(paramTags, tag => !!tag.typeExpression);
|
||||
}
|
||||
}
|
||||
|
||||
return tag && tag.typeExpression && tag.typeExpression.type;
|
||||
}
|
||||
|
||||
export function getJSDocAugmentsTag(node: Node): JSDocAugmentsTag {
|
||||
return getFirstJSDocTag(node, SyntaxKind.JSDocAugmentsTag) as JSDocAugmentsTag;
|
||||
}
|
||||
|
||||
export function getJSDocClassTag(node: Node): JSDocClassTag {
|
||||
return getFirstJSDocTag(node, SyntaxKind.JSDocClassTag) as JSDocClassTag;
|
||||
}
|
||||
|
||||
export function getJSDocReturnTag(node: Node): JSDocReturnTag {
|
||||
return getFirstJSDocTag(node, SyntaxKind.JSDocReturnTag) as JSDocReturnTag;
|
||||
}
|
||||
|
||||
export function getJSDocReturnType(node: Node): TypeNode {
|
||||
const returnTag = getJSDocReturnTag(node);
|
||||
return returnTag && returnTag.typeExpression && returnTag.typeExpression.type;
|
||||
}
|
||||
|
||||
export function getJSDocTemplateTag(node: Node): JSDocTemplateTag {
|
||||
return getFirstJSDocTag(node, SyntaxKind.JSDocTemplateTag) as JSDocTemplateTag;
|
||||
}
|
||||
|
||||
export function hasRestParameter(s: SignatureDeclaration): boolean {
|
||||
return isRestParameter(lastOrUndefined(s.parameters));
|
||||
}
|
||||
@@ -4240,6 +4195,119 @@ namespace ts {
|
||||
return (declaration as NamedDeclaration).name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the JSDoc parameter tags for the node if present.
|
||||
*
|
||||
* @remarks Returns any JSDoc param tag that matches the provided
|
||||
* parameter, whether a param tag on a containing function
|
||||
* expression, or a param tag on a variable declaration whose
|
||||
* initializer is the containing function. The tags closest to the
|
||||
* node are returned first, so in the previous example, the param
|
||||
* tag on the containing function expression would be first.
|
||||
*
|
||||
* Does not return tags for binding patterns, because JSDoc matches
|
||||
* parameters by name and binding patterns do not have a name.
|
||||
*/
|
||||
export function getJSDocParameterTags(param: ParameterDeclaration): ReadonlyArray<JSDocParameterTag> | undefined {
|
||||
if (param.name && isIdentifier(param.name)) {
|
||||
const name = param.name.escapedText;
|
||||
return getJSDocTags(param.parent).filter((tag): tag is JSDocParameterTag => isJSDocParameterTag(tag) && isIdentifier(tag.name) && tag.name.escapedText === name) as JSDocParameterTag[];
|
||||
}
|
||||
// a binding pattern doesn't have a name, so it's not possible to match it a JSDoc parameter, which is identified by name
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the node has JSDoc parameter tags.
|
||||
*
|
||||
* @remarks Includes parameter tags that are not directly on the node,
|
||||
* for example on a variable declaration whose initializer is a function expression.
|
||||
*/
|
||||
export function hasJSDocParameterTags(node: FunctionLikeDeclaration | SignatureDeclaration): boolean {
|
||||
return !!getFirstJSDocTag(node, SyntaxKind.JSDocParameterTag);
|
||||
}
|
||||
|
||||
/** Gets the JSDoc augments tag for the node if present */
|
||||
export function getJSDocAugmentsTag(node: Node): JSDocAugmentsTag | undefined {
|
||||
return getFirstJSDocTag(node, SyntaxKind.JSDocAugmentsTag) as JSDocAugmentsTag;
|
||||
}
|
||||
|
||||
/** Gets the JSDoc class tag for the node if present */
|
||||
export function getJSDocClassTag(node: Node): JSDocClassTag | undefined {
|
||||
return getFirstJSDocTag(node, SyntaxKind.JSDocClassTag) as JSDocClassTag;
|
||||
}
|
||||
|
||||
/** Gets the JSDoc return tag for the node if present */
|
||||
export function getJSDocReturnTag(node: Node): JSDocReturnTag | undefined {
|
||||
return getFirstJSDocTag(node, SyntaxKind.JSDocReturnTag) as JSDocReturnTag;
|
||||
}
|
||||
|
||||
/** Gets the JSDoc template tag for the node if present */
|
||||
export function getJSDocTemplateTag(node: Node): JSDocTemplateTag | undefined {
|
||||
return getFirstJSDocTag(node, SyntaxKind.JSDocTemplateTag) as JSDocTemplateTag;
|
||||
}
|
||||
|
||||
/** Gets the JSDoc type tag for the node if present and valid */
|
||||
export function getJSDocTypeTag(node: Node): JSDocTypeTag | undefined {
|
||||
// We should have already issued an error if there were multiple type jsdocs, so just use the first one.
|
||||
const tag = getFirstJSDocTag(node, SyntaxKind.JSDocTypeTag) as JSDocTypeTag;
|
||||
if (tag && tag.typeExpression && tag.typeExpression.type) {
|
||||
return tag;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type node for the node if provided via JSDoc.
|
||||
*
|
||||
* @remarks The search includes any JSDoc param tag that relates
|
||||
* to the provided parameter, for example a type tag on the
|
||||
* parameter itself, or a param tag on a containing function
|
||||
* expression, or a param tag on a variable declaration whose
|
||||
* initializer is the containing function. The tags closest to the
|
||||
* node are examined first, so in the previous example, the type
|
||||
* tag directly on the node would be returned.
|
||||
*/
|
||||
export function getJSDocType(node: Node): TypeNode | undefined {
|
||||
let tag: JSDocTypeTag | JSDocParameterTag = getFirstJSDocTag(node, SyntaxKind.JSDocTypeTag) as JSDocTypeTag;
|
||||
if (!tag && node.kind === SyntaxKind.Parameter) {
|
||||
const paramTags = getJSDocParameterTags(node as ParameterDeclaration);
|
||||
if (paramTags) {
|
||||
tag = find(paramTags, tag => !!tag.typeExpression);
|
||||
}
|
||||
}
|
||||
|
||||
return tag && tag.typeExpression && tag.typeExpression.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the return type node for the node if provided via JSDoc's return tag.
|
||||
*
|
||||
* @remarks `getJSDocReturnTag` just gets the whole JSDoc tag. This function
|
||||
* gets the type from inside the braces.
|
||||
*/
|
||||
export function getJSDocReturnType(node: Node): TypeNode | undefined {
|
||||
const returnTag = getJSDocReturnTag(node);
|
||||
return returnTag && returnTag.typeExpression && returnTag.typeExpression.type;
|
||||
}
|
||||
|
||||
/** Get all JSDoc tags related to a node, including those on parent nodes. */
|
||||
export function getJSDocTags(node: Node): ReadonlyArray<JSDocTag> | undefined {
|
||||
let tags = (node as JSDocContainer).jsDocCache;
|
||||
// If cache is 'null', that means we did the work of searching for JSDoc tags and came up with nothing.
|
||||
if (tags === undefined) {
|
||||
(node as JSDocContainer).jsDocCache = tags = flatMap(getJSDocCommentsAndTags(node), j => isJSDoc(j) ? j.tags : j);
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
/** Get the first JSDoc tag of a specified kind, or undefined if not present. */
|
||||
function getFirstJSDocTag(node: Node, kind: SyntaxKind): JSDocTag | undefined {
|
||||
const tags = getJSDocTags(node);
|
||||
return find(tags, doc => doc.kind === kind);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Simple node tests of the form `node.kind === SyntaxKind.Foo`.
|
||||
|
||||
@@ -177,7 +177,7 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
return;
|
||||
}
|
||||
|
||||
Harness.Compiler.doTypeAndSymbolBaseline(justName, result, toBeCompiled.concat(otherFiles).filter(file => !!result.program.getSourceFile(file.unitName)));
|
||||
Harness.Compiler.doTypeAndSymbolBaseline(justName, result.program, toBeCompiled.concat(otherFiles).filter(file => !!result.program.getSourceFile(file.unitName)));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
+78
-73
@@ -22,10 +22,6 @@
|
||||
namespace FourSlash {
|
||||
ts.disableIncrementalParsing = false;
|
||||
|
||||
function normalizeNewLines(s: string) {
|
||||
return s.replace(/\r\n/g, "\n");
|
||||
}
|
||||
|
||||
// Represents a parsed source file with metadata
|
||||
export interface FourSlashFile {
|
||||
// The contents of the file (with markers, etc stripped out)
|
||||
@@ -364,7 +360,7 @@ namespace FourSlash {
|
||||
baseIndentSize: 0,
|
||||
indentSize: 4,
|
||||
tabSize: 4,
|
||||
newLineCharacter: Harness.IO.newLine(),
|
||||
newLineCharacter: "\n",
|
||||
convertTabsToSpaces: true,
|
||||
indentStyle: ts.IndentStyle.Smart,
|
||||
insertSpaceAfterCommaDelimiter: true,
|
||||
@@ -1007,7 +1003,7 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public verifyReferenceGroups(startRanges: Range | Range[], parts: Array<{ definition: string, ranges: Range[] }>): void {
|
||||
public verifyReferenceGroups(startRanges: Range | Range[], parts: FourSlashInterface.ReferenceGroup[]): void {
|
||||
const fullExpected = ts.map(parts, ({ definition, ranges }) => ({ definition, ranges: ranges.map(rangeToReferenceEntry) }));
|
||||
|
||||
for (const startRange of toArray(startRanges)) {
|
||||
@@ -1603,7 +1599,7 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public printCurrentFileState(makeWhitespaceVisible: boolean, makeCaretVisible: boolean) {
|
||||
public printCurrentFileState(showWhitespace: boolean, makeCaretVisible: boolean) {
|
||||
for (const file of this.testData.files) {
|
||||
const active = (this.activeFile === file);
|
||||
Harness.IO.log(`=== Script (${file.fileName}) ${(active ? "(active, cursor at |)" : "")} ===`);
|
||||
@@ -1611,8 +1607,8 @@ namespace FourSlash {
|
||||
if (active) {
|
||||
content = content.substr(0, this.currentCaretPosition) + (makeCaretVisible ? "|" : "") + content.substr(this.currentCaretPosition);
|
||||
}
|
||||
if (makeWhitespaceVisible) {
|
||||
content = TestState.makeWhitespaceVisible(content);
|
||||
if (showWhitespace) {
|
||||
content = makeWhitespaceVisible(content);
|
||||
}
|
||||
Harness.IO.log(content);
|
||||
}
|
||||
@@ -2128,10 +2124,8 @@ namespace FourSlash {
|
||||
|
||||
public verifyCurrentFileContent(text: string) {
|
||||
const actual = this.getFileContent(this.activeFile.fileName);
|
||||
if (normalizeNewLines(actual) !== normalizeNewLines(text)) {
|
||||
throw new Error("verifyCurrentFileContent\n" +
|
||||
"\tExpected: \"" + TestState.makeWhitespaceVisible(text) + "\"\n" +
|
||||
"\t Actual: \"" + TestState.makeWhitespaceVisible(actual) + "\"");
|
||||
if (actual !== text) {
|
||||
throw new Error(`verifyCurrentFileContent failed:\n${showTextDiff(text, actual)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2305,11 +2299,11 @@ namespace FourSlash {
|
||||
const actualText = this.rangeText(ranges[0]);
|
||||
|
||||
const result = includeWhiteSpace
|
||||
? normalizeNewLines(actualText) === normalizeNewLines(expectedText)
|
||||
? actualText === expectedText
|
||||
: this.removeWhitespace(actualText) === this.removeWhitespace(expectedText);
|
||||
|
||||
if (!result) {
|
||||
this.raiseError(`Actual text doesn't match expected text. Actual:\n'${actualText}'\nExpected:\n'${expectedText}'`);
|
||||
this.raiseError(`Actual range text doesn't match expected text.\n${showTextDiff(expectedText, actualText)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2403,15 +2397,19 @@ namespace FourSlash {
|
||||
const originalContent = scriptInfo.content;
|
||||
for (const codeFix of codeFixes) {
|
||||
this.applyEdits(codeFix.changes[0].fileName, codeFix.changes[0].textChanges, /*isFormattingEdit*/ false);
|
||||
actualTextArray.push(this.normalizeNewlines(this.rangeText(ranges[0])));
|
||||
let text = this.rangeText(ranges[0]);
|
||||
// TODO:GH#18445 (remove this line to see errors in many `importNameCodeFix` tests)
|
||||
text = text.replace(/\r\n/g, "\n");
|
||||
actualTextArray.push(text);
|
||||
scriptInfo.updateContent(originalContent);
|
||||
}
|
||||
const sortedExpectedArray = ts.map(expectedTextArray, str => this.normalizeNewlines(str)).sort();
|
||||
const sortedExpectedArray = expectedTextArray.sort();
|
||||
const sortedActualArray = actualTextArray.sort();
|
||||
if (!ts.arrayIsEqualTo(sortedExpectedArray, sortedActualArray)) {
|
||||
this.raiseError(
|
||||
`Actual text array doesn't match expected text array. \nActual: \n'${sortedActualArray.join("\n\n")}'\n---\nExpected: \n'${sortedExpectedArray.join("\n\n")}'`);
|
||||
}
|
||||
ts.zipWith(sortedExpectedArray, sortedActualArray, (expected, actual, index) => {
|
||||
if (expected !== actual) {
|
||||
this.raiseError(`Import fix at index ${index} doesn't match.\n${showTextDiff(expected, actual)}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public verifyDocCommentTemplate(expected: ts.TextInsertion | undefined) {
|
||||
@@ -2431,7 +2429,7 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
if (actual.newText !== expected.newText) {
|
||||
this.raiseError(`${name} failed - expected insertion:\n"${this.clarifyNewlines(expected.newText)}"\nactual insertion:\n"${this.clarifyNewlines(actual.newText)}"`);
|
||||
this.raiseError(`${name} failed for expected insertion.\n${showTextDiff(expected.newText, actual.newText)}`);
|
||||
}
|
||||
|
||||
if (actual.caretOffset !== expected.caretOffset) {
|
||||
@@ -2440,17 +2438,6 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
private clarifyNewlines(str: string) {
|
||||
return str.replace(/\r?\n/g, lineEnding => {
|
||||
const representation = lineEnding === "\r\n" ? "CRLF" : "LF";
|
||||
return "# - " + representation + lineEnding;
|
||||
});
|
||||
}
|
||||
|
||||
private normalizeNewlines(str: string) {
|
||||
return str.replace(/\r?\n/g, "\n");
|
||||
}
|
||||
|
||||
public verifyBraceCompletionAtPosition(negative: boolean, openingBrace: string) {
|
||||
|
||||
const openBraceMap = ts.createMapFromTemplate<ts.CharacterCodes>({
|
||||
@@ -2584,20 +2571,29 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public verifyNavigationBar(json: any) {
|
||||
const items = this.languageService.getNavigationBarItems(this.activeFile.fileName);
|
||||
if (JSON.stringify(items, replacer) !== JSON.stringify(json)) {
|
||||
this.raiseError(`verifyNavigationBar failed - expected: ${stringify(json)}, got: ${stringify(items, replacer)}`);
|
||||
public verifyNavigationBar(json: any, options: { checkSpans?: boolean } | undefined) {
|
||||
this.verifyNavigationTreeOrBar(json, this.languageService.getNavigationBarItems(this.activeFile.fileName), "Bar", options);
|
||||
}
|
||||
|
||||
public verifyNavigationTree(json: any, options: { checkSpans?: boolean } | undefined) {
|
||||
this.verifyNavigationTreeOrBar(json, this.languageService.getNavigationTree(this.activeFile.fileName), "Tree", options);
|
||||
}
|
||||
|
||||
private verifyNavigationTreeOrBar(json: any, tree: any, name: "Tree" | "Bar", options: { checkSpans?: boolean } | undefined) {
|
||||
if (JSON.stringify(tree, replacer) !== JSON.stringify(json)) {
|
||||
this.raiseError(`verifyNavigation${name} failed - expected: ${stringify(json)}, got: ${stringify(tree, replacer)}`);
|
||||
}
|
||||
|
||||
// Make the data easier to read.
|
||||
function replacer(key: string, value: any) {
|
||||
switch (key) {
|
||||
case "spans":
|
||||
// We won't ever check this.
|
||||
return undefined;
|
||||
return options && options.checkSpans ? value : undefined;
|
||||
case "start":
|
||||
case "length":
|
||||
// Never omit the values in a span, even if they are 0.
|
||||
return value;
|
||||
case "childItems":
|
||||
return value.length === 0 ? undefined : value;
|
||||
return !value || value.length === 0 ? undefined : value;
|
||||
default:
|
||||
// Omit falsy values, those are presumed to be the default.
|
||||
return value || undefined;
|
||||
@@ -2605,18 +2601,6 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public verifyNavigationTree(json: any) {
|
||||
const tree = this.languageService.getNavigationTree(this.activeFile.fileName);
|
||||
if (JSON.stringify(tree, replacer) !== JSON.stringify(json)) {
|
||||
this.raiseError(`verifyNavigationTree failed - expected: ${stringify(json)}, got: ${stringify(tree, replacer)}`);
|
||||
}
|
||||
|
||||
function replacer(key: string, value: any) {
|
||||
// Don't check "spans", and omit falsy values.
|
||||
return key === "spans" ? undefined : (value || undefined);
|
||||
}
|
||||
}
|
||||
|
||||
public printNavigationItems(searchValue: string) {
|
||||
const items = this.languageService.getNavigateToItems(searchValue);
|
||||
Harness.IO.log(`NavigationItems list (${items.length} items)`);
|
||||
@@ -2878,8 +2862,8 @@ namespace FourSlash {
|
||||
}
|
||||
const actualContent = this.getFileContent(this.activeFile.fileName);
|
||||
|
||||
if (this.normalizeNewlines(actualContent) !== this.normalizeNewlines(expectedContent)) {
|
||||
this.raiseError(`verifyFileAfterApplyingRefactors failed: expected:\n${expectedContent}\nactual:\n${actualContent}`);
|
||||
if (actualContent !== expectedContent) {
|
||||
this.raiseError(`verifyFileAfterApplyingRefactors failed:\n${showTextDiff(expectedContent, actualContent)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3014,10 +2998,6 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
private static makeWhitespaceVisible(text: string) {
|
||||
return text.replace(/ /g, "\u00B7").replace(/\r/g, "\u00B6").replace(/\n/g, "\u2193\n").replace(/\t/g, "\u2192\ ");
|
||||
}
|
||||
|
||||
public setCancelled(numberOfCalls: number): void {
|
||||
this.cancellationToken.setCancelled(numberOfCalls);
|
||||
}
|
||||
@@ -3319,12 +3299,7 @@ ${code}
|
||||
let column = 1;
|
||||
|
||||
const flush = (lastSafeCharIndex: number) => {
|
||||
if (lastSafeCharIndex === undefined) {
|
||||
output = output + content.substr(lastNormalCharPosition);
|
||||
}
|
||||
else {
|
||||
output = output + content.substr(lastNormalCharPosition, lastSafeCharIndex - lastNormalCharPosition);
|
||||
}
|
||||
output = output + content.substr(lastNormalCharPosition, lastSafeCharIndex === undefined ? undefined : lastSafeCharIndex - lastNormalCharPosition);
|
||||
};
|
||||
|
||||
if (content.length > 0) {
|
||||
@@ -3511,6 +3486,27 @@ ${code}
|
||||
function toArray<T>(x: T | T[]): T[] {
|
||||
return ts.isArray(x) ? x : [x];
|
||||
}
|
||||
|
||||
function makeWhitespaceVisible(text: string) {
|
||||
return text.replace(/ /g, "\u00B7").replace(/\r/g, "\u00B6").replace(/\n/g, "\u2193\n").replace(/\t/g, "\u2192\ ");
|
||||
}
|
||||
|
||||
function showTextDiff(expected: string, actual: string): string {
|
||||
// Only show whitespace if the difference is whitespace-only.
|
||||
if (differOnlyByWhitespace(expected, actual)) {
|
||||
expected = makeWhitespaceVisible(expected);
|
||||
actual = makeWhitespaceVisible(actual);
|
||||
}
|
||||
return `Expected:\n${expected}\nActual:\n${actual}`;
|
||||
}
|
||||
|
||||
function differOnlyByWhitespace(a: string, b: string) {
|
||||
return stripWhitespace(a) === stripWhitespace(b);
|
||||
}
|
||||
|
||||
function stripWhitespace(s: string): string {
|
||||
return s.replace(/\s/g, "");
|
||||
}
|
||||
}
|
||||
|
||||
namespace FourSlashInterface {
|
||||
@@ -3534,6 +3530,10 @@ namespace FourSlashInterface {
|
||||
return this.state.getRanges();
|
||||
}
|
||||
|
||||
public spans(): ts.TextSpan[] {
|
||||
return this.ranges().map(r => ts.createTextSpan(r.start, r.end - r.start));
|
||||
}
|
||||
|
||||
public rangesByText(): ts.Map<FourSlash.Range[]> {
|
||||
return this.state.rangesByText();
|
||||
}
|
||||
@@ -3833,7 +3833,7 @@ namespace FourSlashInterface {
|
||||
this.state.verifyReferencesOf(start, references);
|
||||
}
|
||||
|
||||
public referenceGroups(startRanges: FourSlash.Range[], parts: Array<{ definition: string, ranges: FourSlash.Range[] }>) {
|
||||
public referenceGroups(startRanges: FourSlash.Range[], parts: ReferenceGroup[]) {
|
||||
this.state.verifyReferenceGroups(startRanges, parts);
|
||||
}
|
||||
|
||||
@@ -3967,12 +3967,12 @@ namespace FourSlashInterface {
|
||||
this.state.verifyImportFixAtPosition(expectedTextArray, errorCode);
|
||||
}
|
||||
|
||||
public navigationBar(json: any) {
|
||||
this.state.verifyNavigationBar(json);
|
||||
public navigationBar(json: any, options?: { checkSpans?: boolean }) {
|
||||
this.state.verifyNavigationBar(json, options);
|
||||
}
|
||||
|
||||
public navigationTree(json: any) {
|
||||
this.state.verifyNavigationTree(json);
|
||||
public navigationTree(json: any, options?: { checkSpans?: boolean }) {
|
||||
this.state.verifyNavigationTree(json, options);
|
||||
}
|
||||
|
||||
public navigationItemsListCount(count: number, searchValue: string, matchKind?: string, fileName?: string) {
|
||||
@@ -4143,15 +4143,15 @@ namespace FourSlashInterface {
|
||||
}
|
||||
|
||||
public printCurrentFileState() {
|
||||
this.state.printCurrentFileState(/*makeWhitespaceVisible*/ false, /*makeCaretVisible*/ true);
|
||||
this.state.printCurrentFileState(/*showWhitespace*/ false, /*makeCaretVisible*/ true);
|
||||
}
|
||||
|
||||
public printCurrentFileStateWithWhitespace() {
|
||||
this.state.printCurrentFileState(/*makeWhitespaceVisible*/ true, /*makeCaretVisible*/ true);
|
||||
this.state.printCurrentFileState(/*showWhitespace*/ true, /*makeCaretVisible*/ true);
|
||||
}
|
||||
|
||||
public printCurrentFileStateWithoutCaret() {
|
||||
this.state.printCurrentFileState(/*makeWhitespaceVisible*/ false, /*makeCaretVisible*/ false);
|
||||
this.state.printCurrentFileState(/*showWhitespace*/ false, /*makeCaretVisible*/ false);
|
||||
}
|
||||
|
||||
public printCurrentQuickInfo() {
|
||||
@@ -4344,6 +4344,11 @@ namespace FourSlashInterface {
|
||||
}
|
||||
}
|
||||
|
||||
export interface ReferenceGroup {
|
||||
definition: string;
|
||||
ranges: FourSlash.Range[];
|
||||
}
|
||||
|
||||
export interface ApplyRefactorOptions {
|
||||
refactorName: string;
|
||||
actionName: string;
|
||||
|
||||
+184
-72
@@ -148,6 +148,8 @@ namespace Utils {
|
||||
});
|
||||
}
|
||||
|
||||
export const canonicalizeForHarness = ts.createGetCanonicalFileName(/*caseSensitive*/ false); // This is done so tests work on windows _and_ linux
|
||||
|
||||
export function assertInvariants(node: ts.Node, parent: ts.Node): void {
|
||||
if (node) {
|
||||
assert.isFalse(node.pos < 0, "node.pos < 0");
|
||||
@@ -500,7 +502,8 @@ namespace Harness {
|
||||
export let IO: IO;
|
||||
|
||||
// harness always uses one kind of new line
|
||||
const harnessNewLine = "\r\n";
|
||||
// But note that `parseTestData` in `fourslash.ts` uses "\n"
|
||||
export const harnessNewLine = "\r\n";
|
||||
|
||||
// Root for file paths that are stored in a virtual file system
|
||||
export const virtualFileSystemRoot = "/";
|
||||
@@ -1294,11 +1297,25 @@ namespace Harness {
|
||||
}
|
||||
|
||||
export function getErrorBaseline(inputFiles: ReadonlyArray<TestFile>, diagnostics: ReadonlyArray<ts.Diagnostic>, pretty?: boolean) {
|
||||
let outputLines = "";
|
||||
const gen = iterateErrorBaseline(inputFiles, diagnostics, pretty);
|
||||
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
|
||||
const [, content] = value;
|
||||
outputLines += content;
|
||||
}
|
||||
return outputLines;
|
||||
}
|
||||
|
||||
export const diagnosticSummaryMarker = "__diagnosticSummary";
|
||||
export const globalErrorsMarker = "__globalErrors";
|
||||
export function *iterateErrorBaseline(inputFiles: ReadonlyArray<TestFile>, diagnostics: ReadonlyArray<ts.Diagnostic>, pretty?: boolean): IterableIterator<[string, string, number]> {
|
||||
diagnostics = diagnostics.slice().sort(ts.compareDiagnostics);
|
||||
let outputLines = "";
|
||||
// Count up all errors that were found in files other than lib.d.ts so we don't miss any
|
||||
let totalErrorsReportedInNonLibraryFiles = 0;
|
||||
|
||||
let errorsReported = 0;
|
||||
|
||||
let firstLine = true;
|
||||
function newLine() {
|
||||
if (firstLine) {
|
||||
@@ -1317,6 +1334,7 @@ namespace Harness {
|
||||
.filter(s => s.length > 0)
|
||||
.map(s => "!!! " + ts.DiagnosticCategory[error.category].toLowerCase() + " TS" + error.code + ": " + s);
|
||||
errLines.forEach(e => outputLines += (newLine() + e));
|
||||
errorsReported++;
|
||||
|
||||
// do not count errors from lib.d.ts here, they are computed separately as numLibraryDiagnostics
|
||||
// if lib.d.ts is explicitly included in input files and there are some errors in it (i.e. because of duplicate identifiers)
|
||||
@@ -1328,12 +1346,18 @@ namespace Harness {
|
||||
}
|
||||
}
|
||||
|
||||
yield [diagnosticSummaryMarker, minimalDiagnosticsToString(diagnostics, pretty) + Harness.IO.newLine() + Harness.IO.newLine(), diagnostics.length];
|
||||
|
||||
// Report global errors
|
||||
const globalErrors = diagnostics.filter(err => !err.file);
|
||||
globalErrors.forEach(outputErrorText);
|
||||
yield [globalErrorsMarker, outputLines, errorsReported];
|
||||
outputLines = "";
|
||||
errorsReported = 0;
|
||||
|
||||
// 'merge' the lines of each input file with any errors associated with it
|
||||
inputFiles.filter(f => f.content !== undefined).forEach(inputFile => {
|
||||
const dupeCase = ts.createMap<number>();
|
||||
for (const inputFile of inputFiles.filter(f => f.content !== undefined)) {
|
||||
// Filter down to the errors in the file
|
||||
const fileErrors = diagnostics.filter(e => {
|
||||
const errFn = e.file;
|
||||
@@ -1399,7 +1423,10 @@ namespace Harness {
|
||||
|
||||
// Verify we didn't miss any errors in this file
|
||||
assert.equal(markedErrorCount, fileErrors.length, "count of errors in " + inputFile.unitName);
|
||||
});
|
||||
yield [checkDuplicatedFileName(inputFile.unitName, dupeCase), outputLines, errorsReported];
|
||||
outputLines = "";
|
||||
errorsReported = 0;
|
||||
}
|
||||
|
||||
const numLibraryDiagnostics = ts.countWhere(diagnostics, diagnostic => {
|
||||
return diagnostic.file && (isDefaultLibraryFile(diagnostic.file.fileName) || isBuiltFile(diagnostic.file.fileName));
|
||||
@@ -1412,9 +1439,6 @@ namespace Harness {
|
||||
|
||||
// Verify we didn't miss any errors in total
|
||||
assert.equal(totalErrorsReportedInNonLibraryFiles + numLibraryDiagnostics + numTest262HarnessDiagnostics, diagnostics.length, "total number of errors");
|
||||
|
||||
return minimalDiagnosticsToString(diagnostics, pretty) +
|
||||
Harness.IO.newLine() + Harness.IO.newLine() + outputLines;
|
||||
}
|
||||
|
||||
export function doErrorBaseline(baselinePath: string, inputFiles: TestFile[], errors: ts.Diagnostic[], pretty?: boolean) {
|
||||
@@ -1428,10 +1452,7 @@ namespace Harness {
|
||||
});
|
||||
}
|
||||
|
||||
export function doTypeAndSymbolBaseline(baselinePath: string, result: CompilerResult, allFiles: {unitName: string, content: string}[], opts?: Harness.Baseline.BaselineOptions) {
|
||||
if (result.errors.length !== 0) {
|
||||
return;
|
||||
}
|
||||
export function doTypeAndSymbolBaseline(baselinePath: string, program: ts.Program, allFiles: {unitName: string, content: string}[], opts?: Harness.Baseline.BaselineOptions, multifile?: boolean, skipTypeAndSymbolbaselines?: boolean) {
|
||||
// The full walker simulates the types that you would get from doing a full
|
||||
// compile. The pull walker simulates the types you get when you just do
|
||||
// a type query for a random node (like how the LS would do it). Most of the
|
||||
@@ -1447,16 +1468,8 @@ namespace Harness {
|
||||
// These types are equivalent, but depend on what order the compiler observed
|
||||
// certain parts of the program.
|
||||
|
||||
const program = result.program;
|
||||
|
||||
const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true);
|
||||
|
||||
const fullResults = ts.createMap<TypeWriterResult[]>();
|
||||
|
||||
for (const sourceFile of allFiles) {
|
||||
fullResults.set(sourceFile.unitName, fullWalker.getTypeAndSymbols(sourceFile.unitName));
|
||||
}
|
||||
|
||||
// Produce baselines. The first gives the types for all expressions.
|
||||
// The second gives symbols for all identifiers.
|
||||
let typesError: Error, symbolsError: Error;
|
||||
@@ -1489,67 +1502,86 @@ namespace Harness {
|
||||
return;
|
||||
|
||||
function checkBaseLines(isSymbolBaseLine: boolean) {
|
||||
const fullBaseLine = generateBaseLine(fullResults, isSymbolBaseLine);
|
||||
|
||||
const fullExtension = isSymbolBaseLine ? ".symbols" : ".types";
|
||||
|
||||
// When calling this function from rwc-runner, the baselinePath will have no extension.
|
||||
// As rwc test- file is stored in json which ".json" will get stripped off.
|
||||
// When calling this function from compiler-runner, the baselinePath will then has either ".ts" or ".tsx" extension
|
||||
const outputFileName = ts.endsWith(baselinePath, ts.Extension.Ts) || ts.endsWith(baselinePath, ts.Extension.Tsx) ?
|
||||
baselinePath.replace(/\.tsx?/, fullExtension) : baselinePath.concat(fullExtension);
|
||||
Harness.Baseline.runBaseline(outputFileName, () => fullBaseLine, opts);
|
||||
baselinePath.replace(/\.tsx?/, "") : baselinePath;
|
||||
|
||||
if (!multifile) {
|
||||
const fullBaseLine = generateBaseLine(isSymbolBaseLine, skipTypeAndSymbolbaselines);
|
||||
Harness.Baseline.runBaseline(outputFileName + fullExtension, () => fullBaseLine, opts);
|
||||
}
|
||||
else {
|
||||
Harness.Baseline.runMultifileBaseline(outputFileName, fullExtension, () => {
|
||||
return iterateBaseLine(isSymbolBaseLine, skipTypeAndSymbolbaselines);
|
||||
}, opts);
|
||||
}
|
||||
}
|
||||
|
||||
function generateBaseLine(typeWriterResults: ts.Map<TypeWriterResult[]>, isSymbolBaseline: boolean): string {
|
||||
const typeLines: string[] = [];
|
||||
const typeMap: { [fileName: string]: { [lineNum: number]: string[]; } } = {};
|
||||
function generateBaseLine(isSymbolBaseline: boolean, skipTypeAndSymbolbaselines?: boolean): string {
|
||||
let result = "";
|
||||
const gen = iterateBaseLine(isSymbolBaseline, skipTypeAndSymbolbaselines);
|
||||
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
|
||||
const [, content] = value;
|
||||
result += content;
|
||||
}
|
||||
/* tslint:disable:no-null-keyword */
|
||||
return result || null;
|
||||
/* tslint:enable:no-null-keyword */
|
||||
}
|
||||
|
||||
allFiles.forEach(file => {
|
||||
const codeLines = file.content.split("\n");
|
||||
typeWriterResults.get(file.unitName).forEach(result => {
|
||||
function *iterateBaseLine(isSymbolBaseline: boolean, skipTypeAndSymbolbaselines?: boolean): IterableIterator<[string, string]> {
|
||||
if (skipTypeAndSymbolbaselines) {
|
||||
return;
|
||||
}
|
||||
const dupeCase = ts.createMap<number>();
|
||||
|
||||
for (const file of allFiles) {
|
||||
const { unitName } = file;
|
||||
let typeLines = "=== " + unitName + " ===\r\n";
|
||||
const codeLines = ts.flatMap(file.content.split(/\r?\n/g), e => e.split(/[\r\u2028\u2029]/g));
|
||||
const gen: IterableIterator<TypeWriterResult> = isSymbolBaseline ? fullWalker.getSymbols(unitName) : fullWalker.getTypes(unitName);
|
||||
let lastIndexWritten: number | undefined;
|
||||
for (let {done, value: result} = gen.next(); !done; { done, value: result } = gen.next()) {
|
||||
if (isSymbolBaseline && !result.symbol) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastIndexWritten === undefined) {
|
||||
typeLines += codeLines.slice(0, result.line + 1).join("\r\n") + "\r\n";
|
||||
}
|
||||
else if (result.line !== lastIndexWritten) {
|
||||
if (!((lastIndexWritten + 1 < codeLines.length) && (codeLines[lastIndexWritten + 1].match(/^\s*[{|}]\s*$/) || codeLines[lastIndexWritten + 1].trim() === ""))) {
|
||||
typeLines += "\r\n";
|
||||
}
|
||||
typeLines += codeLines.slice(lastIndexWritten + 1, result.line + 1).join("\r\n") + "\r\n";
|
||||
}
|
||||
lastIndexWritten = result.line;
|
||||
const typeOrSymbolString = isSymbolBaseline ? result.symbol : result.type;
|
||||
const formattedLine = result.sourceText.replace(/\r?\n/g, "") + " : " + typeOrSymbolString;
|
||||
if (!typeMap[file.unitName]) {
|
||||
typeMap[file.unitName] = {};
|
||||
}
|
||||
typeLines += ">" + formattedLine + "\r\n";
|
||||
}
|
||||
|
||||
let typeInfo = [formattedLine];
|
||||
const existingTypeInfo = typeMap[file.unitName][result.line];
|
||||
if (existingTypeInfo) {
|
||||
typeInfo = existingTypeInfo.concat(typeInfo);
|
||||
}
|
||||
typeMap[file.unitName][result.line] = typeInfo;
|
||||
});
|
||||
|
||||
typeLines.push("=== " + file.unitName + " ===\r\n");
|
||||
for (let i = 0; i < codeLines.length; i++) {
|
||||
const currentCodeLine = codeLines[i];
|
||||
typeLines.push(currentCodeLine + "\r\n");
|
||||
if (typeMap[file.unitName]) {
|
||||
const typeInfo = typeMap[file.unitName][i];
|
||||
if (typeInfo) {
|
||||
typeInfo.forEach(ty => {
|
||||
typeLines.push(">" + ty + "\r\n");
|
||||
});
|
||||
if (i + 1 < codeLines.length && (codeLines[i + 1].match(/^\s*[{|}]\s*$/) || codeLines[i + 1].trim() === "")) {
|
||||
}
|
||||
else {
|
||||
typeLines.push("\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
typeLines.push("No type information for this code.");
|
||||
// Preserve legacy behavior
|
||||
if (lastIndexWritten === undefined) {
|
||||
for (let i = 0; i < codeLines.length; i++) {
|
||||
const currentCodeLine = codeLines[i];
|
||||
typeLines += currentCodeLine + "\r\n";
|
||||
typeLines += "No type information for this code.";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return typeLines.join("");
|
||||
else {
|
||||
if (lastIndexWritten + 1 < codeLines.length) {
|
||||
if (!((lastIndexWritten + 1 < codeLines.length) && (codeLines[lastIndexWritten + 1].match(/^\s*[{|}]\s*$/) || codeLines[lastIndexWritten + 1].trim() === ""))) {
|
||||
typeLines += "\r\n";
|
||||
}
|
||||
typeLines += codeLines.slice(lastIndexWritten + 1).join("\r\n");
|
||||
}
|
||||
typeLines += "\r\n";
|
||||
}
|
||||
yield [checkDuplicatedFileName(unitName, dupeCase), typeLines];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1645,24 +1677,29 @@ namespace Harness {
|
||||
}
|
||||
|
||||
export function collateOutputs(outputFiles: Harness.Compiler.GeneratedFile[]): string {
|
||||
// Collect, test, and sort the fileNames
|
||||
outputFiles.sort((a, b) => ts.compareStrings(cleanName(a.fileName), cleanName(b.fileName)));
|
||||
|
||||
const gen = iterateOutputs(outputFiles);
|
||||
// Emit them
|
||||
let result = "";
|
||||
for (const outputFile of outputFiles) {
|
||||
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
|
||||
// Some extra spacing if this isn't the first file
|
||||
if (result.length) {
|
||||
result += "\r\n\r\n";
|
||||
}
|
||||
|
||||
// FileName header + content
|
||||
result += "/*====== " + outputFile.fileName + " ======*/\r\n";
|
||||
|
||||
result += outputFile.code;
|
||||
const [, content] = value;
|
||||
result += content;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function *iterateOutputs(outputFiles: Harness.Compiler.GeneratedFile[]): IterableIterator<[string, string]> {
|
||||
// Collect, test, and sort the fileNames
|
||||
outputFiles.sort((a, b) => ts.compareStrings(cleanName(a.fileName), cleanName(b.fileName)));
|
||||
const dupeCase = ts.createMap<number>();
|
||||
// Yield them
|
||||
for (const outputFile of outputFiles) {
|
||||
yield [checkDuplicatedFileName(outputFile.fileName, dupeCase), "/*====== " + outputFile.fileName + " ======*/\r\n" + outputFile.code];
|
||||
}
|
||||
|
||||
function cleanName(fn: string) {
|
||||
const lastSlash = ts.normalizeSlashes(fn).lastIndexOf("/");
|
||||
@@ -1670,6 +1707,24 @@ namespace Harness {
|
||||
}
|
||||
}
|
||||
|
||||
function checkDuplicatedFileName(resultName: string, dupeCase: ts.Map<number>): string {
|
||||
resultName = sanitizeTestFilePath(resultName);
|
||||
if (dupeCase.has(resultName)) {
|
||||
// A different baseline filename should be manufactured if the names differ only in case, for windows compat
|
||||
const count = 1 + dupeCase.get(resultName);
|
||||
dupeCase.set(resultName, count);
|
||||
resultName = `${resultName}.dupe${count}`;
|
||||
}
|
||||
else {
|
||||
dupeCase.set(resultName, 0);
|
||||
}
|
||||
return resultName;
|
||||
}
|
||||
|
||||
function sanitizeTestFilePath(name: string) {
|
||||
return ts.toPath(ts.normalizeSlashes(name.replace(/[\^<>:"|?*%]/g, "_")).replace(/\.\.\//g, "__dotdot/"), "", Utils.canonicalizeForHarness);
|
||||
}
|
||||
|
||||
// This does not need to exist strictly speaking, but many tests will need to be updated if it's removed
|
||||
export function compileString(_code: string, _unitName: string, _callback: (result: CompilerResult) => void) {
|
||||
// NEWTODO: Re-implement 'compileString'
|
||||
@@ -2007,6 +2062,63 @@ namespace Harness {
|
||||
const comparison = compareToBaseline(actual, relativeFileName, opts);
|
||||
writeComparison(comparison.expected, comparison.actual, relativeFileName, actualFileName);
|
||||
}
|
||||
|
||||
export function runMultifileBaseline(relativeFileBase: string, extension: string, generateContent: () => IterableIterator<[string, string, number]> | IterableIterator<[string, string]>, opts?: BaselineOptions, referencedExtensions?: string[]): void {
|
||||
const gen = generateContent();
|
||||
const writtenFiles = ts.createMap<true>();
|
||||
/* tslint:disable-next-line:no-null-keyword */
|
||||
const errors: Error[] = [];
|
||||
if (gen !== null) {
|
||||
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
|
||||
const [name, content, count] = value as [string, string, number | undefined];
|
||||
if (count === 0) continue; // Allow error reporter to skip writing files without errors
|
||||
const relativeFileName = relativeFileBase + (ts.startsWith(name, "/") ? "" : "/") + name + extension;
|
||||
const actualFileName = localPath(relativeFileName, opts && opts.Baselinefolder, opts && opts.Subfolder);
|
||||
const comparison = compareToBaseline(content, relativeFileName, opts);
|
||||
try {
|
||||
writeComparison(comparison.expected, comparison.actual, relativeFileName, actualFileName);
|
||||
}
|
||||
catch (e) {
|
||||
errors.push(e);
|
||||
}
|
||||
writtenFiles.set(relativeFileName, true);
|
||||
}
|
||||
}
|
||||
|
||||
const referenceDir = referencePath(relativeFileBase, opts && opts.Baselinefolder, opts && opts.Subfolder);
|
||||
let existing = Harness.IO.readDirectory(referenceDir, referencedExtensions || [extension]);
|
||||
if (extension === ".ts" || referencedExtensions && referencedExtensions.indexOf(".ts") > -1 && referencedExtensions.indexOf(".d.ts") === -1) {
|
||||
// special-case and filter .d.ts out of .ts results
|
||||
existing = existing.filter(f => !ts.endsWith(f, ".d.ts"));
|
||||
}
|
||||
const missing: string[] = [];
|
||||
for (const name of existing) {
|
||||
const localCopy = name.substring(referenceDir.length - relativeFileBase.length);
|
||||
if (!writtenFiles.has(localCopy)) {
|
||||
missing.push(localCopy);
|
||||
}
|
||||
}
|
||||
if (missing.length) {
|
||||
for (const file of missing) {
|
||||
IO.writeFile(localPath(file + ".delete", opts && opts.Baselinefolder, opts && opts.Subfolder), "");
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.length || missing.length) {
|
||||
let errorMsg = "";
|
||||
if (errors.length) {
|
||||
errorMsg += `The baseline for ${relativeFileBase} in ${errors.length} files has changed:${"\n " + errors.slice(0, 5).map(e => e.message).join("\n ") + (errors.length > 5 ? "\n" + ` and ${errors.length - 5} more` : "")}`;
|
||||
}
|
||||
if (errors.length && missing.length) {
|
||||
errorMsg += "\n";
|
||||
}
|
||||
if (missing.length) {
|
||||
const writtenFilesArray = ts.arrayFrom(writtenFiles.keys());
|
||||
errorMsg += `Baseline missing ${missing.length} files:${"\n " + missing.slice(0, 5).join("\n ") + (missing.length > 5 ? "\n" + ` and ${missing.length - 5} more` : "") + "\n"}Written ${writtenFiles.size} files:${"\n " + writtenFilesArray.slice(0, 5).join("\n ") + (writtenFilesArray.length > 5 ? "\n" + ` and ${writtenFilesArray.length - 5} more` : "")}`;
|
||||
}
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function isDefaultLibraryFile(filePath: string): boolean {
|
||||
|
||||
@@ -130,7 +130,7 @@ namespace Harness.LanguageService {
|
||||
}
|
||||
|
||||
public getNewLine(): string {
|
||||
return "\r\n";
|
||||
return harnessNewLine;
|
||||
}
|
||||
|
||||
public getFilenames(): string[] {
|
||||
|
||||
@@ -0,0 +1,481 @@
|
||||
if (typeof describe === "undefined") {
|
||||
(global as any).describe = undefined; // If launched without mocha for parallel mode, we still need a global describe visible to satisfy the parsing of the unit tests
|
||||
(global as any).it = undefined;
|
||||
}
|
||||
namespace Harness.Parallel.Host {
|
||||
|
||||
interface ChildProcessPartial {
|
||||
send(message: ParallelHostMessage, callback?: (error: Error) => void): boolean;
|
||||
on(event: "error", listener: (err: Error) => void): this;
|
||||
on(event: "exit", listener: (code: number, signal: string) => void): this;
|
||||
on(event: "message", listener: (message: ParallelClientMessage) => void): this;
|
||||
}
|
||||
|
||||
interface ProgressBarsOptions {
|
||||
open: string;
|
||||
close: string;
|
||||
complete: string;
|
||||
incomplete: string;
|
||||
width: number;
|
||||
noColors: boolean;
|
||||
}
|
||||
interface ProgressBar {
|
||||
lastN?: number;
|
||||
title?: string;
|
||||
progressColor?: string;
|
||||
text?: string;
|
||||
}
|
||||
|
||||
const perfdataFileNameFragment = ".parallelperf";
|
||||
function perfdataFileName(target?: string) {
|
||||
return `${perfdataFileNameFragment}${target ? `.${target}` : ""}.json`;
|
||||
}
|
||||
function readSavedPerfData(target?: string): {[testHash: string]: number} {
|
||||
const perfDataContents = Harness.IO.readFile(perfdataFileName(target));
|
||||
if (perfDataContents) {
|
||||
return JSON.parse(perfDataContents);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function hashName(runner: TestRunnerKind, test: string) {
|
||||
return `tsrunner-${runner}://${test}`;
|
||||
}
|
||||
|
||||
export function start() {
|
||||
initializeProgressBarsDependencies();
|
||||
console.log("Discovering tests...");
|
||||
const discoverStart = +(new Date());
|
||||
const { statSync }: { statSync(path: string): { size: number }; } = require("fs");
|
||||
let tasks: { runner: TestRunnerKind, file: string, size: number }[] = [];
|
||||
const newTasks: { runner: TestRunnerKind, file: string, size: number }[] = [];
|
||||
const perfData = readSavedPerfData(configOption);
|
||||
let totalCost = 0;
|
||||
let unknownValue: string | undefined;
|
||||
for (const runner of runners) {
|
||||
const files = runner.enumerateTestFiles();
|
||||
for (const file of files) {
|
||||
let size: number;
|
||||
if (!perfData) {
|
||||
size = statSync(file).size;
|
||||
|
||||
}
|
||||
else {
|
||||
const hashedName = hashName(runner.kind(), file);
|
||||
size = perfData[hashedName];
|
||||
if (size === undefined) {
|
||||
size = 0;
|
||||
unknownValue = hashedName;
|
||||
newTasks.push({ runner: runner.kind(), file, size });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
tasks.push({ runner: runner.kind(), file, size });
|
||||
totalCost += size;
|
||||
}
|
||||
}
|
||||
tasks.sort((a, b) => a.size - b.size);
|
||||
tasks = tasks.concat(newTasks);
|
||||
// 1 fewer batches than threads to account for unittests running on the final thread
|
||||
const batchCount = runners.length === 1 ? workerCount : workerCount - 1;
|
||||
const packfraction = 0.9;
|
||||
const chunkSize = 1000; // ~1KB or 1s for sending batches near the end of a test
|
||||
const batchSize = (totalCost / workerCount) * packfraction; // Keep spare tests for unittest thread in reserve
|
||||
console.log(`Discovered ${tasks.length} test files in ${+(new Date()) - discoverStart}ms.`);
|
||||
console.log(`Starting to run tests using ${workerCount} threads...`);
|
||||
const { fork }: { fork(modulePath: string, args?: string[], options?: {}): ChildProcessPartial; } = require("child_process");
|
||||
|
||||
const totalFiles = tasks.length;
|
||||
let passingFiles = 0;
|
||||
let failingFiles = 0;
|
||||
let errorResults: ErrorInfo[] = [];
|
||||
let totalPassing = 0;
|
||||
const startTime = Date.now();
|
||||
|
||||
const progressBars = new ProgressBars({ noColors });
|
||||
const progressUpdateInterval = 1 / progressBars._options.width;
|
||||
let nextProgress = progressUpdateInterval;
|
||||
|
||||
const newPerfData: {[testHash: string]: number} = {};
|
||||
|
||||
const workers: ChildProcessPartial[] = [];
|
||||
let closedWorkers = 0;
|
||||
for (let i = 0; i < workerCount; i++) {
|
||||
// TODO: Just send the config over the IPC channel or in the command line arguments
|
||||
const config: TestConfig = { light: Harness.lightMode, listenForWork: true, runUnitTests: runners.length === 1 ? false : i === workerCount - 1 };
|
||||
const configPath = ts.combinePaths(taskConfigsFolder, `task-config${i}.json`);
|
||||
Harness.IO.writeFile(configPath, JSON.stringify(config));
|
||||
const child = fork(__filename, [`--config="${configPath}"`]);
|
||||
child.on("error", err => {
|
||||
console.error("Unexpected error in child process:");
|
||||
console.error(err);
|
||||
return process.exit(2);
|
||||
});
|
||||
child.on("exit", (code, _signal) => {
|
||||
if (code !== 0) {
|
||||
console.error("Test worker process exited with nonzero exit code!");
|
||||
return process.exit(2);
|
||||
}
|
||||
});
|
||||
child.on("message", (data: ParallelClientMessage) => {
|
||||
switch (data.type) {
|
||||
case "error": {
|
||||
console.error(`Test worker encounted unexpected error${data.payload.name ? ` during the execution of test ${data.payload.name}` : ""} and was forced to close:
|
||||
Message: ${data.payload.error}
|
||||
Stack: ${data.payload.stack}`);
|
||||
return process.exit(2);
|
||||
}
|
||||
case "progress":
|
||||
case "result": {
|
||||
totalPassing += data.payload.passing;
|
||||
if (data.payload.errors.length) {
|
||||
errorResults = errorResults.concat(data.payload.errors);
|
||||
failingFiles++;
|
||||
}
|
||||
else {
|
||||
passingFiles++;
|
||||
}
|
||||
newPerfData[hashName(data.payload.runner, data.payload.file)] = data.payload.duration;
|
||||
|
||||
const progress = (failingFiles + passingFiles) / totalFiles;
|
||||
if (progress >= nextProgress) {
|
||||
while (nextProgress < progress) {
|
||||
nextProgress += progressUpdateInterval;
|
||||
}
|
||||
updateProgress(progress, errorResults.length ? `${errorResults.length} failing` : `${totalPassing} passing`, errorResults.length ? "fail" : undefined);
|
||||
}
|
||||
|
||||
if (data.type === "result") {
|
||||
if (tasks.length === 0) {
|
||||
// No more tasks to distribute
|
||||
child.send({ type: "close" });
|
||||
closedWorkers++;
|
||||
if (closedWorkers === workerCount) {
|
||||
outputFinalResult();
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Send tasks in blocks if the tasks are small
|
||||
const taskList = [tasks.pop()];
|
||||
while (tasks.length && taskList.reduce((p, c) => p + c.size, 0) < chunkSize) {
|
||||
taskList.push(tasks.pop());
|
||||
}
|
||||
if (taskList.length === 1) {
|
||||
child.send({ type: "test", payload: taskList[0] });
|
||||
}
|
||||
else {
|
||||
child.send({ type: "batch", payload: taskList });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
workers.push(child);
|
||||
}
|
||||
|
||||
// It's only really worth doing an initial batching if there are a ton of files to go through
|
||||
if (totalFiles > 1000) {
|
||||
console.log("Batching initial test lists...");
|
||||
const batches: { runner: TestRunnerKind, file: string, size: number }[][] = new Array(batchCount);
|
||||
const doneBatching = new Array(batchCount);
|
||||
let scheduledTotal = 0;
|
||||
batcher: while (true) {
|
||||
for (let i = 0; i < batchCount; i++) {
|
||||
if (tasks.length <= workerCount) { // Keep a small reserve even in the suboptimally packed case
|
||||
console.log(`Suboptimal packing detected: no tests remain to be stolen. Reduce packing fraction from ${packfraction} to fix.`);
|
||||
break batcher;
|
||||
}
|
||||
if (doneBatching[i]) {
|
||||
continue;
|
||||
}
|
||||
if (!batches[i]) {
|
||||
batches[i] = [];
|
||||
}
|
||||
const total = batches[i].reduce((p, c) => p + c.size, 0);
|
||||
if (total >= batchSize) {
|
||||
doneBatching[i] = true;
|
||||
continue;
|
||||
}
|
||||
const task = tasks.pop();
|
||||
batches[i].push(task);
|
||||
scheduledTotal += task.size;
|
||||
}
|
||||
for (let j = 0; j < batchCount; j++) {
|
||||
if (!doneBatching[j]) {
|
||||
continue batcher;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
const prefix = `Batched into ${batchCount} groups`;
|
||||
if (unknownValue) {
|
||||
console.log(`${prefix}. Unprofiled tests including ${unknownValue} will be run first.`);
|
||||
}
|
||||
else {
|
||||
console.log(`${prefix} with approximate total ${perfData ? "time" : "file sizes"} of ${perfData ? ms(batchSize) : `${Math.floor(batchSize)} bytes`} in each group. (${(scheduledTotal / totalCost * 100).toFixed(1)}% of total tests batched)`);
|
||||
}
|
||||
for (const worker of workers) {
|
||||
const payload = batches.pop();
|
||||
if (payload) {
|
||||
worker.send({ type: "batch", payload });
|
||||
}
|
||||
else { // Unittest thread - send off just one test
|
||||
const payload = tasks.pop();
|
||||
ts.Debug.assert(!!payload); // The reserve kept above should ensure there is always an initial task available, even in suboptimal scenarios
|
||||
worker.send({ type: "test", payload });
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (let i = 0; i < workerCount; i++) {
|
||||
workers[i].send({ type: "test", payload: tasks.pop() });
|
||||
}
|
||||
}
|
||||
|
||||
progressBars.enable();
|
||||
updateProgress(0);
|
||||
let duration: number;
|
||||
|
||||
function completeBar() {
|
||||
const isPartitionFail = failingFiles !== 0;
|
||||
const summaryColor = isPartitionFail ? "fail" : "green";
|
||||
const summarySymbol = isPartitionFail ? Base.symbols.err : Base.symbols.ok;
|
||||
|
||||
const summaryTests = (isPartitionFail ? totalPassing + "/" + (errorResults.length + totalPassing) : totalPassing) + " passing";
|
||||
const summaryDuration = "(" + ms(duration) + ")";
|
||||
const savedUseColors = Base.useColors;
|
||||
Base.useColors = !noColors;
|
||||
|
||||
const summary = color(summaryColor, summarySymbol + " " + summaryTests) + " " + color("light", summaryDuration);
|
||||
Base.useColors = savedUseColors;
|
||||
|
||||
updateProgress(1, summary);
|
||||
}
|
||||
|
||||
function updateProgress(percentComplete: number, title?: string, titleColor?: string) {
|
||||
let progressColor = "pending";
|
||||
if (failingFiles) {
|
||||
progressColor = "fail";
|
||||
}
|
||||
|
||||
progressBars.update(
|
||||
0,
|
||||
percentComplete,
|
||||
progressColor,
|
||||
title,
|
||||
titleColor
|
||||
);
|
||||
}
|
||||
|
||||
function outputFinalResult() {
|
||||
duration = Date.now() - startTime;
|
||||
completeBar();
|
||||
progressBars.disable();
|
||||
|
||||
const reporter = new Base();
|
||||
const stats = reporter.stats;
|
||||
const failures = reporter.failures;
|
||||
stats.passes = totalPassing;
|
||||
stats.failures = errorResults.length;
|
||||
stats.tests = totalPassing + errorResults.length;
|
||||
stats.duration = duration;
|
||||
for (let j = 0; j < errorResults.length; j++) {
|
||||
const failure = errorResults[j];
|
||||
failures.push(makeMochaTest(failure));
|
||||
}
|
||||
if (noColors) {
|
||||
const savedUseColors = Base.useColors;
|
||||
Base.useColors = false;
|
||||
reporter.epilogue();
|
||||
Base.useColors = savedUseColors;
|
||||
}
|
||||
else {
|
||||
reporter.epilogue();
|
||||
}
|
||||
|
||||
Harness.IO.writeFile(perfdataFileName(configOption), JSON.stringify(newPerfData, null, 4)); // tslint:disable-line:no-null-keyword
|
||||
|
||||
process.exit(errorResults.length);
|
||||
}
|
||||
|
||||
function makeMochaTest(test: ErrorInfo) {
|
||||
return {
|
||||
fullTitle: () => {
|
||||
return test.name;
|
||||
},
|
||||
err: {
|
||||
message: test.error,
|
||||
stack: test.stack
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe = ts.noop as any; // Disable unit tests
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let Mocha: any;
|
||||
let Base: any;
|
||||
let color: any;
|
||||
let cursor: any;
|
||||
let readline: any;
|
||||
let os: any;
|
||||
let tty: { isatty(x: number): boolean };
|
||||
let isatty: boolean;
|
||||
|
||||
const s = 1000;
|
||||
const m = s * 60;
|
||||
const h = m * 60;
|
||||
const d = h * 24;
|
||||
function ms(ms: number) {
|
||||
let result = "";
|
||||
if (ms >= d) {
|
||||
const count = Math.floor(ms / d);
|
||||
result += count + "d";
|
||||
ms -= count * d;
|
||||
}
|
||||
if (ms >= h) {
|
||||
const count = Math.floor(ms / h);
|
||||
result += count + "h";
|
||||
ms -= count * h;
|
||||
}
|
||||
if (ms >= m) {
|
||||
const count = Math.floor(ms / m);
|
||||
result += count + "m";
|
||||
ms -= count * m;
|
||||
}
|
||||
if (ms >= s) {
|
||||
const count = Math.round(ms / s);
|
||||
result += count + "s";
|
||||
return result;
|
||||
}
|
||||
if (ms > 0) {
|
||||
result += Math.round(ms) + "ms";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function initializeProgressBarsDependencies() {
|
||||
Mocha = require("mocha");
|
||||
Base = Mocha.reporters.Base;
|
||||
color = Base.color;
|
||||
cursor = Base.cursor;
|
||||
readline = require("readline");
|
||||
os = require("os");
|
||||
tty = require("tty");
|
||||
isatty = tty.isatty(1) && tty.isatty(2);
|
||||
}
|
||||
|
||||
class ProgressBars {
|
||||
public readonly _options: Readonly<ProgressBarsOptions>;
|
||||
private _enabled: boolean;
|
||||
private _lineCount: number;
|
||||
private _progressBars: ProgressBar[];
|
||||
constructor(options?: Partial<ProgressBarsOptions>) {
|
||||
if (!options) options = {};
|
||||
const open = options.open || "[";
|
||||
const close = options.close || "]";
|
||||
const complete = options.complete || "▬";
|
||||
const incomplete = options.incomplete || Base.symbols.dot;
|
||||
const maxWidth = Base.window.width - open.length - close.length - 34;
|
||||
const width = minMax(options.width || maxWidth, 10, maxWidth);
|
||||
this._options = {
|
||||
open,
|
||||
complete,
|
||||
incomplete,
|
||||
close,
|
||||
width,
|
||||
noColors: options.noColors || false
|
||||
};
|
||||
|
||||
this._progressBars = [];
|
||||
this._lineCount = 0;
|
||||
this._enabled = false;
|
||||
}
|
||||
enable() {
|
||||
if (!this._enabled) {
|
||||
process.stdout.write(os.EOL);
|
||||
this._enabled = true;
|
||||
}
|
||||
}
|
||||
disable() {
|
||||
if (this._enabled) {
|
||||
process.stdout.write(os.EOL);
|
||||
this._enabled = false;
|
||||
}
|
||||
}
|
||||
update(index: number, percentComplete: number, color: string, title: string, titleColor?: string) {
|
||||
percentComplete = minMax(percentComplete, 0, 1);
|
||||
|
||||
const progressBar = this._progressBars[index] || (this._progressBars[index] = { });
|
||||
const width = this._options.width;
|
||||
const n = Math.floor(width * percentComplete);
|
||||
const i = width - n;
|
||||
if (n === progressBar.lastN && title === progressBar.title && color === progressBar.progressColor) {
|
||||
return;
|
||||
}
|
||||
|
||||
progressBar.lastN = n;
|
||||
progressBar.title = title;
|
||||
progressBar.progressColor = color;
|
||||
|
||||
let progress = " ";
|
||||
progress += this._color("progress", this._options.open);
|
||||
progress += this._color(color, fill(this._options.complete, n));
|
||||
progress += this._color("progress", fill(this._options.incomplete, i));
|
||||
progress += this._color("progress", this._options.close);
|
||||
|
||||
if (title) {
|
||||
progress += this._color(titleColor || "progress", " " + title);
|
||||
}
|
||||
|
||||
if (progressBar.text !== progress) {
|
||||
progressBar.text = progress;
|
||||
this._render(index);
|
||||
}
|
||||
}
|
||||
private _render(index: number) {
|
||||
if (!this._enabled || !isatty) {
|
||||
return;
|
||||
}
|
||||
|
||||
cursor.hide();
|
||||
readline.moveCursor(process.stdout, -process.stdout.columns, -this._lineCount);
|
||||
let lineCount = 0;
|
||||
const numProgressBars = this._progressBars.length;
|
||||
for (let i = 0; i < numProgressBars; i++) {
|
||||
if (i === index) {
|
||||
readline.clearLine(process.stdout, 1);
|
||||
process.stdout.write(this._progressBars[i].text + os.EOL);
|
||||
}
|
||||
else {
|
||||
readline.moveCursor(process.stdout, -process.stdout.columns, +1);
|
||||
}
|
||||
|
||||
lineCount++;
|
||||
}
|
||||
|
||||
this._lineCount = lineCount;
|
||||
cursor.show();
|
||||
}
|
||||
private _color(type: string, text: string) {
|
||||
return type && !this._options.noColors ? color(type, text) : text;
|
||||
}
|
||||
}
|
||||
|
||||
function fill(ch: string, size: number) {
|
||||
let s = "";
|
||||
while (s.length < size) {
|
||||
s += ch;
|
||||
}
|
||||
|
||||
return s.length > size ? s.substr(0, size) : s;
|
||||
}
|
||||
|
||||
function minMax(value: number, min: number, max: number) {
|
||||
if (value < min) return min;
|
||||
if (value > max) return max;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/// <reference path="./host.ts" />
|
||||
/// <reference path="./worker.ts" />
|
||||
namespace Harness.Parallel {
|
||||
export type ParallelTestMessage = { type: "test", payload: { runner: TestRunnerKind, file: string } } | never;
|
||||
export type ParallelBatchMessage = { type: "batch", payload: ParallelTestMessage["payload"][] } | never;
|
||||
export type ParallelCloseMessage = { type: "close" } | never;
|
||||
export type ParallelHostMessage = ParallelTestMessage | ParallelCloseMessage | ParallelBatchMessage;
|
||||
|
||||
export type ParallelErrorMessage = { type: "error", payload: { error: string, stack: string, name?: string } } | never;
|
||||
export type ErrorInfo = ParallelErrorMessage["payload"] & { name: string };
|
||||
export type ParallelResultMessage = { type: "result", payload: { passing: number, errors: ErrorInfo[], duration: number, runner: TestRunnerKind, file: string } } | never;
|
||||
export type ParallelBatchProgressMessage = { type: "progress", payload: ParallelResultMessage["payload"] } | never;
|
||||
export type ParallelClientMessage = ParallelErrorMessage | ParallelResultMessage | ParallelBatchProgressMessage;
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
namespace Harness.Parallel.Worker {
|
||||
let errors: ErrorInfo[] = [];
|
||||
let passing = 0;
|
||||
let reportedUnitTests = false;
|
||||
|
||||
type Executor = {name: string, callback: Function, kind: "suite" | "test"} | never;
|
||||
|
||||
function resetShimHarnessAndExecute(runner: RunnerBase) {
|
||||
if (reportedUnitTests) {
|
||||
errors = [];
|
||||
passing = 0;
|
||||
testList.length = 0;
|
||||
}
|
||||
reportedUnitTests = true;
|
||||
const start = +(new Date());
|
||||
runner.initializeTests();
|
||||
testList.forEach(({ name, callback, kind }) => executeCallback(name, callback, kind));
|
||||
return { errors, passing, duration: +(new Date()) - start };
|
||||
}
|
||||
|
||||
|
||||
let beforeEachFunc: Function;
|
||||
const namestack: string[] = [];
|
||||
let testList: Executor[] = [];
|
||||
function shimMochaHarness() {
|
||||
(global as any).before = undefined;
|
||||
(global as any).after = undefined;
|
||||
(global as any).beforeEach = undefined;
|
||||
describe = ((name, callback) => {
|
||||
testList.push({ name, callback, kind: "suite" });
|
||||
}) as Mocha.IContextDefinition;
|
||||
it = ((name, callback) => {
|
||||
if (!testList) {
|
||||
throw new Error("Tests must occur within a describe block");
|
||||
}
|
||||
testList.push({ name, callback, kind: "test" });
|
||||
}) as Mocha.ITestDefinition;
|
||||
}
|
||||
|
||||
function executeSuiteCallback(name: string, callback: Function) {
|
||||
const fakeContext: Mocha.ISuiteCallbackContext = {
|
||||
retries() { return this; },
|
||||
slow() { return this; },
|
||||
timeout() { return this; },
|
||||
};
|
||||
namestack.push(name);
|
||||
let beforeFunc: Function;
|
||||
(before as any) = (cb: Function) => beforeFunc = cb;
|
||||
let afterFunc: Function;
|
||||
(after as any) = (cb: Function) => afterFunc = cb;
|
||||
const savedBeforeEach = beforeEachFunc;
|
||||
(beforeEach as any) = (cb: Function) => beforeEachFunc = cb;
|
||||
const savedTestList = testList;
|
||||
|
||||
testList = [];
|
||||
try {
|
||||
callback.call(fakeContext);
|
||||
}
|
||||
catch (e) {
|
||||
errors.push({ error: `Error executing suite: ${e.message}`, stack: e.stack, name: namestack.join(" ") });
|
||||
return cleanup();
|
||||
}
|
||||
try {
|
||||
beforeFunc && beforeFunc();
|
||||
}
|
||||
catch (e) {
|
||||
errors.push({ error: `Error executing before function: ${e.message}`, stack: e.stack, name: namestack.join(" ") });
|
||||
return cleanup();
|
||||
}
|
||||
finally {
|
||||
beforeFunc = undefined;
|
||||
}
|
||||
testList.forEach(({ name, callback, kind }) => executeCallback(name, callback, kind));
|
||||
|
||||
try {
|
||||
afterFunc && afterFunc();
|
||||
}
|
||||
catch (e) {
|
||||
errors.push({ error: `Error executing after function: ${e.message}`, stack: e.stack, name: namestack.join(" ") });
|
||||
}
|
||||
finally {
|
||||
afterFunc = undefined;
|
||||
cleanup();
|
||||
}
|
||||
function cleanup() {
|
||||
testList.length = 0;
|
||||
testList = savedTestList;
|
||||
beforeEachFunc = savedBeforeEach;
|
||||
namestack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
function executeCallback(name: string, callback: Function, kind: "suite" | "test") {
|
||||
if (kind === "suite") {
|
||||
executeSuiteCallback(name, callback);
|
||||
}
|
||||
else {
|
||||
executeTestCallback(name, callback);
|
||||
}
|
||||
}
|
||||
|
||||
function executeTestCallback(name: string, callback: Function) {
|
||||
const fakeContext: Mocha.ITestCallbackContext = {
|
||||
skip() { return this; },
|
||||
timeout() { return this; },
|
||||
retries() { return this; },
|
||||
slow() { return this; },
|
||||
};
|
||||
namestack.push(name);
|
||||
name = namestack.join(" ");
|
||||
if (beforeEachFunc) {
|
||||
try {
|
||||
beforeEachFunc();
|
||||
}
|
||||
catch (error) {
|
||||
errors.push({ error: error.message, stack: error.stack, name });
|
||||
namestack.pop();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (callback.length === 0) {
|
||||
try {
|
||||
// TODO: If we ever start using async test completions, polyfill promise return handling
|
||||
callback.call(fakeContext);
|
||||
}
|
||||
catch (error) {
|
||||
errors.push({ error: error.message, stack: error.stack, name });
|
||||
return;
|
||||
}
|
||||
finally {
|
||||
namestack.pop();
|
||||
}
|
||||
passing++;
|
||||
}
|
||||
else {
|
||||
// Uses `done` callback
|
||||
let completed = false;
|
||||
try {
|
||||
callback.call(fakeContext, (err: any) => {
|
||||
if (completed) {
|
||||
throw new Error(`done() callback called multiple times; ensure it is only called once.`);
|
||||
}
|
||||
if (err) {
|
||||
errors.push({ error: err.toString(), stack: "", name });
|
||||
}
|
||||
else {
|
||||
passing++;
|
||||
}
|
||||
completed = true;
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
errors.push({ error: error.message, stack: error.stack, name });
|
||||
return;
|
||||
}
|
||||
finally {
|
||||
namestack.pop();
|
||||
}
|
||||
if (!completed) {
|
||||
errors.push({ error: "Test completes asynchronously, which is unsupported by the parallel harness", stack: "", name });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function start() {
|
||||
let initialized = false;
|
||||
const runners = ts.createMap<RunnerBase>();
|
||||
process.on("message", (data: ParallelHostMessage) => {
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
shimMochaHarness();
|
||||
}
|
||||
switch (data.type) {
|
||||
case "test":
|
||||
const { runner, file } = data.payload;
|
||||
if (!runner) {
|
||||
console.error(data);
|
||||
}
|
||||
const message: ParallelResultMessage = { type: "result", payload: handleTest(runner, file) };
|
||||
process.send(message);
|
||||
break;
|
||||
case "close":
|
||||
process.exit(0);
|
||||
break;
|
||||
case "batch": {
|
||||
const items = data.payload;
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const { runner, file } = items[i];
|
||||
if (!runner) {
|
||||
console.error(data);
|
||||
}
|
||||
let message: ParallelBatchProgressMessage | ParallelResultMessage;
|
||||
const payload = handleTest(runner, file);
|
||||
if (i === (items.length - 1)) {
|
||||
message = { type: "result", payload };
|
||||
}
|
||||
else {
|
||||
message = { type: "progress", payload };
|
||||
}
|
||||
process.send(message);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
process.on("uncaughtException", error => {
|
||||
const message: ParallelErrorMessage = { type: "error", payload: { error: error.message, stack: error.stack, name: namestack.join(" ") } };
|
||||
try {
|
||||
process.send(message);
|
||||
}
|
||||
catch (e) {
|
||||
console.error(error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
if (!runUnitTests) {
|
||||
// ensure unit tests do not get run
|
||||
describe = ts.noop as any;
|
||||
}
|
||||
else {
|
||||
initialized = true;
|
||||
shimMochaHarness();
|
||||
}
|
||||
|
||||
function handleTest(runner: TestRunnerKind, file: string) {
|
||||
if (!runners.has(runner)) {
|
||||
runners.set(runner, createRunner(runner));
|
||||
}
|
||||
const instance = runners.get(runner);
|
||||
instance.tests = [file];
|
||||
return { ...resetShimHarnessAndExecute(instance), runner, file };
|
||||
}
|
||||
}
|
||||
}
|
||||
+113
-117
@@ -19,6 +19,7 @@
|
||||
/// <reference path="projectsRunner.ts" />
|
||||
/// <reference path="rwcRunner.ts" />
|
||||
/// <reference path="harness.ts" />
|
||||
/// <reference path="./parallel/shared.ts" />
|
||||
|
||||
let runners: RunnerBase[] = [];
|
||||
let iterations = 1;
|
||||
@@ -59,6 +60,7 @@ function createRunner(kind: TestRunnerKind): RunnerBase {
|
||||
case "test262":
|
||||
return new Test262BaselineRunner();
|
||||
}
|
||||
ts.Debug.fail(`Unknown runner kind ${kind}`);
|
||||
}
|
||||
|
||||
if (Harness.IO.tryEnableSourceMapsForHost && /^development$/i.test(Harness.IO.getEnvironmentVariable("NODE_ENV"))) {
|
||||
@@ -81,15 +83,17 @@ let testConfigContent =
|
||||
let taskConfigsFolder: string;
|
||||
let workerCount: number;
|
||||
let runUnitTests = true;
|
||||
let noColors = false;
|
||||
|
||||
interface TestConfig {
|
||||
light?: boolean;
|
||||
taskConfigsFolder?: string;
|
||||
listenForWork?: boolean;
|
||||
workerCount?: number;
|
||||
stackTraceLimit?: number | "full";
|
||||
tasks?: TaskSet[];
|
||||
test?: string[];
|
||||
runUnitTests?: boolean;
|
||||
noColors?: boolean;
|
||||
}
|
||||
|
||||
interface TaskSet {
|
||||
@@ -97,138 +101,130 @@ interface TaskSet {
|
||||
files: string[];
|
||||
}
|
||||
|
||||
if (testConfigContent !== "") {
|
||||
const testConfig = <TestConfig>JSON.parse(testConfigContent);
|
||||
if (testConfig.light) {
|
||||
Harness.lightMode = true;
|
||||
}
|
||||
if (testConfig.taskConfigsFolder) {
|
||||
taskConfigsFolder = testConfig.taskConfigsFolder;
|
||||
}
|
||||
if (testConfig.runUnitTests !== undefined) {
|
||||
runUnitTests = testConfig.runUnitTests;
|
||||
}
|
||||
if (testConfig.workerCount) {
|
||||
workerCount = testConfig.workerCount;
|
||||
}
|
||||
if (testConfig.tasks) {
|
||||
for (const taskSet of testConfig.tasks) {
|
||||
const runner = createRunner(taskSet.runner);
|
||||
for (const file of taskSet.files) {
|
||||
runner.addTest(file);
|
||||
}
|
||||
runners.push(runner);
|
||||
let configOption: string;
|
||||
function handleTestConfig() {
|
||||
if (testConfigContent !== "") {
|
||||
const testConfig = <TestConfig>JSON.parse(testConfigContent);
|
||||
if (testConfig.light) {
|
||||
Harness.lightMode = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (testConfig.stackTraceLimit === "full") {
|
||||
(<any>Error).stackTraceLimit = Infinity;
|
||||
}
|
||||
else if ((+testConfig.stackTraceLimit | 0) > 0) {
|
||||
(<any>Error).stackTraceLimit = testConfig.stackTraceLimit;
|
||||
}
|
||||
|
||||
if (testConfig.test && testConfig.test.length > 0) {
|
||||
for (const option of testConfig.test) {
|
||||
if (!option) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (option) {
|
||||
case "compiler":
|
||||
runners.push(new CompilerBaselineRunner(CompilerTestType.Conformance));
|
||||
runners.push(new CompilerBaselineRunner(CompilerTestType.Regressions));
|
||||
runners.push(new ProjectRunner());
|
||||
break;
|
||||
case "conformance":
|
||||
runners.push(new CompilerBaselineRunner(CompilerTestType.Conformance));
|
||||
break;
|
||||
case "project":
|
||||
runners.push(new ProjectRunner());
|
||||
break;
|
||||
case "fourslash":
|
||||
runners.push(new FourSlashRunner(FourSlashTestType.Native));
|
||||
break;
|
||||
case "fourslash-shims":
|
||||
runners.push(new FourSlashRunner(FourSlashTestType.Shims));
|
||||
break;
|
||||
case "fourslash-shims-pp":
|
||||
runners.push(new FourSlashRunner(FourSlashTestType.ShimsWithPreprocess));
|
||||
break;
|
||||
case "fourslash-server":
|
||||
runners.push(new FourSlashRunner(FourSlashTestType.Server));
|
||||
break;
|
||||
case "fourslash-generated":
|
||||
runners.push(new GeneratedFourslashRunner(FourSlashTestType.Native));
|
||||
break;
|
||||
case "rwc":
|
||||
runners.push(new RWCRunner());
|
||||
break;
|
||||
case "test262":
|
||||
runners.push(new Test262BaselineRunner());
|
||||
break;
|
||||
}
|
||||
if (testConfig.runUnitTests !== undefined) {
|
||||
runUnitTests = testConfig.runUnitTests;
|
||||
}
|
||||
if (testConfig.workerCount) {
|
||||
workerCount = +testConfig.workerCount;
|
||||
}
|
||||
if (testConfig.taskConfigsFolder) {
|
||||
taskConfigsFolder = testConfig.taskConfigsFolder;
|
||||
}
|
||||
if (testConfig.noColors !== undefined) {
|
||||
noColors = testConfig.noColors;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (runners.length === 0) {
|
||||
// compiler
|
||||
runners.push(new CompilerBaselineRunner(CompilerTestType.Conformance));
|
||||
runners.push(new CompilerBaselineRunner(CompilerTestType.Regressions));
|
||||
if (testConfig.stackTraceLimit === "full") {
|
||||
(<any>Error).stackTraceLimit = Infinity;
|
||||
}
|
||||
else if ((+testConfig.stackTraceLimit | 0) > 0) {
|
||||
(<any>Error).stackTraceLimit = testConfig.stackTraceLimit;
|
||||
}
|
||||
if (testConfig.listenForWork) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: project tests don't work in the browser yet
|
||||
if (Utils.getExecutionEnvironment() !== Utils.ExecutionEnvironment.Browser) {
|
||||
runners.push(new ProjectRunner());
|
||||
}
|
||||
if (testConfig.test && testConfig.test.length > 0) {
|
||||
for (const option of testConfig.test) {
|
||||
if (!option) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// language services
|
||||
runners.push(new FourSlashRunner(FourSlashTestType.Native));
|
||||
runners.push(new FourSlashRunner(FourSlashTestType.Shims));
|
||||
runners.push(new FourSlashRunner(FourSlashTestType.ShimsWithPreprocess));
|
||||
runners.push(new FourSlashRunner(FourSlashTestType.Server));
|
||||
// runners.push(new GeneratedFourslashRunner());
|
||||
}
|
||||
if (!configOption) {
|
||||
configOption = option;
|
||||
}
|
||||
else {
|
||||
configOption += "+" + option;
|
||||
}
|
||||
|
||||
if (taskConfigsFolder) {
|
||||
// this instance of mocha should only partition work but not run actual tests
|
||||
runUnitTests = false;
|
||||
const workerConfigs: TestConfig[] = [];
|
||||
for (let i = 0; i < workerCount; i++) {
|
||||
// pass light mode settings to workers
|
||||
workerConfigs.push({ light: Harness.lightMode, tasks: [] });
|
||||
}
|
||||
|
||||
for (const runner of runners) {
|
||||
const files = runner.enumerateTestFiles();
|
||||
const chunkSize = Math.floor(files.length / workerCount) + 1; // add extra 1 to prevent missing tests due to rounding
|
||||
for (let i = 0; i < workerCount; i++) {
|
||||
const startPos = i * chunkSize;
|
||||
const len = Math.min(chunkSize, files.length - startPos);
|
||||
if (len > 0) {
|
||||
workerConfigs[i].tasks.push({
|
||||
runner: runner.kind(),
|
||||
files: files.slice(startPos, startPos + len)
|
||||
});
|
||||
switch (option) {
|
||||
case "compiler":
|
||||
runners.push(new CompilerBaselineRunner(CompilerTestType.Conformance));
|
||||
runners.push(new CompilerBaselineRunner(CompilerTestType.Regressions));
|
||||
runners.push(new ProjectRunner());
|
||||
break;
|
||||
case "conformance":
|
||||
runners.push(new CompilerBaselineRunner(CompilerTestType.Conformance));
|
||||
break;
|
||||
case "project":
|
||||
runners.push(new ProjectRunner());
|
||||
break;
|
||||
case "fourslash":
|
||||
runners.push(new FourSlashRunner(FourSlashTestType.Native));
|
||||
break;
|
||||
case "fourslash-shims":
|
||||
runners.push(new FourSlashRunner(FourSlashTestType.Shims));
|
||||
break;
|
||||
case "fourslash-shims-pp":
|
||||
runners.push(new FourSlashRunner(FourSlashTestType.ShimsWithPreprocess));
|
||||
break;
|
||||
case "fourslash-server":
|
||||
runners.push(new FourSlashRunner(FourSlashTestType.Server));
|
||||
break;
|
||||
case "fourslash-generated":
|
||||
runners.push(new GeneratedFourslashRunner(FourSlashTestType.Native));
|
||||
break;
|
||||
case "rwc":
|
||||
runners.push(new RWCRunner());
|
||||
break;
|
||||
case "test262":
|
||||
runners.push(new Test262BaselineRunner());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < workerCount; i++) {
|
||||
const config = workerConfigs[i];
|
||||
// use last worker to run unit tests if we're not just running a single specific runner
|
||||
config.runUnitTests = runners.length !== 1 && i === workerCount - 1;
|
||||
Harness.IO.writeFile(ts.combinePaths(taskConfigsFolder, `task-config${i}.json`), JSON.stringify(workerConfigs[i]));
|
||||
if (runners.length === 0) {
|
||||
// compiler
|
||||
runners.push(new CompilerBaselineRunner(CompilerTestType.Conformance));
|
||||
runners.push(new CompilerBaselineRunner(CompilerTestType.Regressions));
|
||||
|
||||
// TODO: project tests don"t work in the browser yet
|
||||
if (Utils.getExecutionEnvironment() !== Utils.ExecutionEnvironment.Browser) {
|
||||
runners.push(new ProjectRunner());
|
||||
}
|
||||
|
||||
// language services
|
||||
runners.push(new FourSlashRunner(FourSlashTestType.Native));
|
||||
runners.push(new FourSlashRunner(FourSlashTestType.Shims));
|
||||
runners.push(new FourSlashRunner(FourSlashTestType.ShimsWithPreprocess));
|
||||
runners.push(new FourSlashRunner(FourSlashTestType.Server));
|
||||
// runners.push(new GeneratedFourslashRunner());
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
function beginTests() {
|
||||
if (ts.Debug.isDebugging) {
|
||||
ts.Debug.enableDebugInfo();
|
||||
}
|
||||
|
||||
runTests(runners);
|
||||
|
||||
if (!runUnitTests) {
|
||||
// patch `describe` to skip unit tests
|
||||
describe = ts.noop as any;
|
||||
}
|
||||
}
|
||||
if (!runUnitTests) {
|
||||
// patch `describe` to skip unit tests
|
||||
describe = ts.noop as any;
|
||||
|
||||
function startTestEnvironment() {
|
||||
const isWorker = handleTestConfig();
|
||||
if (Utils.getExecutionEnvironment() !== Utils.ExecutionEnvironment.Browser) {
|
||||
if (isWorker) {
|
||||
return Harness.Parallel.Worker.start();
|
||||
}
|
||||
else if (taskConfigsFolder && workerCount && workerCount > 1) {
|
||||
return Harness.Parallel.Host.start();
|
||||
}
|
||||
}
|
||||
beginTests();
|
||||
}
|
||||
|
||||
startTestEnvironment();
|
||||
|
||||
+19
-17
@@ -39,6 +39,8 @@ namespace RWC {
|
||||
const baseName = /(.*)\/(.*).json/.exec(ts.normalizeSlashes(jsonPath))[2];
|
||||
let currentDirectory: string;
|
||||
let useCustomLibraryFile: boolean;
|
||||
let skipTypeAndSymbolbaselines = false;
|
||||
const typeAndSymbolSizeLimit = 10000000;
|
||||
after(() => {
|
||||
// Mocha holds onto the closure environment of the describe callback even after the test is done.
|
||||
// Therefore we have to clean out large objects after the test is done.
|
||||
@@ -52,6 +54,7 @@ namespace RWC {
|
||||
// or to use lib.d.ts inside the json object. If the flag is true, use the lib.d.ts inside json file
|
||||
// otherwise use the lib.d.ts from built/local
|
||||
useCustomLibraryFile = undefined;
|
||||
skipTypeAndSymbolbaselines = false;
|
||||
});
|
||||
|
||||
it("can compile", function(this: Mocha.ITestCallbackContext) {
|
||||
@@ -61,6 +64,7 @@ namespace RWC {
|
||||
const ioLog: IOLog = JSON.parse(Harness.IO.readFile(jsonPath));
|
||||
currentDirectory = ioLog.currentDirectory;
|
||||
useCustomLibraryFile = ioLog.useCustomLibraryFile;
|
||||
skipTypeAndSymbolbaselines = ioLog.filesRead.reduce((acc, elem) => (elem && elem.result && elem.result.contents) ? acc + elem.result.contents.length : acc, 0) > typeAndSymbolSizeLimit;
|
||||
runWithIOLog(ioLog, () => {
|
||||
opts = ts.parseCommandLine(ioLog.arguments, fileName => Harness.IO.readFile(fileName));
|
||||
assert.equal(opts.errors.length, 0);
|
||||
@@ -170,29 +174,29 @@ namespace RWC {
|
||||
|
||||
|
||||
it("has the expected emitted code", () => {
|
||||
Harness.Baseline.runBaseline(`${baseName}.output.js`, () => {
|
||||
return Harness.Compiler.collateOutputs(compilerResult.files);
|
||||
}, baselineOpts);
|
||||
Harness.Baseline.runMultifileBaseline(baseName, "", () => {
|
||||
return Harness.Compiler.iterateOutputs(compilerResult.files);
|
||||
}, baselineOpts, [".js", ".jsx"]);
|
||||
});
|
||||
|
||||
it("has the expected declaration file content", () => {
|
||||
Harness.Baseline.runBaseline(`${baseName}.d.ts`, () => {
|
||||
Harness.Baseline.runMultifileBaseline(baseName, "", () => {
|
||||
if (!compilerResult.declFilesCode.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Harness.Compiler.collateOutputs(compilerResult.declFilesCode);
|
||||
}, baselineOpts);
|
||||
return Harness.Compiler.iterateOutputs(compilerResult.declFilesCode);
|
||||
}, baselineOpts, [".d.ts"]);
|
||||
});
|
||||
|
||||
it("has the expected source maps", () => {
|
||||
Harness.Baseline.runBaseline(`${baseName}.map`, () => {
|
||||
Harness.Baseline.runMultifileBaseline(baseName, "", () => {
|
||||
if (!compilerResult.sourceMaps.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Harness.Compiler.collateOutputs(compilerResult.sourceMaps);
|
||||
}, baselineOpts);
|
||||
return Harness.Compiler.iterateOutputs(compilerResult.sourceMaps);
|
||||
}, baselineOpts, [".map"]);
|
||||
});
|
||||
|
||||
/*it("has correct source map record", () => {
|
||||
@@ -204,30 +208,30 @@ namespace RWC {
|
||||
});*/
|
||||
|
||||
it("has the expected errors", () => {
|
||||
Harness.Baseline.runBaseline(`${baseName}.errors.txt`, () => {
|
||||
Harness.Baseline.runMultifileBaseline(baseName, ".errors.txt", () => {
|
||||
if (compilerResult.errors.length === 0) {
|
||||
return null;
|
||||
}
|
||||
// Do not include the library in the baselines to avoid noise
|
||||
const baselineFiles = tsconfigFiles.concat(inputFiles, otherFiles).filter(f => !Harness.isDefaultLibraryFile(f.unitName));
|
||||
const errors = compilerResult.errors.filter(e => !e.file || !Harness.isDefaultLibraryFile(e.file.fileName));
|
||||
return Harness.Compiler.getErrorBaseline(baselineFiles, errors);
|
||||
return Harness.Compiler.iterateErrorBaseline(baselineFiles, errors);
|
||||
}, baselineOpts);
|
||||
});
|
||||
|
||||
it("has the expected types", () => {
|
||||
// We don't need to pass the extension here because "doTypeAndSymbolBaseline" will append appropriate extension of ".types" or ".symbols"
|
||||
Harness.Compiler.doTypeAndSymbolBaseline(baseName, compilerResult, inputFiles
|
||||
Harness.Compiler.doTypeAndSymbolBaseline(baseName, compilerResult.program, inputFiles
|
||||
.concat(otherFiles)
|
||||
.filter(file => !!compilerResult.program.getSourceFile(file.unitName))
|
||||
.filter(e => !Harness.isDefaultLibraryFile(e.unitName)), baselineOpts);
|
||||
.filter(e => !Harness.isDefaultLibraryFile(e.unitName)), baselineOpts, /*multifile*/ true, skipTypeAndSymbolbaselines);
|
||||
});
|
||||
|
||||
// Ideally, a generated declaration file will have no errors. But we allow generated
|
||||
// declaration file errors as part of the baseline.
|
||||
it("has the expected errors in generated declaration files", () => {
|
||||
if (compilerOptions.declaration && !compilerResult.errors.length) {
|
||||
Harness.Baseline.runBaseline(`${baseName}.dts.errors.txt`, () => {
|
||||
Harness.Baseline.runMultifileBaseline(baseName, ".dts.errors.txt", () => {
|
||||
if (compilerResult.errors.length === 0) {
|
||||
return null;
|
||||
}
|
||||
@@ -239,9 +243,7 @@ namespace RWC {
|
||||
compilerResult = undefined;
|
||||
const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles(declContext);
|
||||
|
||||
return Harness.Compiler.minimalDiagnosticsToString(declFileCompilationResult.declResult.errors) +
|
||||
Harness.IO.newLine() + Harness.IO.newLine() +
|
||||
Harness.Compiler.getErrorBaseline(tsconfigFiles.concat(declFileCompilationResult.declInputFiles, declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors);
|
||||
return Harness.Compiler.iterateErrorBaseline(tsconfigFiles.concat(declFileCompilationResult.declInputFiles, declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors);
|
||||
}, baselineOpts);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -93,6 +93,9 @@
|
||||
"loggedIO.ts",
|
||||
"rwcRunner.ts",
|
||||
"test262Runner.ts",
|
||||
"./parallel/shared.ts",
|
||||
"./parallel/host.ts",
|
||||
"./parallel/worker.ts",
|
||||
"runner.ts",
|
||||
"virtualFileSystemWithWatch.ts",
|
||||
"../server/protocol.ts",
|
||||
|
||||
+84
-35
@@ -1,13 +1,26 @@
|
||||
interface TypeWriterResult {
|
||||
interface TypeWriterTypeResult {
|
||||
line: number;
|
||||
syntaxKind: number;
|
||||
sourceText: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
interface TypeWriterSymbolResult {
|
||||
line: number;
|
||||
syntaxKind: number;
|
||||
sourceText: string;
|
||||
symbol: string;
|
||||
}
|
||||
|
||||
interface TypeWriterResult {
|
||||
line: number;
|
||||
syntaxKind: number;
|
||||
sourceText: string;
|
||||
symbol?: string;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
class TypeWriterWalker {
|
||||
results: TypeWriterResult[];
|
||||
currentSourceFile: ts.SourceFile;
|
||||
|
||||
private checker: ts.TypeChecker;
|
||||
@@ -20,57 +33,93 @@ class TypeWriterWalker {
|
||||
: program.getTypeChecker();
|
||||
}
|
||||
|
||||
public getTypeAndSymbols(fileName: string): TypeWriterResult[] {
|
||||
public *getSymbols(fileName: string): IterableIterator<TypeWriterSymbolResult> {
|
||||
const sourceFile = this.program.getSourceFile(fileName);
|
||||
this.currentSourceFile = sourceFile;
|
||||
this.results = [];
|
||||
this.visitNode(sourceFile);
|
||||
return this.results;
|
||||
const gen = this.visitNode(sourceFile, /*isSymbolWalk*/ true);
|
||||
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
|
||||
yield value as TypeWriterSymbolResult;
|
||||
}
|
||||
}
|
||||
|
||||
private visitNode(node: ts.Node): void {
|
||||
public *getTypes(fileName: string): IterableIterator<TypeWriterTypeResult> {
|
||||
const sourceFile = this.program.getSourceFile(fileName);
|
||||
this.currentSourceFile = sourceFile;
|
||||
const gen = this.visitNode(sourceFile, /*isSymbolWalk*/ false);
|
||||
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
|
||||
yield value as TypeWriterTypeResult;
|
||||
}
|
||||
}
|
||||
|
||||
private *visitNode(node: ts.Node, isSymbolWalk: boolean): IterableIterator<TypeWriterResult> {
|
||||
if (ts.isPartOfExpression(node) || node.kind === ts.SyntaxKind.Identifier) {
|
||||
this.logTypeAndSymbol(node);
|
||||
const result = this.writeTypeOrSymbol(node, isSymbolWalk);
|
||||
if (result) {
|
||||
yield result;
|
||||
}
|
||||
}
|
||||
|
||||
ts.forEachChild(node, child => this.visitNode(child));
|
||||
const children: ts.Node[] = [];
|
||||
ts.forEachChild(node, child => void children.push(child));
|
||||
for (const child of children) {
|
||||
const gen = this.visitNode(child, isSymbolWalk);
|
||||
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
|
||||
yield value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private logTypeAndSymbol(node: ts.Node): void {
|
||||
private writeTypeOrSymbol(node: ts.Node, isSymbolWalk: boolean): TypeWriterResult {
|
||||
const actualPos = ts.skipTrivia(this.currentSourceFile.text, node.pos);
|
||||
const lineAndCharacter = this.currentSourceFile.getLineAndCharacterOfPosition(actualPos);
|
||||
const sourceText = ts.getTextOfNodeFromSourceText(this.currentSourceFile.text, node);
|
||||
|
||||
// Workaround to ensure we output 'C' instead of 'typeof C' for base class expressions
|
||||
// let type = this.checker.getTypeAtLocation(node);
|
||||
const type = node.parent && ts.isExpressionWithTypeArgumentsInClassExtendsClause(node.parent) && this.checker.getTypeAtLocation(node.parent) || this.checker.getTypeAtLocation(node);
|
||||
|
||||
ts.Debug.assert(type !== undefined, "type doesn't exist");
|
||||
const symbol = this.checker.getSymbolAtLocation(node);
|
||||
|
||||
const typeString = this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.NoTruncation);
|
||||
let symbolString: string;
|
||||
if (symbol) {
|
||||
symbolString = "Symbol(" + this.checker.symbolToString(symbol, node.parent);
|
||||
if (symbol.declarations) {
|
||||
for (const declaration of symbol.declarations) {
|
||||
symbolString += ", ";
|
||||
const declSourceFile = declaration.getSourceFile();
|
||||
const declLineAndCharacter = declSourceFile.getLineAndCharacterOfPosition(declaration.pos);
|
||||
const fileName = ts.getBaseFileName(declSourceFile.fileName);
|
||||
const isLibFile = /lib(.*)\.d\.ts/i.test(fileName);
|
||||
symbolString += `Decl(${ fileName }, ${ isLibFile ? "--" : declLineAndCharacter.line }, ${ isLibFile ? "--" : declLineAndCharacter.character })`;
|
||||
}
|
||||
}
|
||||
symbolString += ")";
|
||||
if (!isSymbolWalk) {
|
||||
// Workaround to ensure we output 'C' instead of 'typeof C' for base class expressions
|
||||
// let type = this.checker.getTypeAtLocation(node);
|
||||
const type = node.parent && ts.isExpressionWithTypeArgumentsInClassExtendsClause(node.parent) && this.checker.getTypeAtLocation(node.parent) || this.checker.getTypeAtLocation(node);
|
||||
const typeString = type ? this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.NoTruncation) : "No type information available!";
|
||||
return {
|
||||
line: lineAndCharacter.line,
|
||||
syntaxKind: node.kind,
|
||||
sourceText,
|
||||
type: typeString
|
||||
};
|
||||
}
|
||||
|
||||
this.results.push({
|
||||
const symbol = this.checker.getSymbolAtLocation(node);
|
||||
if (!symbol) {
|
||||
return;
|
||||
}
|
||||
let symbolString = "Symbol(" + this.checker.symbolToString(symbol, node.parent);
|
||||
if (symbol.declarations) {
|
||||
let count = 0;
|
||||
for (const declaration of symbol.declarations) {
|
||||
if (count >= 5) {
|
||||
symbolString += ` ... and ${symbol.declarations.length - count} more`;
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
symbolString += ", ";
|
||||
if ((declaration as any)["__symbolTestOutputCache"]) {
|
||||
symbolString += (declaration as any)["__symbolTestOutputCache"];
|
||||
continue;
|
||||
}
|
||||
const declSourceFile = declaration.getSourceFile();
|
||||
const declLineAndCharacter = declSourceFile.getLineAndCharacterOfPosition(declaration.pos);
|
||||
const fileName = ts.getBaseFileName(declSourceFile.fileName);
|
||||
const isLibFile = /lib(.*)\.d\.ts/i.test(fileName);
|
||||
const declText = `Decl(${ fileName }, ${ isLibFile ? "--" : declLineAndCharacter.line }, ${ isLibFile ? "--" : declLineAndCharacter.character })`;
|
||||
symbolString += declText;
|
||||
(declaration as any)["__symbolTestOutputCache"] = declText;
|
||||
}
|
||||
}
|
||||
symbolString += ")";
|
||||
return {
|
||||
line: lineAndCharacter.line,
|
||||
syntaxKind: node.kind,
|
||||
sourceText,
|
||||
type: typeString,
|
||||
symbol: symbolString
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -410,6 +410,8 @@ function test(x: number) {
|
||||
"Statement or expression expected."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extract-method-not-for-token-expression-statement", `[#|a|]`, ["Select more than a single identifier."]);
|
||||
|
||||
testExtractMethod("extractMethod1",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
@@ -766,6 +768,11 @@ function parsePrimaryExpression(): any {
|
||||
}
|
||||
}|]
|
||||
}
|
||||
}`);
|
||||
// Selection excludes leading trivia of declaration
|
||||
testExtractMethod("extractMethod33",
|
||||
`function F() {
|
||||
[#|function G() { }|]
|
||||
}`);
|
||||
});
|
||||
|
||||
|
||||
@@ -139,6 +139,16 @@ namespace ts {
|
||||
`/**
|
||||
* @param
|
||||
*/`);
|
||||
|
||||
parsesIncorrectly("noType",
|
||||
`/**
|
||||
* @type
|
||||
*/`);
|
||||
|
||||
parsesIncorrectly("@augments with no type",
|
||||
`/**
|
||||
* @augments
|
||||
*/`);
|
||||
});
|
||||
|
||||
describe("parsesCorrectly", () => {
|
||||
@@ -148,12 +158,6 @@ namespace ts {
|
||||
*/`);
|
||||
|
||||
|
||||
parsesCorrectly("noType",
|
||||
`/**
|
||||
* @type
|
||||
*/`);
|
||||
|
||||
|
||||
parsesCorrectly("noReturnType",
|
||||
`/**
|
||||
* @return
|
||||
|
||||
@@ -110,6 +110,29 @@ namespace ts {
|
||||
createSourceFile("source.ts", "", ScriptTarget.ES2015)
|
||||
));
|
||||
|
||||
|
||||
printsCorrectly("emptyGlobalAugmentation", {}, printer => printer.printNode(
|
||||
EmitHint.Unspecified,
|
||||
createModuleDeclaration(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ [createToken(SyntaxKind.DeclareKeyword)],
|
||||
createIdentifier("global"),
|
||||
createModuleBlock(emptyArray),
|
||||
NodeFlags.GlobalAugmentation),
|
||||
createSourceFile("source.ts", "", ScriptTarget.ES2015)
|
||||
));
|
||||
|
||||
printsCorrectly("emptyGlobalAugmentationWithNoDeclareKeyword", {}, printer => printer.printNode(
|
||||
EmitHint.Unspecified,
|
||||
createModuleDeclaration(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
createIdentifier("global"),
|
||||
createModuleBlock(emptyArray),
|
||||
NodeFlags.GlobalAugmentation),
|
||||
createSourceFile("source.ts", "", ScriptTarget.ES2015)
|
||||
));
|
||||
|
||||
// https://github.com/Microsoft/TypeScript/issues/15971
|
||||
printsCorrectly("classWithOptionalMethodAndProperty", {}, printer => printer.printNode(
|
||||
EmitHint.Unspecified,
|
||||
|
||||
@@ -509,7 +509,7 @@ namespace ts.server {
|
||||
class InProcClient {
|
||||
private server: InProcSession;
|
||||
private seq = 0;
|
||||
private callbacks: Array<(resp: protocol.Response) => void> = [];
|
||||
private callbacks: ((resp: protocol.Response) => void)[] = [];
|
||||
private eventHandlers = createMap<(args: any) => void>();
|
||||
|
||||
handle(msg: protocol.Message): void {
|
||||
|
||||
@@ -17,32 +17,33 @@ namespace ts {
|
||||
let oldTranspileResult: string;
|
||||
let oldTranspileDiagnostics: Diagnostic[];
|
||||
|
||||
transpileOptions = testSettings.options || {};
|
||||
if (!transpileOptions.compilerOptions) {
|
||||
transpileOptions.compilerOptions = {};
|
||||
}
|
||||
|
||||
if (transpileOptions.compilerOptions.newLine === undefined) {
|
||||
// use \r\n as default new line
|
||||
transpileOptions.compilerOptions.newLine = ts.NewLineKind.CarriageReturnLineFeed;
|
||||
}
|
||||
|
||||
transpileOptions.compilerOptions.sourceMap = true;
|
||||
|
||||
if (!transpileOptions.fileName) {
|
||||
transpileOptions.fileName = transpileOptions.compilerOptions.jsx ? "file.tsx" : "file.ts";
|
||||
}
|
||||
|
||||
transpileOptions.reportDiagnostics = true;
|
||||
|
||||
justName = "transpile/" + name.replace(/[^a-z0-9\-. ]/ig, "") + (transpileOptions.compilerOptions.jsx ? Extension.Tsx : Extension.Ts);
|
||||
toBeCompiled = [{
|
||||
unitName: transpileOptions.fileName,
|
||||
content: input
|
||||
}];
|
||||
|
||||
canUseOldTranspile = !transpileOptions.renamedDependencies;
|
||||
|
||||
before(() => {
|
||||
transpileOptions = testSettings.options || {};
|
||||
if (!transpileOptions.compilerOptions) {
|
||||
transpileOptions.compilerOptions = {};
|
||||
}
|
||||
|
||||
if (transpileOptions.compilerOptions.newLine === undefined) {
|
||||
// use \r\n as default new line
|
||||
transpileOptions.compilerOptions.newLine = ts.NewLineKind.CarriageReturnLineFeed;
|
||||
}
|
||||
|
||||
transpileOptions.compilerOptions.sourceMap = true;
|
||||
|
||||
if (!transpileOptions.fileName) {
|
||||
transpileOptions.fileName = transpileOptions.compilerOptions.jsx ? "file.tsx" : "file.ts";
|
||||
}
|
||||
|
||||
transpileOptions.reportDiagnostics = true;
|
||||
|
||||
justName = "transpile/" + name.replace(/[^a-z0-9\-. ]/ig, "") + (transpileOptions.compilerOptions.jsx ? Extension.Tsx : Extension.Ts);
|
||||
toBeCompiled = [{
|
||||
unitName: transpileOptions.fileName,
|
||||
content: input
|
||||
}];
|
||||
|
||||
canUseOldTranspile = !transpileOptions.renamedDependencies;
|
||||
transpileResult = transpileModule(input, transpileOptions);
|
||||
|
||||
if (canUseOldTranspile) {
|
||||
@@ -52,10 +53,6 @@ namespace ts {
|
||||
});
|
||||
|
||||
after(() => {
|
||||
justName = undefined;
|
||||
transpileOptions = undefined;
|
||||
canUseOldTranspile = undefined;
|
||||
toBeCompiled = undefined;
|
||||
transpileResult = undefined;
|
||||
oldTranspileResult = undefined;
|
||||
oldTranspileDiagnostics = undefined;
|
||||
|
||||
@@ -4213,22 +4213,23 @@ namespace ts.projectSystem {
|
||||
});
|
||||
|
||||
describe("CachingFileSystemInformation", () => {
|
||||
interface CalledMaps {
|
||||
fileExists: MultiMap<true>;
|
||||
directoryExists: MultiMap<true>;
|
||||
getDirectories: MultiMap<true>;
|
||||
readFile: MultiMap<true>;
|
||||
readDirectory: MultiMap<[ReadonlyArray<string>, ReadonlyArray<string>, ReadonlyArray<string>, number]>;
|
||||
enum CalledMapsWithSingleArg {
|
||||
fileExists = "fileExists",
|
||||
directoryExists = "directoryExists",
|
||||
getDirectories = "getDirectories",
|
||||
readFile = "readFile"
|
||||
}
|
||||
|
||||
enum CalledMapsWithFiveArgs {
|
||||
readDirectory = "readDirectory"
|
||||
}
|
||||
type CalledMaps = CalledMapsWithSingleArg | CalledMapsWithFiveArgs;
|
||||
function createCallsTrackingHost(host: TestServerHost) {
|
||||
const keys: Array<keyof CalledMaps> = ["fileExists", "directoryExists", "getDirectories", "readFile", "readDirectory"];
|
||||
const calledMaps: CalledMaps = {
|
||||
fileExists: setCallsTrackingWithSingleArgFn("fileExists"),
|
||||
directoryExists: setCallsTrackingWithSingleArgFn("directoryExists"),
|
||||
getDirectories: setCallsTrackingWithSingleArgFn("getDirectories"),
|
||||
readFile: setCallsTrackingWithSingleArgFn("readFile"),
|
||||
readDirectory: setCallsTrackingWithFiveArgFn("readDirectory")
|
||||
const calledMaps: Record<CalledMapsWithSingleArg, MultiMap<true>> & Record<CalledMapsWithFiveArgs, MultiMap<[ReadonlyArray<string>, ReadonlyArray<string>, ReadonlyArray<string>, number]>> = {
|
||||
fileExists: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.fileExists),
|
||||
directoryExists: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.directoryExists),
|
||||
getDirectories: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.getDirectories),
|
||||
readFile: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.readFile),
|
||||
readDirectory: setCallsTrackingWithFiveArgFn(CalledMapsWithFiveArgs.readDirectory)
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -4241,7 +4242,7 @@ namespace ts.projectSystem {
|
||||
clear
|
||||
};
|
||||
|
||||
function setCallsTrackingWithSingleArgFn(prop: keyof CalledMaps) {
|
||||
function setCallsTrackingWithSingleArgFn(prop: CalledMapsWithSingleArg) {
|
||||
const calledMap = createMultiMap<true>();
|
||||
const cb = (<any>host)[prop].bind(host);
|
||||
(<any>host)[prop] = (f: string) => {
|
||||
@@ -4251,7 +4252,7 @@ namespace ts.projectSystem {
|
||||
return calledMap;
|
||||
}
|
||||
|
||||
function setCallsTrackingWithFiveArgFn<U, V, W, X>(prop: keyof CalledMaps) {
|
||||
function setCallsTrackingWithFiveArgFn<U, V, W, X>(prop: CalledMapsWithFiveArgs) {
|
||||
const calledMap = createMultiMap<[U, V, W, X]>();
|
||||
const cb = (<any>host)[prop].bind(host);
|
||||
(<any>host)[prop] = (f: string, arg1?: U, arg2?: V, arg3?: W, arg4?: X) => {
|
||||
@@ -4261,18 +4262,18 @@ namespace ts.projectSystem {
|
||||
return calledMap;
|
||||
}
|
||||
|
||||
function verifyCalledOn(callback: keyof CalledMaps, name: string) {
|
||||
function verifyCalledOn(callback: CalledMaps, name: string) {
|
||||
const calledMap = calledMaps[callback];
|
||||
const result = calledMap.get(name);
|
||||
assert.isTrue(result && !!result.length, `${callback} should be called with name: ${name}: ${arrayFrom(calledMap.keys())}`);
|
||||
}
|
||||
|
||||
function verifyNoCall(callback: keyof CalledMaps) {
|
||||
function verifyNoCall(callback: CalledMaps) {
|
||||
const calledMap = calledMaps[callback];
|
||||
assert.equal(calledMap.size, 0, `${callback} shouldnt be called: ${arrayFrom(calledMap.keys())}`);
|
||||
}
|
||||
|
||||
function verifyCalledOnEachEntry(callback: keyof CalledMaps, expectedKeys: Map<number>) {
|
||||
function verifyCalledOnEachEntry(callback: CalledMaps, expectedKeys: Map<number>) {
|
||||
const calledMap = calledMaps[callback];
|
||||
assert.equal(calledMap.size, expectedKeys.size, `${callback}: incorrect size of map: Actual keys: ${arrayFrom(calledMap.keys())} Expected: ${arrayFrom(expectedKeys.keys())}`);
|
||||
expectedKeys.forEach((called, name) => {
|
||||
@@ -4281,27 +4282,32 @@ namespace ts.projectSystem {
|
||||
});
|
||||
}
|
||||
|
||||
function verifyCalledOnEachEntryNTimes(callback: keyof CalledMaps, expectedKeys: string[], nTimes: number) {
|
||||
function verifyCalledOnEachEntryNTimes(callback: CalledMaps, expectedKeys: string[], nTimes: number) {
|
||||
return verifyCalledOnEachEntry(callback, zipToMap(expectedKeys, expectedKeys.map(() => nTimes)));
|
||||
}
|
||||
|
||||
function verifyNoHostCalls() {
|
||||
for (const key of keys) {
|
||||
verifyNoCall(key);
|
||||
}
|
||||
iterateOnCalledMaps(key => verifyNoCall(key));
|
||||
}
|
||||
|
||||
function verifyNoHostCallsExceptFileExistsOnce(expectedKeys: string[]) {
|
||||
verifyCalledOnEachEntryNTimes("fileExists", expectedKeys, 1);
|
||||
verifyNoCall("directoryExists");
|
||||
verifyNoCall("getDirectories");
|
||||
verifyNoCall("readFile");
|
||||
verifyNoCall("readDirectory");
|
||||
verifyCalledOnEachEntryNTimes(CalledMapsWithSingleArg.fileExists, expectedKeys, 1);
|
||||
verifyNoCall(CalledMapsWithSingleArg.directoryExists);
|
||||
verifyNoCall(CalledMapsWithSingleArg.getDirectories);
|
||||
verifyNoCall(CalledMapsWithSingleArg.readFile);
|
||||
verifyNoCall(CalledMapsWithFiveArgs.readDirectory);
|
||||
}
|
||||
|
||||
function clear() {
|
||||
for (const key of keys) {
|
||||
calledMaps[key].clear();
|
||||
iterateOnCalledMaps(key => calledMaps[key].clear());
|
||||
}
|
||||
|
||||
function iterateOnCalledMaps(cb: (key: CalledMaps) => void) {
|
||||
for (const key in CalledMapsWithSingleArg) {
|
||||
cb(key as CalledMapsWithSingleArg);
|
||||
}
|
||||
for (const key in CalledMapsWithFiveArgs) {
|
||||
cb(key as CalledMapsWithFiveArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4350,12 +4356,12 @@ namespace ts.projectSystem {
|
||||
assert.isTrue(e.message.indexOf(`Could not find file: '${imported.path}'.`) === 0);
|
||||
}
|
||||
const f2Lookups = getLocationsForModuleLookup("f2");
|
||||
callsTrackingHost.verifyCalledOnEachEntryNTimes("fileExists", f2Lookups, 1);
|
||||
callsTrackingHost.verifyCalledOnEachEntryNTimes(CalledMapsWithSingleArg.fileExists, f2Lookups, 1);
|
||||
const f2DirLookups = getLocationsForDirectoryLookup();
|
||||
callsTrackingHost.verifyCalledOnEachEntry("directoryExists", f2DirLookups);
|
||||
callsTrackingHost.verifyNoCall("getDirectories");
|
||||
callsTrackingHost.verifyNoCall("readFile");
|
||||
callsTrackingHost.verifyNoCall("readDirectory");
|
||||
callsTrackingHost.verifyCalledOnEachEntry(CalledMapsWithSingleArg.directoryExists, f2DirLookups);
|
||||
callsTrackingHost.verifyNoCall(CalledMapsWithSingleArg.getDirectories);
|
||||
callsTrackingHost.verifyNoCall(CalledMapsWithSingleArg.readFile);
|
||||
callsTrackingHost.verifyNoCall(CalledMapsWithFiveArgs.readDirectory);
|
||||
|
||||
editContent(`import {x} from "f1"`);
|
||||
verifyImportedDiagnostics();
|
||||
@@ -4371,11 +4377,11 @@ namespace ts.projectSystem {
|
||||
vertifyF1Lookups();
|
||||
|
||||
function vertifyF1Lookups() {
|
||||
callsTrackingHost.verifyCalledOnEachEntryNTimes("fileExists", f1Lookups, 1);
|
||||
callsTrackingHost.verifyCalledOnEachEntryNTimes("directoryExists", f1DirLookups, 1);
|
||||
callsTrackingHost.verifyNoCall("getDirectories");
|
||||
callsTrackingHost.verifyNoCall("readFile");
|
||||
callsTrackingHost.verifyNoCall("readDirectory");
|
||||
callsTrackingHost.verifyCalledOnEachEntryNTimes(CalledMapsWithSingleArg.fileExists, f1Lookups, 1);
|
||||
callsTrackingHost.verifyCalledOnEachEntryNTimes(CalledMapsWithSingleArg.directoryExists, f1DirLookups, 1);
|
||||
callsTrackingHost.verifyNoCall(CalledMapsWithSingleArg.getDirectories);
|
||||
callsTrackingHost.verifyNoCall(CalledMapsWithSingleArg.readFile);
|
||||
callsTrackingHost.verifyNoCall(CalledMapsWithFiveArgs.readDirectory);
|
||||
}
|
||||
|
||||
function editContent(newContent: string) {
|
||||
@@ -4450,7 +4456,7 @@ namespace ts.projectSystem {
|
||||
const diag = diags[0];
|
||||
assert.equal(diag.code, Diagnostics.Cannot_find_module_0.code);
|
||||
assert.equal(flattenDiagnosticMessageText(diag.messageText, "\n"), "Cannot find module 'bar'.");
|
||||
callsTrackingHost.verifyCalledOn("fileExists", imported.path);
|
||||
callsTrackingHost.verifyCalledOn(CalledMapsWithSingleArg.fileExists, imported.path);
|
||||
|
||||
|
||||
callsTrackingHost.clear();
|
||||
@@ -4458,7 +4464,7 @@ namespace ts.projectSystem {
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
diags = project.getLanguageService().getSemanticDiagnostics(root.path);
|
||||
assert.equal(diags.length, 0);
|
||||
callsTrackingHost.verifyCalledOn("fileExists", imported.path);
|
||||
callsTrackingHost.verifyCalledOn(CalledMapsWithSingleArg.fileExists, imported.path);
|
||||
});
|
||||
|
||||
it("when calling goto definition of module", () => {
|
||||
@@ -4613,11 +4619,11 @@ namespace ts.projectSystem {
|
||||
|
||||
const canonicalFile3Path = useCaseSensitiveFileNames ? file3.path : file3.path.toLocaleLowerCase();
|
||||
const numberOfTimesWatchInvoked = getNumberOfWatchesInvokedForRecursiveWatches(watchingRecursiveDirectories, canonicalFile3Path);
|
||||
callsTrackingHost.verifyCalledOnEachEntryNTimes("fileExists", [canonicalFile3Path], numberOfTimesWatchInvoked);
|
||||
callsTrackingHost.verifyCalledOnEachEntryNTimes("directoryExists", [canonicalFile3Path], numberOfTimesWatchInvoked);
|
||||
callsTrackingHost.verifyNoCall("getDirectories");
|
||||
callsTrackingHost.verifyCalledOnEachEntryNTimes("readFile", [file3.path], 1);
|
||||
callsTrackingHost.verifyNoCall("readDirectory");
|
||||
callsTrackingHost.verifyCalledOnEachEntryNTimes(CalledMapsWithSingleArg.fileExists, [canonicalFile3Path], numberOfTimesWatchInvoked);
|
||||
callsTrackingHost.verifyCalledOnEachEntryNTimes(CalledMapsWithSingleArg.directoryExists, [canonicalFile3Path], numberOfTimesWatchInvoked);
|
||||
callsTrackingHost.verifyNoCall(CalledMapsWithSingleArg.getDirectories);
|
||||
callsTrackingHost.verifyCalledOnEachEntryNTimes(CalledMapsWithSingleArg.readFile, [file3.path], 1);
|
||||
callsTrackingHost.verifyNoCall(CalledMapsWithFiveArgs.readDirectory);
|
||||
|
||||
checkNumberOfConfiguredProjects(projectService, 1);
|
||||
assert.strictEqual(projectService.configuredProjects.get(canonicalConfigPath), project);
|
||||
|
||||
Vendored
+4
-4
@@ -10,7 +10,7 @@ interface Array<T> {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: T, index: number, obj: Array<T>) => boolean, thisArg?: any): T | undefined;
|
||||
find(predicate: (value: T, index: number, obj: T[]) => boolean, thisArg?: any): T | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -21,7 +21,7 @@ interface Array<T> {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: T, index: number, obj: Array<T>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (value: T, index: number, obj: T[]) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Returns the this object after filling the section identified by start and end with value
|
||||
@@ -52,13 +52,13 @@ interface ArrayConstructor {
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from<T, U = T>(arrayLike: ArrayLike<T>, mapfn?: (v: T, k: number) => U, thisArg?: any): Array<U>;
|
||||
from<T, U = T>(arrayLike: ArrayLike<T>, mapfn?: (v: T, k: number) => U, thisArg?: any): U[];
|
||||
|
||||
/**
|
||||
* Returns a new array from a set of elements.
|
||||
* @param items A set of elements to include in the new array object.
|
||||
*/
|
||||
of<T>(...items: T[]): Array<T>;
|
||||
of<T>(...items: T[]): T[];
|
||||
}
|
||||
|
||||
interface DateConstructor {
|
||||
|
||||
Vendored
+1
-37
@@ -54,7 +54,7 @@ interface ArrayConstructor {
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from<T, U = T>(iterable: Iterable<T>, mapfn?: (v: T, k: number) => U, thisArg?: any): Array<U>;
|
||||
from<T, U = T>(iterable: Iterable<T>, mapfn?: (v: T, k: number) => U, thisArg?: any): U[];
|
||||
}
|
||||
|
||||
interface ReadonlyArray<T> {
|
||||
@@ -209,10 +209,6 @@ interface String {
|
||||
[Symbol.iterator](): IterableIterator<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit integer values. The contents are initialized to 0. If the requested
|
||||
* number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int8Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
@@ -241,10 +237,6 @@ interface Int8ArrayConstructor {
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Int8Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint8Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
@@ -273,10 +265,6 @@ interface Uint8ArrayConstructor {
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Uint8Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit unsigned integer (clamped) values. The contents are initialized to 0.
|
||||
* If the requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint8ClampedArray {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
@@ -308,10 +296,6 @@ interface Uint8ClampedArrayConstructor {
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Uint8ClampedArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 16-bit signed integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int16Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
@@ -342,10 +326,6 @@ interface Int16ArrayConstructor {
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Int16Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 16-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint16Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
@@ -374,10 +354,6 @@ interface Uint16ArrayConstructor {
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Uint16Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 32-bit signed integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int32Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
@@ -406,10 +382,6 @@ interface Int32ArrayConstructor {
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Int32Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 32-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint32Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
@@ -438,10 +410,6 @@ interface Uint32ArrayConstructor {
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Uint32Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 32-bit float values. The contents are initialized to 0. If the requested number
|
||||
* of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Float32Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
@@ -470,10 +438,6 @@ interface Float32ArrayConstructor {
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Float32Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 64-bit float values. The contents are initialized to 0. If the requested
|
||||
* number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Float64Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
|
||||
Vendored
+1
-1
@@ -8,7 +8,7 @@ declare namespace Reflect {
|
||||
function getPrototypeOf(target: object): object;
|
||||
function has(target: object, propertyKey: PropertyKey): boolean;
|
||||
function isExtensible(target: object): boolean;
|
||||
function ownKeys(target: object): Array<PropertyKey>;
|
||||
function ownKeys(target: object): PropertyKey[];
|
||||
function preventExtensions(target: object): boolean;
|
||||
function set(target: object, propertyKey: PropertyKey, value: any, receiver?: any): boolean;
|
||||
function setPrototypeOf(target: object, proto: any): boolean;
|
||||
|
||||
Vendored
-42
@@ -240,12 +240,6 @@ interface String {
|
||||
split(splitter: { [Symbol.split](string: string, limit?: number): string[]; }, limit?: number): string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a raw buffer of binary data, which is used to store data for the
|
||||
* different typed arrays. ArrayBuffers cannot be read from or written to directly,
|
||||
* but can be passed to a typed array or DataView Object to interpret the raw
|
||||
* buffer as needed.
|
||||
*/
|
||||
interface ArrayBuffer {
|
||||
readonly [Symbol.toStringTag]: "ArrayBuffer";
|
||||
}
|
||||
@@ -254,74 +248,38 @@ interface DataView {
|
||||
readonly [Symbol.toStringTag]: "DataView";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit integer values. The contents are initialized to 0. If the requested
|
||||
* number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int8Array {
|
||||
readonly [Symbol.toStringTag]: "Int8Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint8Array {
|
||||
readonly [Symbol.toStringTag]: "UInt8Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit unsigned integer (clamped) values. The contents are initialized to 0.
|
||||
* If the requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint8ClampedArray {
|
||||
readonly [Symbol.toStringTag]: "Uint8ClampedArray";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 16-bit signed integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int16Array {
|
||||
readonly [Symbol.toStringTag]: "Int16Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 16-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint16Array {
|
||||
readonly [Symbol.toStringTag]: "Uint16Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 32-bit signed integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int32Array {
|
||||
readonly [Symbol.toStringTag]: "Int32Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 32-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint32Array {
|
||||
readonly [Symbol.toStringTag]: "Uint32Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 32-bit float values. The contents are initialized to 0. If the requested number
|
||||
* of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Float32Array {
|
||||
readonly [Symbol.toStringTag]: "Float32Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 64-bit float values. The contents are initialized to 0. If the requested
|
||||
* number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Float64Array {
|
||||
readonly [Symbol.toStringTag]: "Float64Array";
|
||||
}
|
||||
|
||||
Vendored
+18
-18
@@ -1577,7 +1577,7 @@ interface Int8Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
|
||||
find(predicate: (value: number, index: number, obj: Int8Array) => boolean, thisArg?: any): number | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -1588,7 +1588,7 @@ interface Int8Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (value: number, index: number, obj: Int8Array) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
@@ -1844,7 +1844,7 @@ interface Uint8Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
|
||||
find(predicate: (value: number, index: number, obj: Uint8Array) => boolean, thisArg?: any): number | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -1855,7 +1855,7 @@ interface Uint8Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (value: number, index: number, obj: Uint8Array) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
@@ -2111,7 +2111,7 @@ interface Uint8ClampedArray {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
|
||||
find(predicate: (value: number, index: number, obj: Uint8ClampedArray) => boolean, thisArg?: any): number | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -2122,7 +2122,7 @@ interface Uint8ClampedArray {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (value: number, index: number, obj: Uint8ClampedArray) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
@@ -2377,7 +2377,7 @@ interface Int16Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
|
||||
find(predicate: (value: number, index: number, obj: Int16Array) => boolean, thisArg?: any): number | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -2388,7 +2388,7 @@ interface Int16Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (value: number, index: number, obj: Int16Array) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
@@ -2644,7 +2644,7 @@ interface Uint16Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
|
||||
find(predicate: (value: number, index: number, obj: Uint16Array) => boolean, thisArg?: any): number | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -2655,7 +2655,7 @@ interface Uint16Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (value: number, index: number, obj: Uint16Array) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
@@ -2911,7 +2911,7 @@ interface Int32Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
|
||||
find(predicate: (value: number, index: number, obj: Int32Array) => boolean, thisArg?: any): number | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -2922,7 +2922,7 @@ interface Int32Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (value: number, index: number, obj: Int32Array) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
@@ -3178,7 +3178,7 @@ interface Uint32Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
|
||||
find(predicate: (value: number, index: number, obj: Uint32Array) => boolean, thisArg?: any): number | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -3189,7 +3189,7 @@ interface Uint32Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (value: number, index: number, obj: Uint32Array) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
@@ -3444,7 +3444,7 @@ interface Float32Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
|
||||
find(predicate: (value: number, index: number, obj: Float32Array) => boolean, thisArg?: any): number | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -3455,7 +3455,7 @@ interface Float32Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (value: number, index: number, obj: Float32Array) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
@@ -3712,7 +3712,7 @@ interface Float64Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
|
||||
find(predicate: (value: number, index: number, obj: Float64Array) => boolean, thisArg?: any): number | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -3723,7 +3723,7 @@ interface Float64Array {
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (value: number, index: number, obj: Float64Array) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
|
||||
Vendored
+18
-7
@@ -201,10 +201,18 @@ declare var WScript: {
|
||||
Sleep(intTime: number): void;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents an Automation SAFEARRAY
|
||||
*/
|
||||
declare class SafeArray<T = any> {
|
||||
private constructor();
|
||||
private SafeArray_typekey: SafeArray<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows enumerating over a COM collection, which may not have indexed item access.
|
||||
*/
|
||||
interface Enumerator<T> {
|
||||
interface Enumerator<T = any> {
|
||||
/**
|
||||
* Returns true if the current item is the last one in the collection, or the collection is empty,
|
||||
* or the current item is undefined.
|
||||
@@ -230,8 +238,9 @@ interface Enumerator<T> {
|
||||
}
|
||||
|
||||
interface EnumeratorConstructor {
|
||||
new <T>(collection: any): Enumerator<T>;
|
||||
new (collection: any): Enumerator<any>;
|
||||
new <T = any>(safearray: SafeArray<T>): Enumerator<T>;
|
||||
new <T = any>(collection: { Item(index: any): T }): Enumerator<T>;
|
||||
new <T = any>(collection: any): Enumerator<T>;
|
||||
}
|
||||
|
||||
declare var Enumerator: EnumeratorConstructor;
|
||||
@@ -239,7 +248,7 @@ declare var Enumerator: EnumeratorConstructor;
|
||||
/**
|
||||
* Enables reading from a COM safe array, which might have an alternate lower bound, or multiple dimensions.
|
||||
*/
|
||||
interface VBArray<T> {
|
||||
interface VBArray<T = any> {
|
||||
/**
|
||||
* Returns the number of dimensions (1-based).
|
||||
*/
|
||||
@@ -271,8 +280,7 @@ interface VBArray<T> {
|
||||
}
|
||||
|
||||
interface VBArrayConstructor {
|
||||
new <T>(safeArray: any): VBArray<T>;
|
||||
new (safeArray: any): VBArray<any>;
|
||||
new <T = any>(safeArray: SafeArray<T>): VBArray<T>;
|
||||
}
|
||||
|
||||
declare var VBArray: VBArrayConstructor;
|
||||
@@ -280,7 +288,10 @@ declare var VBArray: VBArrayConstructor;
|
||||
/**
|
||||
* Automation date (VT_DATE)
|
||||
*/
|
||||
interface VarDate { }
|
||||
declare class VarDate {
|
||||
private constructor();
|
||||
private VarDate_typekey: VarDate;
|
||||
}
|
||||
|
||||
interface DateConstructor {
|
||||
new (vd: VarDate): Date;
|
||||
|
||||
@@ -573,7 +573,7 @@ namespace ts.server {
|
||||
|
||||
getEditsForRefactor(
|
||||
fileName: string,
|
||||
_formatOptions: FormatCodeSettings,
|
||||
formatOptions: FormatCodeSettings,
|
||||
positionOrRange: number | TextRange,
|
||||
refactorName: string,
|
||||
actionName: string): RefactorEditInfo {
|
||||
@@ -581,6 +581,7 @@ namespace ts.server {
|
||||
const args = this.createFileLocationOrRangeRequestArgs(positionOrRange, fileName) as protocol.GetEditsForRefactorRequestArgs;
|
||||
args.refactor = refactorName;
|
||||
args.action = actionName;
|
||||
args.formatOptions = formatOptions;
|
||||
|
||||
const request = this.processRequest<protocol.GetEditsForRefactorRequest>(CommandNames.GetEditsForRefactor, args);
|
||||
const response = this.processResponse<protocol.GetEditsForRefactorResponse>(request);
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
export interface SafeList {
|
||||
[name: string]: { match: RegExp, exclude?: Array<Array<string | number>>, types?: string[] };
|
||||
[name: string]: { match: RegExp, exclude?: (string | number)[][], types?: string[] };
|
||||
}
|
||||
|
||||
function prepareConvertersForEnumLikeCompilerOptions(commandLineOptions: CommandLineOption[]): Map<Map<number>> {
|
||||
@@ -1457,7 +1457,8 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
project.setProjectErrors(configFileErrors);
|
||||
this.addFilesToNonInferredProjectAndUpdateGraph(project, projectOptions.files, fileNamePropertyReader, projectOptions.typeAcquisition);
|
||||
const filesToAdd = projectOptions.files.concat(project.getExternalFiles());
|
||||
this.addFilesToNonInferredProjectAndUpdateGraph(project, filesToAdd, fileNamePropertyReader, projectOptions.typeAcquisition);
|
||||
this.configuredProjects.set(project.canonicalConfigFilePath, project);
|
||||
this.setConfigFileExistenceByNewConfiguredProject(project);
|
||||
this.sendProjectTelemetry(project.getConfigFilePath(), project, projectOptions);
|
||||
@@ -2105,7 +2106,7 @@ namespace ts.server {
|
||||
|
||||
if (rule.exclude) {
|
||||
for (const exclude of rule.exclude) {
|
||||
const processedRule = root.replace(rule.match, (...groups: Array<string>) => {
|
||||
const processedRule = root.replace(rule.match, (...groups: string[]) => {
|
||||
return exclude.map(groupNumberOrString => {
|
||||
// RegExp group numbers are 1-based, but the first element in groups
|
||||
// is actually the original string, so it all works out in the end.
|
||||
|
||||
@@ -957,7 +957,8 @@ namespace ts.server {
|
||||
}
|
||||
// compute and return the difference
|
||||
const lastReportedFileNames = this.lastReportedFileNames;
|
||||
const currentFiles = arrayToSet(this.getFileNames());
|
||||
const externalFiles = this.getExternalFiles().map(f => toNormalizedPath(f));
|
||||
const currentFiles = arrayToSet(this.getFileNames().concat(externalFiles));
|
||||
|
||||
const added: string[] = [];
|
||||
const removed: string[] = [];
|
||||
@@ -980,7 +981,8 @@ namespace ts.server {
|
||||
else {
|
||||
// unknown version - return everything
|
||||
const projectFileNames = this.getFileNames();
|
||||
this.lastReportedFileNames = arrayToSet(projectFileNames);
|
||||
const externalFiles = this.getExternalFiles().map(f => toNormalizedPath(f));
|
||||
this.lastReportedFileNames = arrayToSet(projectFileNames.concat(externalFiles));
|
||||
this.lastReportedVersion = this.projectStructureVersion;
|
||||
return { info, files: projectFileNames, projectErrors: this.getGlobalProjectErrors() };
|
||||
}
|
||||
@@ -1290,6 +1292,9 @@ namespace ts.server {
|
||||
}
|
||||
catch (e) {
|
||||
this.projectService.logger.info(`A plugin threw an exception in getExternalFiles: ${e}`);
|
||||
if (e.stack) {
|
||||
this.projectService.logger.info(e.stack);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -494,6 +494,7 @@ namespace ts.server.protocol {
|
||||
refactor: string;
|
||||
/* The 'name' property from the refactoring action */
|
||||
action: string;
|
||||
formatOptions?: FormatCodeSettings,
|
||||
};
|
||||
|
||||
|
||||
|
||||
+84
-70
@@ -380,82 +380,96 @@ namespace ts.server {
|
||||
this.logger.info(`Received response: ${JSON.stringify(response)}`);
|
||||
}
|
||||
|
||||
if (response.kind === EventInitializationFailed) {
|
||||
if (!this.eventSender) {
|
||||
return;
|
||||
}
|
||||
const body: protocol.TypesInstallerInitializationFailedEventBody = {
|
||||
message: response.message
|
||||
};
|
||||
const eventName: protocol.TypesInstallerInitializationFailedEventName = "typesInstallerInitializationFailed";
|
||||
this.eventSender.event(body, eventName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.kind === EventBeginInstallTypes) {
|
||||
if (!this.eventSender) {
|
||||
return;
|
||||
}
|
||||
const body: protocol.BeginInstallTypesEventBody = {
|
||||
eventId: response.eventId,
|
||||
packages: response.packagesToInstall,
|
||||
};
|
||||
const eventName: protocol.BeginInstallTypesEventName = "beginInstallTypes";
|
||||
this.eventSender.event(body, eventName);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.kind === EventEndInstallTypes) {
|
||||
if (!this.eventSender) {
|
||||
return;
|
||||
}
|
||||
if (this.telemetryEnabled) {
|
||||
const body: protocol.TypingsInstalledTelemetryEventBody = {
|
||||
telemetryEventName: "typingsInstalled",
|
||||
payload: {
|
||||
installedPackages: response.packagesToInstall.join(","),
|
||||
installSuccess: response.installSuccess,
|
||||
typingsInstallerVersion: response.typingsInstallerVersion
|
||||
}
|
||||
switch (response.kind) {
|
||||
case EventInitializationFailed:
|
||||
{
|
||||
if (!this.eventSender) {
|
||||
break;
|
||||
}
|
||||
const body: protocol.TypesInstallerInitializationFailedEventBody = {
|
||||
message: response.message
|
||||
};
|
||||
const eventName: protocol.TelemetryEventName = "telemetry";
|
||||
const eventName: protocol.TypesInstallerInitializationFailedEventName = "typesInstallerInitializationFailed";
|
||||
this.eventSender.event(body, eventName);
|
||||
}
|
||||
|
||||
const body: protocol.EndInstallTypesEventBody = {
|
||||
eventId: response.eventId,
|
||||
packages: response.packagesToInstall,
|
||||
success: response.installSuccess,
|
||||
};
|
||||
const eventName: protocol.EndInstallTypesEventName = "endInstallTypes";
|
||||
this.eventSender.event(body, eventName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.activeRequestCount > 0) {
|
||||
this.activeRequestCount--;
|
||||
}
|
||||
else {
|
||||
Debug.fail("Received too many responses");
|
||||
}
|
||||
|
||||
while (this.requestQueue.length > 0) {
|
||||
const queuedRequest = this.requestQueue.shift();
|
||||
if (this.requestMap.get(queuedRequest.operationId) === queuedRequest) {
|
||||
this.requestMap.delete(queuedRequest.operationId);
|
||||
this.scheduleRequest(queuedRequest);
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.logger.hasLevel(LogLevel.verbose)) {
|
||||
this.logger.info(`Skipping defunct request for: ${queuedRequest.operationId}`);
|
||||
case EventBeginInstallTypes:
|
||||
{
|
||||
if (!this.eventSender) {
|
||||
break;
|
||||
}
|
||||
const body: protocol.BeginInstallTypesEventBody = {
|
||||
eventId: response.eventId,
|
||||
packages: response.packagesToInstall,
|
||||
};
|
||||
const eventName: protocol.BeginInstallTypesEventName = "beginInstallTypes";
|
||||
this.eventSender.event(body, eventName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case EventEndInstallTypes:
|
||||
{
|
||||
if (!this.eventSender) {
|
||||
break;
|
||||
}
|
||||
if (this.telemetryEnabled) {
|
||||
const body: protocol.TypingsInstalledTelemetryEventBody = {
|
||||
telemetryEventName: "typingsInstalled",
|
||||
payload: {
|
||||
installedPackages: response.packagesToInstall.join(","),
|
||||
installSuccess: response.installSuccess,
|
||||
typingsInstallerVersion: response.typingsInstallerVersion
|
||||
}
|
||||
};
|
||||
const eventName: protocol.TelemetryEventName = "telemetry";
|
||||
this.eventSender.event(body, eventName);
|
||||
}
|
||||
|
||||
this.projectService.updateTypingsForProject(response);
|
||||
if (response.kind === ActionSet && this.socket) {
|
||||
this.sendEvent(0, "setTypings", response);
|
||||
const body: protocol.EndInstallTypesEventBody = {
|
||||
eventId: response.eventId,
|
||||
packages: response.packagesToInstall,
|
||||
success: response.installSuccess,
|
||||
};
|
||||
const eventName: protocol.EndInstallTypesEventName = "endInstallTypes";
|
||||
this.eventSender.event(body, eventName);
|
||||
break;
|
||||
}
|
||||
case ActionInvalidate:
|
||||
{
|
||||
this.projectService.updateTypingsForProject(response);
|
||||
break;
|
||||
}
|
||||
case ActionSet:
|
||||
{
|
||||
if (this.activeRequestCount > 0) {
|
||||
this.activeRequestCount--;
|
||||
}
|
||||
else {
|
||||
Debug.fail("Received too many responses");
|
||||
}
|
||||
|
||||
while (this.requestQueue.length > 0) {
|
||||
const queuedRequest = this.requestQueue.shift();
|
||||
if (this.requestMap.get(queuedRequest.operationId) === queuedRequest) {
|
||||
this.requestMap.delete(queuedRequest.operationId);
|
||||
this.scheduleRequest(queuedRequest);
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.logger.hasLevel(LogLevel.verbose)) {
|
||||
this.logger.info(`Skipping defunct request for: ${queuedRequest.operationId}`);
|
||||
}
|
||||
}
|
||||
|
||||
this.projectService.updateTypingsForProject(response);
|
||||
|
||||
if (this.socket) {
|
||||
this.sendEvent(0, "setTypings", response);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assertTypeIsNever(response);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-11
@@ -1488,7 +1488,7 @@ namespace ts.server {
|
||||
|
||||
const result = project.getLanguageService().getEditsForRefactor(
|
||||
file,
|
||||
this.projectService.getFormatCodeOptions(),
|
||||
args.formatOptions ? convertFormatOptions(args.formatOptions) : this.projectService.getFormatCodeOptions(),
|
||||
position || textRange,
|
||||
args.refactor,
|
||||
args.action
|
||||
@@ -1608,7 +1608,10 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
// No need to analyze lib.d.ts
|
||||
let fileNamesInProject = fileNames.filter(value => value.indexOf("lib.d.ts") < 0);
|
||||
const fileNamesInProject = fileNames.filter(value => value.indexOf("lib.d.ts") < 0);
|
||||
if (fileNamesInProject.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sort the file name list to make the recently touched files come first
|
||||
const highPriorityFiles: NormalizedPath[] = [];
|
||||
@@ -1624,7 +1627,7 @@ namespace ts.server {
|
||||
else {
|
||||
const info = this.projectService.getScriptInfo(fileNameInProject);
|
||||
if (!info.isScriptOpen()) {
|
||||
if (fileNameInProject.indexOf(Extension.Dts) > 0) {
|
||||
if (fileExtensionIs(fileNameInProject, Extension.Dts)) {
|
||||
veryLowPriorityFiles.push(fileNameInProject);
|
||||
}
|
||||
else {
|
||||
@@ -1637,14 +1640,11 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
fileNamesInProject = highPriorityFiles.concat(mediumPriorityFiles).concat(lowPriorityFiles).concat(veryLowPriorityFiles);
|
||||
|
||||
if (fileNamesInProject.length > 0) {
|
||||
const checkList = fileNamesInProject.map(fileName => ({ fileName, project }));
|
||||
// Project level error analysis runs on background files too, therefore
|
||||
// doesn't require the file to be opened
|
||||
this.updateErrorCheck(next, checkList, delay, /*requireOpen*/ false);
|
||||
}
|
||||
const sortedFiles = [...highPriorityFiles, ...mediumPriorityFiles, ...lowPriorityFiles, ...veryLowPriorityFiles];
|
||||
const checkList = sortedFiles.map(fileName => ({ fileName, project }));
|
||||
// Project level error analysis runs on background files too, therefore
|
||||
// doesn't require the file to be opened
|
||||
this.updateErrorCheck(next, checkList, delay, /*requireOpen*/ false);
|
||||
}
|
||||
|
||||
getCanonicalFileName(fileName: string) {
|
||||
|
||||
@@ -978,7 +978,7 @@ namespace ts.Completions {
|
||||
isNewIdentifierLocation = true;
|
||||
const typeForObject = typeChecker.getContextualType(<ObjectLiteralExpression>objectLikeContainer);
|
||||
if (!typeForObject) return false;
|
||||
typeMembers = typeChecker.getAllPossiblePropertiesOfType(typeForObject);
|
||||
typeMembers = getPropertiesForCompletion(typeForObject, typeChecker);
|
||||
existingMembers = (<ObjectLiteralExpression>objectLikeContainer).properties;
|
||||
}
|
||||
else {
|
||||
@@ -1766,4 +1766,20 @@ namespace ts.Completions {
|
||||
return node.parent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all properties on a type, but if that type is a union of several types,
|
||||
* tries to only include those types which declare properties, not methods.
|
||||
* This ensures that we don't try providing completions for all the methods on e.g. Array.
|
||||
*/
|
||||
function getPropertiesForCompletion(type: Type, checker: TypeChecker): Symbol[] {
|
||||
if (!(type.flags & TypeFlags.Union)) {
|
||||
return checker.getPropertiesOfType(type);
|
||||
}
|
||||
|
||||
const { types } = type as UnionType;
|
||||
const filteredTypes = types.filter(memberType => !(memberType.flags & TypeFlags.Primitive || checker.isArrayLikeType(memberType)));
|
||||
// If there are no property-only types, just provide completions for every type as usual.
|
||||
return checker.getAllPossiblePropertiesOfTypes(filteredTypes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,7 +515,7 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
|
||||
// Source file ID → symbol ID → Whether the symbol has been searched for in the source file.
|
||||
private readonly sourceFileToSeenSymbols: Array<Array<true>> = [];
|
||||
private readonly sourceFileToSeenSymbols: true[][] = [];
|
||||
/** Returns `true` the first time we search for a symbol in a file and `false` afterwards. */
|
||||
markSearchedSymbol(sourceFile: SourceFile, symbol: Symbol): boolean {
|
||||
const sourceId = getNodeId(sourceFile);
|
||||
|
||||
@@ -53,28 +53,19 @@ namespace ts.formatting {
|
||||
return res;
|
||||
|
||||
function advance(): void {
|
||||
Debug.assert(scanner !== undefined, "Scanner should be present");
|
||||
|
||||
lastTokenInfo = undefined;
|
||||
const isStarted = scanner.getStartPos() !== startPos;
|
||||
|
||||
if (isStarted) {
|
||||
if (trailingTrivia) {
|
||||
Debug.assert(trailingTrivia.length !== 0);
|
||||
wasNewLine = lastOrUndefined(trailingTrivia).kind === SyntaxKind.NewLineTrivia;
|
||||
}
|
||||
else {
|
||||
wasNewLine = false;
|
||||
}
|
||||
wasNewLine = trailingTrivia && lastOrUndefined(trailingTrivia)!.kind === SyntaxKind.NewLineTrivia;
|
||||
}
|
||||
else {
|
||||
scanner.scan();
|
||||
}
|
||||
|
||||
leadingTrivia = undefined;
|
||||
trailingTrivia = undefined;
|
||||
|
||||
if (!isStarted) {
|
||||
scanner.scan();
|
||||
}
|
||||
|
||||
let pos = scanner.getStartPos();
|
||||
|
||||
// Read leading trivia and token
|
||||
@@ -94,25 +85,20 @@ namespace ts.formatting {
|
||||
|
||||
pos = scanner.getStartPos();
|
||||
|
||||
if (!leadingTrivia) {
|
||||
leadingTrivia = [];
|
||||
}
|
||||
leadingTrivia.push(item);
|
||||
leadingTrivia = append(leadingTrivia, item);
|
||||
}
|
||||
|
||||
savedPos = scanner.getStartPos();
|
||||
}
|
||||
|
||||
function shouldRescanGreaterThanToken(node: Node): boolean {
|
||||
if (node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.GreaterThanEqualsToken:
|
||||
case SyntaxKind.GreaterThanGreaterThanEqualsToken:
|
||||
case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
|
||||
case SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
|
||||
case SyntaxKind.GreaterThanGreaterThanToken:
|
||||
return true;
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.GreaterThanEqualsToken:
|
||||
case SyntaxKind.GreaterThanGreaterThanEqualsToken:
|
||||
case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
|
||||
case SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
|
||||
case SyntaxKind.GreaterThanGreaterThanToken:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -125,7 +111,8 @@ namespace ts.formatting {
|
||||
case SyntaxKind.JsxOpeningElement:
|
||||
case SyntaxKind.JsxClosingElement:
|
||||
case SyntaxKind.JsxSelfClosingElement:
|
||||
return node.kind === SyntaxKind.Identifier;
|
||||
// May parse an identifier like `module-layout`; that will be scanned as a keyword at first, but we should parse the whole thing to get an identifier.
|
||||
return isKeyword(node.kind) || node.kind === SyntaxKind.Identifier;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +120,7 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
function shouldRescanJsxText(node: Node): boolean {
|
||||
return node && node.kind === SyntaxKind.JsxText;
|
||||
return node.kind === SyntaxKind.JsxText;
|
||||
}
|
||||
|
||||
function shouldRescanSlashToken(container: Node): boolean {
|
||||
@@ -150,16 +137,7 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
function readTokenInfo(n: Node): TokenInfo {
|
||||
Debug.assert(scanner !== undefined);
|
||||
|
||||
if (!isOnToken()) {
|
||||
// scanner is not on the token (either advance was not called yet or scanner is already past the end position)
|
||||
return {
|
||||
leadingTrivia,
|
||||
trailingTrivia: undefined,
|
||||
token: undefined
|
||||
};
|
||||
}
|
||||
Debug.assert(isOnToken());
|
||||
|
||||
// normally scanner returns the smallest available token
|
||||
// check the kind of context node to determine if scanner should have more greedy behavior and consume more text.
|
||||
@@ -193,33 +171,7 @@ namespace ts.formatting {
|
||||
scanner.scan();
|
||||
}
|
||||
|
||||
let currentToken = scanner.getToken();
|
||||
|
||||
if (expectedScanAction === ScanAction.RescanGreaterThanToken && currentToken === SyntaxKind.GreaterThanToken) {
|
||||
currentToken = scanner.reScanGreaterToken();
|
||||
Debug.assert(n.kind === currentToken);
|
||||
lastScanAction = ScanAction.RescanGreaterThanToken;
|
||||
}
|
||||
else if (expectedScanAction === ScanAction.RescanSlashToken && startsWithSlashToken(currentToken)) {
|
||||
currentToken = scanner.reScanSlashToken();
|
||||
Debug.assert(n.kind === currentToken);
|
||||
lastScanAction = ScanAction.RescanSlashToken;
|
||||
}
|
||||
else if (expectedScanAction === ScanAction.RescanTemplateToken && currentToken === SyntaxKind.CloseBraceToken) {
|
||||
currentToken = scanner.reScanTemplateToken();
|
||||
lastScanAction = ScanAction.RescanTemplateToken;
|
||||
}
|
||||
else if (expectedScanAction === ScanAction.RescanJsxIdentifier && currentToken === SyntaxKind.Identifier) {
|
||||
currentToken = scanner.scanJsxIdentifier();
|
||||
lastScanAction = ScanAction.RescanJsxIdentifier;
|
||||
}
|
||||
else if (expectedScanAction === ScanAction.RescanJsxText) {
|
||||
currentToken = scanner.reScanJsxToken();
|
||||
lastScanAction = ScanAction.RescanJsxText;
|
||||
}
|
||||
else {
|
||||
lastScanAction = ScanAction.Scan;
|
||||
}
|
||||
let currentToken = getNextToken(n, expectedScanAction);
|
||||
|
||||
const token: TextRangeWithKind = {
|
||||
pos: scanner.getStartPos(),
|
||||
@@ -260,9 +212,47 @@ namespace ts.formatting {
|
||||
return fixTokenKind(lastTokenInfo, n);
|
||||
}
|
||||
|
||||
function isOnToken(): boolean {
|
||||
Debug.assert(scanner !== undefined);
|
||||
function getNextToken(n: Node, expectedScanAction: ScanAction): SyntaxKind {
|
||||
const token = scanner.getToken();
|
||||
lastScanAction = ScanAction.Scan;
|
||||
switch (expectedScanAction) {
|
||||
case ScanAction.RescanGreaterThanToken:
|
||||
if (token === SyntaxKind.GreaterThanToken) {
|
||||
lastScanAction = ScanAction.RescanGreaterThanToken;
|
||||
const newToken = scanner.reScanGreaterToken();
|
||||
Debug.assert(n.kind === newToken);
|
||||
return newToken;
|
||||
}
|
||||
break;
|
||||
case ScanAction.RescanSlashToken:
|
||||
if (startsWithSlashToken(token)) {
|
||||
lastScanAction = ScanAction.RescanSlashToken;
|
||||
const newToken = scanner.reScanSlashToken();
|
||||
Debug.assert(n.kind === newToken);
|
||||
return newToken;
|
||||
}
|
||||
break;
|
||||
case ScanAction.RescanTemplateToken:
|
||||
if (token === SyntaxKind.CloseBraceToken) {
|
||||
lastScanAction = ScanAction.RescanTemplateToken;
|
||||
return scanner.reScanTemplateToken();
|
||||
}
|
||||
break;
|
||||
case ScanAction.RescanJsxIdentifier:
|
||||
lastScanAction = ScanAction.RescanJsxIdentifier;
|
||||
return scanner.scanJsxIdentifier();
|
||||
case ScanAction.RescanJsxText:
|
||||
lastScanAction = ScanAction.RescanJsxText;
|
||||
return scanner.reScanJsxToken();
|
||||
case ScanAction.Scan:
|
||||
break;
|
||||
default:
|
||||
Debug.assertNever(expectedScanAction);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
function isOnToken(): boolean {
|
||||
const current = lastTokenInfo ? lastTokenInfo.token.kind : scanner.getToken();
|
||||
const startPos = lastTokenInfo ? lastTokenInfo.token.pos : scanner.getStartPos();
|
||||
return startPos < endPos && current !== SyntaxKind.EndOfFileToken && !isTrivia(current);
|
||||
|
||||
@@ -755,9 +755,8 @@ namespace ts.formatting {
|
||||
return true;
|
||||
case SyntaxKind.Block: {
|
||||
const blockParent = context.currentTokenParent.parent;
|
||||
if (blockParent.kind !== SyntaxKind.ArrowFunction &&
|
||||
blockParent.kind !== SyntaxKind.FunctionExpression
|
||||
) {
|
||||
// In a codefix scenario, we can't rely on parents being set. So just always return true.
|
||||
if (!blockParent || blockParent.kind !== SyntaxKind.ArrowFunction && blockParent.kind !== SyntaxKind.FunctionExpression) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,6 +505,8 @@ namespace ts.formatting {
|
||||
case SyntaxKind.NamedImports:
|
||||
case SyntaxKind.ExportSpecifier:
|
||||
case SyntaxKind.ImportSpecifier:
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace ts.FindAllReferences {
|
||||
export interface ImportsResult {
|
||||
/** For every import of the symbol, the location and local symbol for the import. */
|
||||
importSearches: Array<[Identifier, Symbol]>;
|
||||
importSearches: [Identifier, Symbol][];
|
||||
/** For rename imports/exports `{ foo as bar }`, `foo` is not a local, so it may be added as a reference immediately without further searching. */
|
||||
singleReferences: Identifier[];
|
||||
/** List of source files that may (or may not) use the symbol via a namespace. (For UMD modules this is every file.) */
|
||||
@@ -180,7 +180,7 @@ namespace ts.FindAllReferences {
|
||||
* But re-exports will be placed in 'singleReferences' since they cannot be locally referenced.
|
||||
*/
|
||||
function getSearchesFromDirectImports(directImports: Importer[], exportSymbol: Symbol, exportKind: ExportKind, checker: TypeChecker, isForRename: boolean): Pick<ImportsResult, "importSearches" | "singleReferences"> {
|
||||
const importSearches: Array<[Identifier, Symbol]> = [];
|
||||
const importSearches: [Identifier, Symbol][] = [];
|
||||
const singleReferences: Identifier[] = [];
|
||||
function addSearch(location: Identifier, symbol: Symbol): void {
|
||||
importSearches.push([location, symbol]);
|
||||
|
||||
+142
-144
@@ -21,185 +21,183 @@ namespace ts.NavigateTo {
|
||||
}
|
||||
|
||||
forEachEntry(sourceFile.getNamedDeclarations(), (declarations, name) => {
|
||||
if (declarations) {
|
||||
// First do a quick check to see if the name of the declaration matches the
|
||||
// last portion of the (possibly) dotted name they're searching for.
|
||||
let matches = patternMatcher.getMatchesForLastSegmentOfPattern(name);
|
||||
|
||||
if (!matches) {
|
||||
return; // continue to next named declarations
|
||||
}
|
||||
|
||||
for (const declaration of declarations) {
|
||||
// It was a match! If the pattern has dots in it, then also see if the
|
||||
// declaration container matches as well.
|
||||
if (patternMatcher.patternContainsDots) {
|
||||
const containers = getContainers(declaration);
|
||||
if (!containers) {
|
||||
return true; // Break out of named declarations and go to the next source file.
|
||||
}
|
||||
|
||||
matches = patternMatcher.getMatches(containers, name);
|
||||
|
||||
if (!matches) {
|
||||
return; // continue to next named declarations
|
||||
}
|
||||
}
|
||||
|
||||
const fileName = sourceFile.fileName;
|
||||
const matchKind = bestMatchKind(matches);
|
||||
rawItems.push({ name, fileName, matchKind, isCaseSensitive: allMatchesAreCaseSensitive(matches), declaration });
|
||||
}
|
||||
}
|
||||
getItemsFromNamedDeclaration(patternMatcher, name, declarations, checker, sourceFile.fileName, rawItems);
|
||||
});
|
||||
}
|
||||
|
||||
// Remove imports when the imported declaration is already in the list and has the same name.
|
||||
rawItems = filter(rawItems, item => {
|
||||
const decl = item.declaration;
|
||||
if (decl.kind === SyntaxKind.ImportClause || decl.kind === SyntaxKind.ImportSpecifier || decl.kind === SyntaxKind.ImportEqualsDeclaration) {
|
||||
const importer = checker.getSymbolAtLocation((decl as NamedDeclaration).name);
|
||||
const imported = checker.getAliasedSymbol(importer);
|
||||
return importer.escapedName !== imported.escapedName;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
rawItems.sort(compareNavigateToItems);
|
||||
if (maxResultCount !== undefined) {
|
||||
rawItems = rawItems.slice(0, maxResultCount);
|
||||
}
|
||||
return rawItems.map(createNavigateToItem);
|
||||
}
|
||||
|
||||
const items = map(rawItems, createNavigateToItem);
|
||||
function getItemsFromNamedDeclaration(patternMatcher: PatternMatcher, name: string, declarations: ReadonlyArray<Declaration>, checker: TypeChecker, fileName: string, rawItems: Push<RawNavigateToItem>): void {
|
||||
// First do a quick check to see if the name of the declaration matches the
|
||||
// last portion of the (possibly) dotted name they're searching for.
|
||||
const matches = patternMatcher.getMatchesForLastSegmentOfPattern(name);
|
||||
|
||||
return items;
|
||||
if (!matches) {
|
||||
return; // continue to next named declarations
|
||||
}
|
||||
|
||||
function allMatchesAreCaseSensitive(matches: PatternMatch[]): boolean {
|
||||
Debug.assert(matches.length > 0);
|
||||
for (const declaration of declarations) {
|
||||
if (!shouldKeepItem(declaration, checker)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// This is a case sensitive match, only if all the submatches were case sensitive.
|
||||
for (const match of matches) {
|
||||
if (!match.isCaseSensitive) {
|
||||
// It was a match! If the pattern has dots in it, then also see if the
|
||||
// declaration container matches as well.
|
||||
let containerMatches = matches;
|
||||
if (patternMatcher.patternContainsDots) {
|
||||
containerMatches = patternMatcher.getMatches(getContainers(declaration), name);
|
||||
if (!containerMatches) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const matchKind = bestMatchKind(containerMatches);
|
||||
const isCaseSensitive = allMatchesAreCaseSensitive(containerMatches);
|
||||
rawItems.push({ name, fileName, matchKind, isCaseSensitive, declaration });
|
||||
}
|
||||
}
|
||||
|
||||
function shouldKeepItem(declaration: Declaration, checker: ts.TypeChecker): boolean {
|
||||
switch (declaration.kind) {
|
||||
case SyntaxKind.ImportClause:
|
||||
case SyntaxKind.ImportSpecifier:
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
const importer = checker.getSymbolAtLocation((declaration as ImportClause | ImportSpecifier | ImportEqualsDeclaration).name);
|
||||
const imported = checker.getAliasedSymbol(importer);
|
||||
return importer.escapedName !== imported.escapedName;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function allMatchesAreCaseSensitive(matches: ReadonlyArray<PatternMatch>): boolean {
|
||||
Debug.assert(matches.length > 0);
|
||||
|
||||
// This is a case sensitive match, only if all the submatches were case sensitive.
|
||||
for (const match of matches) {
|
||||
if (!match.isCaseSensitive) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function tryAddSingleDeclarationName(declaration: Declaration, containers: string[]): boolean {
|
||||
if (declaration) {
|
||||
const name = getNameOfDeclaration(declaration);
|
||||
if (name) {
|
||||
const text = getTextOfIdentifierOrLiteral(name as (Identifier | LiteralExpression));
|
||||
if (text !== undefined) {
|
||||
containers.unshift(text);
|
||||
}
|
||||
else if (name.kind === SyntaxKind.ComputedPropertyName) {
|
||||
return tryAddComputedPropertyName((<ComputedPropertyName>name).expression, containers, /*includeLastPortion*/ true);
|
||||
}
|
||||
else {
|
||||
// Don't know how to add this.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only added the names of computed properties if they're simple dotted expressions, like:
|
||||
//
|
||||
// [X.Y.Z]() { }
|
||||
function tryAddComputedPropertyName(expression: Expression, containers: string[], includeLastPortion: boolean): boolean {
|
||||
const text = getTextOfIdentifierOrLiteral(expression as LiteralExpression);
|
||||
if (text !== undefined) {
|
||||
if (includeLastPortion) {
|
||||
containers.unshift(text);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function tryAddSingleDeclarationName(declaration: Declaration, containers: string[]) {
|
||||
if (declaration) {
|
||||
const name = getNameOfDeclaration(declaration);
|
||||
if (name) {
|
||||
const text = getTextOfIdentifierOrLiteral(name as (Identifier | LiteralExpression));
|
||||
if (text !== undefined) {
|
||||
containers.unshift(text);
|
||||
}
|
||||
else if (name.kind === SyntaxKind.ComputedPropertyName) {
|
||||
return tryAddComputedPropertyName((<ComputedPropertyName>name).expression, containers, /*includeLastPortion*/ true);
|
||||
}
|
||||
else {
|
||||
// Don't know how to add this.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (expression.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
const propertyAccess = <PropertyAccessExpression>expression;
|
||||
if (includeLastPortion) {
|
||||
containers.unshift(propertyAccess.name.text);
|
||||
}
|
||||
|
||||
return true;
|
||||
return tryAddComputedPropertyName(propertyAccess.expression, containers, /*includeLastPortion*/ true);
|
||||
}
|
||||
|
||||
// Only added the names of computed properties if they're simple dotted expressions, like:
|
||||
//
|
||||
// [X.Y.Z]() { }
|
||||
function tryAddComputedPropertyName(expression: Expression, containers: string[], includeLastPortion: boolean): boolean {
|
||||
const text = getTextOfIdentifierOrLiteral(expression as LiteralExpression);
|
||||
if (text !== undefined) {
|
||||
if (includeLastPortion) {
|
||||
containers.unshift(text);
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function getContainers(declaration: Declaration): string[] {
|
||||
const containers: string[] = [];
|
||||
|
||||
// First, if we started with a computed property name, then add all but the last
|
||||
// portion into the container array.
|
||||
const name = getNameOfDeclaration(declaration);
|
||||
if (name.kind === SyntaxKind.ComputedPropertyName) {
|
||||
if (!tryAddComputedPropertyName((<ComputedPropertyName>name).expression, containers, /*includeLastPortion*/ false)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (expression.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
const propertyAccess = <PropertyAccessExpression>expression;
|
||||
if (includeLastPortion) {
|
||||
containers.unshift(propertyAccess.name.text);
|
||||
}
|
||||
|
||||
return tryAddComputedPropertyName(propertyAccess.expression, containers, /*includeLastPortion*/ true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getContainers(declaration: Declaration) {
|
||||
const containers: string[] = [];
|
||||
// Now, walk up our containers, adding all their names to the container array.
|
||||
declaration = getContainerNode(declaration);
|
||||
|
||||
// First, if we started with a computed property name, then add all but the last
|
||||
// portion into the container array.
|
||||
const name = getNameOfDeclaration(declaration);
|
||||
if (name.kind === SyntaxKind.ComputedPropertyName) {
|
||||
if (!tryAddComputedPropertyName((<ComputedPropertyName>name).expression, containers, /*includeLastPortion*/ false)) {
|
||||
return undefined;
|
||||
}
|
||||
while (declaration) {
|
||||
if (!tryAddSingleDeclarationName(declaration, containers)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Now, walk up our containers, adding all their names to the container array.
|
||||
declaration = getContainerNode(declaration);
|
||||
}
|
||||
|
||||
while (declaration) {
|
||||
if (!tryAddSingleDeclarationName(declaration, containers)) {
|
||||
return undefined;
|
||||
}
|
||||
return containers;
|
||||
}
|
||||
|
||||
declaration = getContainerNode(declaration);
|
||||
function bestMatchKind(matches: ReadonlyArray<PatternMatch>): PatternMatchKind {
|
||||
Debug.assert(matches.length > 0);
|
||||
let bestMatchKind = PatternMatchKind.camelCase;
|
||||
|
||||
for (const match of matches) {
|
||||
const kind = match.kind;
|
||||
if (kind < bestMatchKind) {
|
||||
bestMatchKind = kind;
|
||||
}
|
||||
|
||||
return containers;
|
||||
}
|
||||
|
||||
function bestMatchKind(matches: PatternMatch[]) {
|
||||
Debug.assert(matches.length > 0);
|
||||
let bestMatchKind = PatternMatchKind.camelCase;
|
||||
return bestMatchKind;
|
||||
}
|
||||
|
||||
for (const match of matches) {
|
||||
const kind = match.kind;
|
||||
if (kind < bestMatchKind) {
|
||||
bestMatchKind = kind;
|
||||
}
|
||||
}
|
||||
function compareNavigateToItems(i1: RawNavigateToItem, i2: RawNavigateToItem): number {
|
||||
// TODO(cyrusn): get the gamut of comparisons that VS already uses here.
|
||||
// Right now we just sort by kind first, and then by name of the item.
|
||||
// We first sort case insensitively. So "Aaa" will come before "bar".
|
||||
// Then we sort case sensitively, so "aaa" will come before "Aaa".
|
||||
return i1.matchKind - i2.matchKind ||
|
||||
ts.compareStringsCaseInsensitive(i1.name, i2.name) ||
|
||||
ts.compareStrings(i1.name, i2.name);
|
||||
}
|
||||
|
||||
return bestMatchKind;
|
||||
}
|
||||
|
||||
function compareNavigateToItems(i1: RawNavigateToItem, i2: RawNavigateToItem) {
|
||||
// TODO(cyrusn): get the gamut of comparisons that VS already uses here.
|
||||
// Right now we just sort by kind first, and then by name of the item.
|
||||
// We first sort case insensitively. So "Aaa" will come before "bar".
|
||||
// Then we sort case sensitively, so "aaa" will come before "Aaa".
|
||||
return i1.matchKind - i2.matchKind ||
|
||||
ts.compareStringsCaseInsensitive(i1.name, i2.name) ||
|
||||
ts.compareStrings(i1.name, i2.name);
|
||||
}
|
||||
|
||||
function createNavigateToItem(rawItem: RawNavigateToItem): NavigateToItem {
|
||||
const declaration = rawItem.declaration;
|
||||
const container = <Declaration>getContainerNode(declaration);
|
||||
const containerName = container && getNameOfDeclaration(container);
|
||||
return {
|
||||
name: rawItem.name,
|
||||
kind: getNodeKind(declaration),
|
||||
kindModifiers: getNodeModifiers(declaration),
|
||||
matchKind: PatternMatchKind[rawItem.matchKind],
|
||||
isCaseSensitive: rawItem.isCaseSensitive,
|
||||
fileName: rawItem.fileName,
|
||||
textSpan: createTextSpanFromNode(declaration),
|
||||
// TODO(jfreeman): What should be the containerName when the container has a computed name?
|
||||
containerName: containerName ? (<Identifier>containerName).text : "",
|
||||
containerKind: containerName ? getNodeKind(container) : ScriptElementKind.unknown
|
||||
};
|
||||
}
|
||||
function createNavigateToItem(rawItem: RawNavigateToItem): NavigateToItem {
|
||||
const declaration = rawItem.declaration;
|
||||
const container = <Declaration>getContainerNode(declaration);
|
||||
const containerName = container && getNameOfDeclaration(container);
|
||||
return {
|
||||
name: rawItem.name,
|
||||
kind: getNodeKind(declaration),
|
||||
kindModifiers: getNodeModifiers(declaration),
|
||||
matchKind: PatternMatchKind[rawItem.matchKind],
|
||||
isCaseSensitive: rawItem.isCaseSensitive,
|
||||
fileName: rawItem.fileName,
|
||||
textSpan: createTextSpanFromNode(declaration),
|
||||
// TODO(jfreeman): What should be the containerName when the container has a computed name?
|
||||
containerName: containerName ? (<Identifier>containerName).text : "",
|
||||
containerKind: containerName ? getNodeKind(container) : ScriptElementKind.unknown
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,17 +209,24 @@ namespace ts.NavigationBar {
|
||||
|
||||
case SyntaxKind.BindingElement:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
const decl = <VariableDeclaration>node;
|
||||
const name = decl.name;
|
||||
const { name, initializer } = <VariableDeclaration | BindingElement>node;
|
||||
if (isBindingPattern(name)) {
|
||||
addChildrenRecursively(name);
|
||||
}
|
||||
else if (decl.initializer && isFunctionOrClassExpression(decl.initializer)) {
|
||||
// For `const x = function() {}`, just use the function node, not the const.
|
||||
addChildrenRecursively(decl.initializer);
|
||||
else if (initializer && isFunctionOrClassExpression(initializer)) {
|
||||
if (initializer.name) {
|
||||
// Don't add a node for the VariableDeclaration, just for the initializer.
|
||||
addChildrenRecursively(initializer);
|
||||
}
|
||||
else {
|
||||
// Add a node for the VariableDeclaration, but not for the initializer.
|
||||
startNode(node);
|
||||
forEachChild(initializer, addChildrenRecursively);
|
||||
endNode();
|
||||
}
|
||||
}
|
||||
else {
|
||||
addNodeWithRecursiveChild(decl, decl.initializer);
|
||||
addNodeWithRecursiveChild(node, initializer);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -644,7 +651,14 @@ namespace ts.NavigationBar {
|
||||
}
|
||||
}
|
||||
|
||||
function isFunctionOrClassExpression(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.FunctionExpression || node.kind === SyntaxKind.ArrowFunction || node.kind === SyntaxKind.ClassExpression;
|
||||
function isFunctionOrClassExpression(node: Node): node is ArrowFunction | FunctionExpression | ClassExpression {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ClassExpression:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,17 @@
|
||||
namespace ts.OutliningElementsCollector {
|
||||
const collapseText = "...";
|
||||
const maxDepth = 20;
|
||||
const defaultLabel = "#region";
|
||||
const regionMatch = new RegExp("^\\s*//\\s*#(end)?region(?:\\s+(.*))?$");
|
||||
|
||||
export function collectElements(sourceFile: SourceFile, cancellationToken: CancellationToken): OutliningSpan[] {
|
||||
const elements: OutliningSpan[] = [];
|
||||
let depth = 0;
|
||||
const regions: OutliningSpan[] = [];
|
||||
|
||||
walk(sourceFile);
|
||||
return elements;
|
||||
gatherRegions();
|
||||
return elements.sort((span1, span2) => span1.textSpan.start - span2.textSpan.start);
|
||||
|
||||
/** If useFullStart is true, then the collapsing span includes leading whitespace, including linebreaks. */
|
||||
function addOutliningSpan(hintSpanNode: Node, startElement: Node, endElement: Node, autoCollapse: boolean, useFullStart: boolean) {
|
||||
@@ -89,6 +93,39 @@ namespace ts.OutliningElementsCollector {
|
||||
return isFunctionBlock(node) && node.parent.kind !== SyntaxKind.ArrowFunction;
|
||||
}
|
||||
|
||||
function gatherRegions(): void {
|
||||
const lineStarts = sourceFile.getLineStarts();
|
||||
|
||||
for (let i = 0; i < lineStarts.length; i++) {
|
||||
const currentLineStart = lineStarts[i];
|
||||
const lineEnd = lineStarts[i + 1] - 1 || sourceFile.getEnd();
|
||||
const comment = sourceFile.text.substring(currentLineStart, lineEnd);
|
||||
const result = comment.match(regionMatch);
|
||||
|
||||
if (result && !isInComment(sourceFile, currentLineStart)) {
|
||||
if (!result[1]) {
|
||||
const start = sourceFile.getFullText().indexOf("//", currentLineStart);
|
||||
const textSpan = createTextSpanFromBounds(start, lineEnd);
|
||||
const region: OutliningSpan = {
|
||||
textSpan,
|
||||
hintSpan: textSpan,
|
||||
bannerText: result[2] || defaultLabel,
|
||||
autoCollapse: false
|
||||
};
|
||||
regions.push(region);
|
||||
}
|
||||
else {
|
||||
const region = regions.pop();
|
||||
if (region) {
|
||||
region.textSpan.length = lineEnd - region.textSpan.start;
|
||||
region.hintSpan.length = lineEnd - region.textSpan.start;
|
||||
elements.push(region);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function walk(n: Node): void {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
if (depth > maxDepth) {
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace ts {
|
||||
// Fully checks a candidate, with an dotted container, against the search pattern.
|
||||
// The candidate must match the last part of the search pattern, and the dotted container
|
||||
// must match the preceding segments of the pattern.
|
||||
getMatches(candidateContainers: string[], candidate: string): PatternMatch[];
|
||||
getMatches(candidateContainers: string[], candidate: string): PatternMatch[] | undefined;
|
||||
|
||||
// Whether or not the pattern contained dots or not. Clients can use this to determine
|
||||
// If they should call getMatches, or if getMatchesForLastSegmentOfPattern is sufficient.
|
||||
@@ -139,7 +139,7 @@ namespace ts {
|
||||
return matchSegment(candidate, lastOrUndefined(dotSeparatedSegments));
|
||||
}
|
||||
|
||||
function getMatches(candidateContainers: string[], candidate: string): PatternMatch[] {
|
||||
function getMatches(candidateContainers: string[], candidate: string): PatternMatch[] | undefined {
|
||||
if (skipMatch(candidate)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -43,4 +43,8 @@ namespace ts {
|
||||
return refactor && refactor.getEditsForAction(context, actionName);
|
||||
}
|
||||
}
|
||||
|
||||
export function getRefactorContextLength(context: RefactorContext): number {
|
||||
return context.endPosition === undefined ? 0 : context.endPosition - context.startPosition;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace ts.refactor.extractMethod {
|
||||
|
||||
/** Compute the associated code actions */
|
||||
function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined {
|
||||
const rangeToExtract = getRangeToExtract(context.file, { start: context.startPosition, length: context.endPosition - context.startPosition });
|
||||
const rangeToExtract = getRangeToExtract(context.file, { start: context.startPosition, length: getRefactorContextLength(context) });
|
||||
|
||||
const targetRange: TargetRange = rangeToExtract.targetRange;
|
||||
if (targetRange === undefined) {
|
||||
@@ -66,8 +66,7 @@ namespace ts.refactor.extractMethod {
|
||||
}
|
||||
|
||||
function getEditsForAction(context: RefactorContext, actionName: string): RefactorEditInfo | undefined {
|
||||
const length = context.endPosition === undefined ? 0 : context.endPosition - context.startPosition;
|
||||
const rangeToExtract = getRangeToExtract(context.file, { start: context.startPosition, length });
|
||||
const rangeToExtract = getRangeToExtract(context.file, { start: context.startPosition, length: getRefactorContextLength(context) });
|
||||
const targetRange: TargetRange = rangeToExtract.targetRange;
|
||||
|
||||
const parsedIndexMatch = /^scope_(\d+)$/.exec(actionName);
|
||||
@@ -92,7 +91,7 @@ namespace ts.refactor.extractMethod {
|
||||
export const CannotExtractRangeThatContainsWritesToReferencesLocatedOutsideOfTheTargetRangeInGenerators: DiagnosticMessage = createMessage("Cannot extract range containing writes to references located outside of the target range in generators.");
|
||||
export const TypeWillNotBeVisibleInTheNewScope = createMessage("Type will not visible in the new scope.");
|
||||
export const FunctionWillNotBeVisibleInTheNewScope = createMessage("Function will not visible in the new scope.");
|
||||
export const InsufficientSelection = createMessage("Select more than a single token.");
|
||||
export const InsufficientSelection = createMessage("Select more than a single identifier.");
|
||||
export const CannotExtractExportedEntity = createMessage("Cannot extract exported declaration");
|
||||
export const CannotCombineWritesAndReturns = createMessage("Cannot combine writes and returns");
|
||||
export const CannotExtractReadonlyPropertyInitializerOutsideConstructor = createMessage("Cannot move initialization of read-only class property outside of the constructor");
|
||||
@@ -148,7 +147,7 @@ namespace ts.refactor.extractMethod {
|
||||
*/
|
||||
// exported only for tests
|
||||
export function getRangeToExtract(sourceFile: SourceFile, span: TextSpan): RangeToExtract {
|
||||
const length = span.length || 0;
|
||||
const { length } = span;
|
||||
|
||||
if (length === 0) {
|
||||
return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.StatementOrExpressionExpected)] };
|
||||
@@ -231,7 +230,7 @@ namespace ts.refactor.extractMethod {
|
||||
}
|
||||
|
||||
function checkRootNode(node: Node): Diagnostic[] | undefined {
|
||||
if (isToken(node)) {
|
||||
if (isIdentifier(isExpressionStatement(node) ? node.expression : node)) {
|
||||
return [createDiagnosticForNode(node, Messages.InsufficientSelection)];
|
||||
}
|
||||
return undefined;
|
||||
@@ -286,7 +285,7 @@ namespace ts.refactor.extractMethod {
|
||||
|
||||
let errors: Diagnostic[];
|
||||
let permittedJumps = PermittedJumps.Return;
|
||||
let seenLabels: Array<__String>;
|
||||
let seenLabels: __String[];
|
||||
|
||||
visit(nodeToCheck);
|
||||
|
||||
@@ -664,7 +663,7 @@ namespace ts.refactor.extractMethod {
|
||||
}
|
||||
newFunction = createMethod(
|
||||
/*decorators*/ undefined,
|
||||
modifiers,
|
||||
modifiers.length ? modifiers : undefined,
|
||||
range.facts & RangeFacts.IsGenerator ? createToken(SyntaxKind.AsteriskToken) : undefined,
|
||||
functionName,
|
||||
/*questionToken*/ undefined,
|
||||
@@ -934,12 +933,8 @@ namespace ts.refactor.extractMethod {
|
||||
* Otherwise, return `undefined`.
|
||||
*/
|
||||
function getNodeToInsertBefore(minPos: number, scope: Scope): Node | undefined {
|
||||
const children = getStatementsOrClassElements(scope);
|
||||
for (const child of children) {
|
||||
if (child.pos >= minPos && isFunctionLike(child) && !isConstructorDeclaration(child)) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return find<Statement | ClassElement>(getStatementsOrClassElements(scope), child =>
|
||||
child.pos >= minPos && isFunctionLike(child) && !isConstructorDeclaration(child));
|
||||
}
|
||||
|
||||
function getPropertyAssignmentsForWrites(writes: ReadonlyArray<UsageEntry>): ShorthandPropertyAssignment[] {
|
||||
@@ -1209,7 +1204,7 @@ namespace ts.refactor.extractMethod {
|
||||
if (!declInFile) {
|
||||
return undefined;
|
||||
}
|
||||
if (rangeContainsRange(enclosingTextRange, declInFile)) {
|
||||
if (rangeContainsStartEnd(enclosingTextRange, declInFile.getStart(), declInFile.end)) {
|
||||
// declaration is located in range to be extracted - do nothing
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -672,7 +672,7 @@ namespace ts {
|
||||
if (!hasModifier(node, ModifierFlags.ParameterPropertyModifier)) {
|
||||
break;
|
||||
}
|
||||
// falls through
|
||||
// falls through
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.BindingElement: {
|
||||
const decl = <VariableDeclaration>node;
|
||||
@@ -684,7 +684,7 @@ namespace ts {
|
||||
visit(decl.initializer);
|
||||
}
|
||||
}
|
||||
// falls through
|
||||
// falls through
|
||||
case SyntaxKind.EnumMember:
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.PropertySignature:
|
||||
@@ -737,7 +737,7 @@ namespace ts {
|
||||
|
||||
class SourceMapSourceObject implements SourceMapSource {
|
||||
lineMap: number[];
|
||||
constructor (public fileName: string, public text: string, public skipTrivia?: (pos: number) => number) {}
|
||||
constructor(public fileName: string, public text: string, public skipTrivia?: (pos: number) => number) { }
|
||||
|
||||
public getLineAndCharacterOfPosition(pos: number): LineAndCharacter {
|
||||
return ts.getLineAndCharacterOfPosition(this, pos);
|
||||
@@ -1481,7 +1481,21 @@ namespace ts {
|
||||
|
||||
function getReferences(fileName: string, position: number, options?: FindAllReferences.Options) {
|
||||
synchronizeHostData();
|
||||
return FindAllReferences.findReferencedEntries(program, cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position, options);
|
||||
|
||||
// Exclude default library when renaming as commonly user don't want to change that file.
|
||||
let sourceFiles: SourceFile[] = [];
|
||||
if (options && options.isForRename) {
|
||||
for (const sourceFile of program.getSourceFiles()) {
|
||||
if (!program.isSourceFileDefaultLibrary(sourceFile)) {
|
||||
sourceFiles.push(sourceFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
sourceFiles = program.getSourceFiles().slice();
|
||||
}
|
||||
|
||||
return FindAllReferences.findReferencedEntries(program, cancellationToken, sourceFiles, getValidSourceFile(fileName), position, options);
|
||||
}
|
||||
|
||||
function findReferences(fileName: string, position: number): ReferencedSymbol[] {
|
||||
@@ -1957,7 +1971,7 @@ namespace ts {
|
||||
startPosition,
|
||||
endPosition,
|
||||
program: getProgram(),
|
||||
newLineCharacter: host.getNewLine(),
|
||||
newLineCharacter: formatOptions ? formatOptions.newLineCharacter : host.getNewLine(),
|
||||
rulesProvider: getRuleProvider(formatOptions),
|
||||
cancellationToken
|
||||
};
|
||||
@@ -2070,7 +2084,7 @@ namespace ts {
|
||||
isLiteralComputedPropertyDeclarationName(node);
|
||||
}
|
||||
|
||||
function isObjectLiteralElement(node: Node): node is ObjectLiteralElement {
|
||||
function isObjectLiteralElement(node: Node): node is ObjectLiteralElement {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.JsxAttribute:
|
||||
case SyntaxKind.JsxSpreadAttribute:
|
||||
@@ -2095,7 +2109,7 @@ namespace ts {
|
||||
if (node.parent.kind === SyntaxKind.ComputedPropertyName) {
|
||||
return isObjectLiteralElement(node.parent.parent) ? node.parent.parent : undefined;
|
||||
}
|
||||
// falls through
|
||||
// falls through
|
||||
case SyntaxKind.Identifier:
|
||||
return isObjectLiteralElement(node.parent) &&
|
||||
(node.parent.parent.kind === SyntaxKind.ObjectLiteralExpression || node.parent.parent.kind === SyntaxKind.JsxAttributes) &&
|
||||
|
||||
@@ -568,11 +568,18 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function realizeDiagnostics(diagnostics: ReadonlyArray<Diagnostic>, newLine: string): { message: string; start: number; length: number; category: string; code: number; }[] {
|
||||
interface RealizedDiagnostic {
|
||||
message: string;
|
||||
start: number;
|
||||
length: number;
|
||||
category: string;
|
||||
code: number;
|
||||
}
|
||||
export function realizeDiagnostics(diagnostics: ReadonlyArray<Diagnostic>, newLine: string): RealizedDiagnostic[] {
|
||||
return diagnostics.map(d => realizeDiagnostic(d, newLine));
|
||||
}
|
||||
|
||||
function realizeDiagnostic(diagnostic: Diagnostic, newLine: string): { message: string; start: number; length: number; category: string; code: number; } {
|
||||
function realizeDiagnostic(diagnostic: Diagnostic, newLine: string): RealizedDiagnostic {
|
||||
return {
|
||||
message: flattenDiagnosticMessageText(diagnostic.messageText, newLine),
|
||||
start: diagnostic.start,
|
||||
|
||||
@@ -61,7 +61,8 @@ namespace ts.SymbolDisplay {
|
||||
if (rootSymbolFlags & (SymbolFlags.PropertyOrAccessor | SymbolFlags.Variable)) {
|
||||
return ScriptElementKind.memberVariableElement;
|
||||
}
|
||||
Debug.assert(!!(rootSymbolFlags & SymbolFlags.Method));
|
||||
// May be a Function if this was from `typeof N` with `namespace N { function f();. }`.
|
||||
Debug.assert(!!(rootSymbolFlags & (SymbolFlags.Method | SymbolFlags.Function)));
|
||||
});
|
||||
if (!unionPropertyKind) {
|
||||
// If this was union of all methods,
|
||||
|
||||
@@ -152,7 +152,9 @@ namespace ts.textChanges {
|
||||
return position === Position.Start ? start : fullStart;
|
||||
}
|
||||
// get start position of the line following the line that contains fullstart position
|
||||
let adjustedStartPosition = getStartPositionOfLine(getLineOfLocalPosition(sourceFile, fullStartLine) + 1, sourceFile);
|
||||
// (but only if the fullstart isn't the very beginning of the file)
|
||||
const nextLineStart = fullStart > 0 ? 1 : 0;
|
||||
let adjustedStartPosition = getStartPositionOfLine(getLineOfLocalPosition(sourceFile, fullStartLine) + nextLineStart, sourceFile);
|
||||
// skip whitespaces/newlines
|
||||
adjustedStartPosition = skipWhitespacesAndLineBreaks(sourceFile.text, adjustedStartPosition);
|
||||
return getStartPositionOfLine(getLineOfLocalPosition(sourceFile, adjustedStartPosition), sourceFile);
|
||||
@@ -184,16 +186,12 @@ namespace ts.textChanges {
|
||||
return s;
|
||||
}
|
||||
|
||||
function getNewlineKind(context: { newLineCharacter: string }) {
|
||||
return context.newLineCharacter === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed;
|
||||
}
|
||||
|
||||
export class ChangeTracker {
|
||||
private changes: Change[] = [];
|
||||
private readonly newLineCharacter: string;
|
||||
|
||||
public static fromContext(context: RefactorContext | CodeFixContext) {
|
||||
return new ChangeTracker(getNewlineKind(context), context.rulesProvider);
|
||||
return new ChangeTracker(context.newLineCharacter === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed, context.rulesProvider);
|
||||
}
|
||||
|
||||
constructor(
|
||||
@@ -228,7 +226,7 @@ namespace ts.textChanges {
|
||||
Debug.fail("node is not a list element");
|
||||
return this;
|
||||
}
|
||||
const index = containingList.indexOf(node);
|
||||
const index = indexOfNode(containingList, node);
|
||||
if (index < 0) {
|
||||
return this;
|
||||
}
|
||||
@@ -360,7 +358,7 @@ namespace ts.textChanges {
|
||||
Debug.fail("node is not a list element");
|
||||
return this;
|
||||
}
|
||||
const index = containingList.indexOf(after);
|
||||
const index = indexOfNode(containingList, after);
|
||||
if (index < 0) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -597,7 +597,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
const children = list.getChildren();
|
||||
const listItemIndex = indexOf(children, node);
|
||||
const listItemIndex = indexOfNode(children, node);
|
||||
|
||||
return {
|
||||
listItemIndex,
|
||||
@@ -1080,7 +1080,7 @@ namespace ts {
|
||||
|
||||
/** Returns `true` the first time it encounters a node and `false` afterwards. */
|
||||
export function nodeSeenTracker<T extends Node>(): (node: T) => boolean {
|
||||
const seen: Array<true> = [];
|
||||
const seen: true[] = [];
|
||||
return node => {
|
||||
const id = getNodeId(node);
|
||||
return !seen[id] && (seen[id] = true);
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
//// [APISample_jsdoc.ts]
|
||||
/*
|
||||
* Note: This test is a public API sample. The original sources can be found
|
||||
* at: https://github.com/YousefED/typescript-json-schema
|
||||
* https://github.com/vega/ts-json-schema-generator
|
||||
* Please log a "breaking change" issue for any API breaking change affecting this issue
|
||||
*/
|
||||
|
||||
declare var console: any;
|
||||
|
||||
import * as ts from "typescript";
|
||||
|
||||
// excerpted from https://github.com/YousefED/typescript-json-schema
|
||||
// (converted from a method and modified; for example, `this: any` to compensate, among other changes)
|
||||
function parseCommentsIntoDefinition(this: any,
|
||||
symbol: ts.Symbol,
|
||||
definition: {description?: string, [s: string]: string | undefined},
|
||||
otherAnnotations: { [s: string]: true}): void {
|
||||
if (!symbol) {
|
||||
return;
|
||||
}
|
||||
|
||||
// the comments for a symbol
|
||||
let comments = symbol.getDocumentationComment();
|
||||
|
||||
if (comments.length) {
|
||||
definition.description = comments.map(comment => comment.kind === "lineBreak" ? comment.text : comment.text.trim().replace(/\r\n/g, "\n")).join("");
|
||||
}
|
||||
|
||||
// jsdocs are separate from comments
|
||||
const jsdocs = symbol.getJsDocTags();
|
||||
jsdocs.forEach(doc => {
|
||||
// if we have @TJS-... annotations, we have to parse them
|
||||
const { name, text } = doc;
|
||||
if (this.userValidationKeywords[name]) {
|
||||
definition[name] = this.parseValue(text);
|
||||
} else {
|
||||
// special annotations
|
||||
otherAnnotations[doc.name] = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// excerpted from https://github.com/vega/ts-json-schema-generator
|
||||
export interface Annotations {
|
||||
[name: string]: any;
|
||||
}
|
||||
function getAnnotations(this: any, node: ts.Node): Annotations | undefined {
|
||||
const symbol: ts.Symbol = (node as any).symbol;
|
||||
if (!symbol) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const jsDocTags: ts.JSDocTagInfo[] = symbol.getJsDocTags();
|
||||
if (!jsDocTags || !jsDocTags.length) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const annotations: Annotations = jsDocTags.reduce((result: Annotations, jsDocTag: ts.JSDocTagInfo) => {
|
||||
const value = this.parseJsDocTag(jsDocTag);
|
||||
if (value !== undefined) {
|
||||
result[jsDocTag.name] = value;
|
||||
}
|
||||
|
||||
return result;
|
||||
}, {});
|
||||
return Object.keys(annotations).length ? annotations : undefined;
|
||||
}
|
||||
|
||||
// these examples are artificial and mostly nonsensical
|
||||
function parseSpecificTags(node: ts.Node) {
|
||||
if (node.kind === ts.SyntaxKind.Parameter) {
|
||||
return ts.getJSDocParameterTags(node as ts.ParameterDeclaration);
|
||||
}
|
||||
if (node.kind === ts.SyntaxKind.FunctionDeclaration) {
|
||||
const func = node as ts.FunctionDeclaration;
|
||||
if (ts.hasJSDocParameterTags(func)) {
|
||||
const flat: ts.JSDocTag[] = [];
|
||||
for (const tags of func.parameters.map(ts.getJSDocParameterTags)) {
|
||||
if (tags) flat.push(...tags);
|
||||
}
|
||||
return flat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getReturnTypeFromJSDoc(node: ts.Node) {
|
||||
if (node.kind === ts.SyntaxKind.FunctionDeclaration) {
|
||||
return ts.getJSDocReturnType(node);
|
||||
}
|
||||
let type = ts.getJSDocType(node);
|
||||
if (type && type.kind === ts.SyntaxKind.FunctionType) {
|
||||
return (type as ts.FunctionTypeNode).type;
|
||||
}
|
||||
}
|
||||
|
||||
function getAllTags(node: ts.Node) {
|
||||
ts.getJSDocTags(node);
|
||||
}
|
||||
|
||||
function getSomeOtherTags(node: ts.Node) {
|
||||
const tags: (ts.JSDocTag | undefined)[] = [];
|
||||
tags.push(ts.getJSDocAugmentsTag(node));
|
||||
tags.push(ts.getJSDocClassTag(node));
|
||||
tags.push(ts.getJSDocReturnTag(node));
|
||||
const type = ts.getJSDocTypeTag(node);
|
||||
if (type) {
|
||||
tags.push(type);
|
||||
}
|
||||
tags.push(ts.getJSDocTemplateTag(node));
|
||||
return tags;
|
||||
}
|
||||
|
||||
|
||||
//// [APISample_jsdoc.js]
|
||||
"use strict";
|
||||
/*
|
||||
* Note: This test is a public API sample. The original sources can be found
|
||||
* at: https://github.com/YousefED/typescript-json-schema
|
||||
* https://github.com/vega/ts-json-schema-generator
|
||||
* Please log a "breaking change" issue for any API breaking change affecting this issue
|
||||
*/
|
||||
exports.__esModule = true;
|
||||
var ts = require("typescript");
|
||||
// excerpted from https://github.com/YousefED/typescript-json-schema
|
||||
// (converted from a method and modified; for example, `this: any` to compensate, among other changes)
|
||||
function parseCommentsIntoDefinition(symbol, definition, otherAnnotations) {
|
||||
var _this = this;
|
||||
if (!symbol) {
|
||||
return;
|
||||
}
|
||||
// the comments for a symbol
|
||||
var comments = symbol.getDocumentationComment();
|
||||
if (comments.length) {
|
||||
definition.description = comments.map(function (comment) { return comment.kind === "lineBreak" ? comment.text : comment.text.trim().replace(/\r\n/g, "\n"); }).join("");
|
||||
}
|
||||
// jsdocs are separate from comments
|
||||
var jsdocs = symbol.getJsDocTags();
|
||||
jsdocs.forEach(function (doc) {
|
||||
// if we have @TJS-... annotations, we have to parse them
|
||||
var name = doc.name, text = doc.text;
|
||||
if (_this.userValidationKeywords[name]) {
|
||||
definition[name] = _this.parseValue(text);
|
||||
}
|
||||
else {
|
||||
// special annotations
|
||||
otherAnnotations[doc.name] = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
function getAnnotations(node) {
|
||||
var _this = this;
|
||||
var symbol = node.symbol;
|
||||
if (!symbol) {
|
||||
return undefined;
|
||||
}
|
||||
var jsDocTags = symbol.getJsDocTags();
|
||||
if (!jsDocTags || !jsDocTags.length) {
|
||||
return undefined;
|
||||
}
|
||||
var annotations = jsDocTags.reduce(function (result, jsDocTag) {
|
||||
var value = _this.parseJsDocTag(jsDocTag);
|
||||
if (value !== undefined) {
|
||||
result[jsDocTag.name] = value;
|
||||
}
|
||||
return result;
|
||||
}, {});
|
||||
return Object.keys(annotations).length ? annotations : undefined;
|
||||
}
|
||||
// these examples are artificial and mostly nonsensical
|
||||
function parseSpecificTags(node) {
|
||||
if (node.kind === ts.SyntaxKind.Parameter) {
|
||||
return ts.getJSDocParameterTags(node);
|
||||
}
|
||||
if (node.kind === ts.SyntaxKind.FunctionDeclaration) {
|
||||
var func = node;
|
||||
if (ts.hasJSDocParameterTags(func)) {
|
||||
var flat = [];
|
||||
for (var _i = 0, _a = func.parameters.map(ts.getJSDocParameterTags); _i < _a.length; _i++) {
|
||||
var tags = _a[_i];
|
||||
if (tags)
|
||||
flat.push.apply(flat, tags);
|
||||
}
|
||||
return flat;
|
||||
}
|
||||
}
|
||||
}
|
||||
function getReturnTypeFromJSDoc(node) {
|
||||
if (node.kind === ts.SyntaxKind.FunctionDeclaration) {
|
||||
return ts.getJSDocReturnType(node);
|
||||
}
|
||||
var type = ts.getJSDocType(node);
|
||||
if (type && type.kind === ts.SyntaxKind.FunctionType) {
|
||||
return type.type;
|
||||
}
|
||||
}
|
||||
function getAllTags(node) {
|
||||
ts.getJSDocTags(node);
|
||||
}
|
||||
function getSomeOtherTags(node) {
|
||||
var tags = [];
|
||||
tags.push(ts.getJSDocAugmentsTag(node));
|
||||
tags.push(ts.getJSDocClassTag(node));
|
||||
tags.push(ts.getJSDocReturnTag(node));
|
||||
var type = ts.getJSDocTypeTag(node);
|
||||
if (type) {
|
||||
tags.push(type);
|
||||
}
|
||||
tags.push(ts.getJSDocTemplateTag(node));
|
||||
return tags;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
=== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ArrowFunctions/ArrowFunction1.ts ===
|
||||
var v = (a: ) => {
|
||||
>v : Symbol(v, Decl(ArrowFunction1.ts, 0, 3))
|
||||
>a : Symbol(a, Decl(ArrowFunction1.ts, 0, 9))
|
||||
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
=== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ArrowFunctions/ArrowFunction1.ts ===
|
||||
var v = (a: ) => {
|
||||
>v : (a: any) => void
|
||||
>(a: ) => { } : (a: any) => void
|
||||
>a : any
|
||||
> : No type information available!
|
||||
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
=== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ArrowFunctions/ArrowFunction3.ts ===
|
||||
var v = (a): => {
|
||||
>v : Symbol(v, Decl(ArrowFunction3.ts, 0, 3))
|
||||
>a : Symbol(a, Decl(ArrowFunction3.ts, 0, 9))
|
||||
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
=== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ArrowFunctions/ArrowFunction3.ts ===
|
||||
var v = (a): => {
|
||||
>v : (a: any) => any
|
||||
>(a): => { } : (a: any) => any
|
||||
>a : any
|
||||
> : No type information available!
|
||||
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
=== tests/cases/compiler/ArrowFunctionExpression1.ts ===
|
||||
var v = (public x: string) => { };
|
||||
>v : Symbol(v, Decl(ArrowFunctionExpression1.ts, 0, 3))
|
||||
>x : Symbol(x, Decl(ArrowFunctionExpression1.ts, 0, 9))
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
=== tests/cases/compiler/ArrowFunctionExpression1.ts ===
|
||||
var v = (public x: string) => { };
|
||||
>v : (public x: string) => void
|
||||
>(public x: string) => { } : (public x: string) => void
|
||||
>x : string
|
||||
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts ===
|
||||
// all expected to be errors
|
||||
|
||||
class clodule1<T>{
|
||||
>clodule1 : Symbol(clodule1, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 0, 0), Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 6, 1))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 2, 15))
|
||||
|
||||
id: string;
|
||||
>id : Symbol(clodule1.id, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 2, 18))
|
||||
|
||||
value: T;
|
||||
>value : Symbol(clodule1.value, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 4, 15))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 2, 15))
|
||||
}
|
||||
|
||||
module clodule1 {
|
||||
>clodule1 : Symbol(clodule1, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 0, 0), Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 6, 1))
|
||||
|
||||
function f(x: T) { }
|
||||
>f : Symbol(f, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 8, 17))
|
||||
>x : Symbol(x, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 9, 15))
|
||||
}
|
||||
|
||||
class clodule2<T>{
|
||||
>clodule2 : Symbol(clodule2, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 10, 1), Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 16, 1))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 12, 15))
|
||||
|
||||
id: string;
|
||||
>id : Symbol(clodule2.id, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 12, 18))
|
||||
|
||||
value: T;
|
||||
>value : Symbol(clodule2.value, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 14, 15))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 12, 15))
|
||||
}
|
||||
|
||||
module clodule2 {
|
||||
>clodule2 : Symbol(clodule2, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 10, 1), Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 16, 1))
|
||||
|
||||
var x: T;
|
||||
>x : Symbol(x, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 19, 7))
|
||||
|
||||
class D<U extends T>{
|
||||
>D : Symbol(D, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 19, 13))
|
||||
>U : Symbol(U, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 21, 12))
|
||||
|
||||
id: string;
|
||||
>id : Symbol(D.id, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 21, 25))
|
||||
|
||||
value: U;
|
||||
>value : Symbol(D.value, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 22, 19))
|
||||
>U : Symbol(U, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 21, 12))
|
||||
}
|
||||
}
|
||||
|
||||
class clodule3<T>{
|
||||
>clodule3 : Symbol(clodule3, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 25, 1), Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 31, 1))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 27, 15))
|
||||
|
||||
id: string;
|
||||
>id : Symbol(clodule3.id, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 27, 18))
|
||||
|
||||
value: T;
|
||||
>value : Symbol(clodule3.value, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 29, 15))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 27, 15))
|
||||
}
|
||||
|
||||
module clodule3 {
|
||||
>clodule3 : Symbol(clodule3, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 25, 1), Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 31, 1))
|
||||
|
||||
export var y = { id: T };
|
||||
>y : Symbol(y, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 34, 14))
|
||||
>id : Symbol(id, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 34, 20))
|
||||
}
|
||||
|
||||
class clodule4<T>{
|
||||
>clodule4 : Symbol(clodule4, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 35, 1), Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 41, 1))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 37, 15))
|
||||
|
||||
id: string;
|
||||
>id : Symbol(clodule4.id, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 37, 18))
|
||||
|
||||
value: T;
|
||||
>value : Symbol(clodule4.value, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 39, 15))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 37, 15))
|
||||
}
|
||||
|
||||
module clodule4 {
|
||||
>clodule4 : Symbol(clodule4, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 35, 1), Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 41, 1))
|
||||
|
||||
class D {
|
||||
>D : Symbol(D, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 43, 17))
|
||||
|
||||
name: T;
|
||||
>name : Symbol(D.name, Decl(ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts, 44, 13))
|
||||
}
|
||||
}
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.ts ===
|
||||
// all expected to be errors
|
||||
|
||||
class clodule1<T>{
|
||||
>clodule1 : clodule1<T>
|
||||
>T : T
|
||||
|
||||
id: string;
|
||||
>id : string
|
||||
|
||||
value: T;
|
||||
>value : T
|
||||
>T : T
|
||||
}
|
||||
|
||||
module clodule1 {
|
||||
>clodule1 : typeof clodule1
|
||||
|
||||
function f(x: T) { }
|
||||
>f : (x: any) => void
|
||||
>x : any
|
||||
>T : No type information available!
|
||||
}
|
||||
|
||||
class clodule2<T>{
|
||||
>clodule2 : clodule2<T>
|
||||
>T : T
|
||||
|
||||
id: string;
|
||||
>id : string
|
||||
|
||||
value: T;
|
||||
>value : T
|
||||
>T : T
|
||||
}
|
||||
|
||||
module clodule2 {
|
||||
>clodule2 : typeof clodule2
|
||||
|
||||
var x: T;
|
||||
>x : any
|
||||
>T : No type information available!
|
||||
|
||||
class D<U extends T>{
|
||||
>D : D<U>
|
||||
>U : U
|
||||
>T : No type information available!
|
||||
|
||||
id: string;
|
||||
>id : string
|
||||
|
||||
value: U;
|
||||
>value : U
|
||||
>U : U
|
||||
}
|
||||
}
|
||||
|
||||
class clodule3<T>{
|
||||
>clodule3 : clodule3<T>
|
||||
>T : T
|
||||
|
||||
id: string;
|
||||
>id : string
|
||||
|
||||
value: T;
|
||||
>value : T
|
||||
>T : T
|
||||
}
|
||||
|
||||
module clodule3 {
|
||||
>clodule3 : typeof clodule3
|
||||
|
||||
export var y = { id: T };
|
||||
>y : { id: any; }
|
||||
>{ id: T } : { id: any; }
|
||||
>id : any
|
||||
>T : any
|
||||
}
|
||||
|
||||
class clodule4<T>{
|
||||
>clodule4 : clodule4<T>
|
||||
>T : T
|
||||
|
||||
id: string;
|
||||
>id : string
|
||||
|
||||
value: T;
|
||||
>value : T
|
||||
>T : T
|
||||
}
|
||||
|
||||
module clodule4 {
|
||||
>clodule4 : typeof clodule4
|
||||
|
||||
class D {
|
||||
>D : D
|
||||
|
||||
name: T;
|
||||
>name : any
|
||||
>T : No type information available!
|
||||
}
|
||||
}
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts ===
|
||||
class clodule<T> {
|
||||
>clodule : Symbol(clodule, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts, 0, 0), Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts, 5, 1))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts, 0, 14))
|
||||
|
||||
id: string;
|
||||
>id : Symbol(clodule.id, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts, 0, 18))
|
||||
|
||||
value: T;
|
||||
>value : Symbol(clodule.value, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts, 1, 15))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts, 0, 14))
|
||||
|
||||
static fn<U>(id: U) { }
|
||||
>fn : Symbol(clodule.fn, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts, 2, 13))
|
||||
>U : Symbol(U, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts, 4, 14))
|
||||
>id : Symbol(id, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts, 4, 17))
|
||||
>U : Symbol(U, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts, 4, 14))
|
||||
}
|
||||
|
||||
module clodule {
|
||||
>clodule : Symbol(clodule, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts, 0, 0), Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts, 5, 1))
|
||||
|
||||
// error: duplicate identifier expected
|
||||
export function fn<T>(x: T, y: T): T {
|
||||
>fn : Symbol(clodule.fn, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts, 7, 16))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts, 9, 23))
|
||||
>x : Symbol(x, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts, 9, 26))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts, 9, 23))
|
||||
>y : Symbol(y, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts, 9, 31))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts, 9, 23))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts, 9, 23))
|
||||
|
||||
return x;
|
||||
>x : Symbol(x, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts, 9, 26))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts ===
|
||||
class clodule<T> {
|
||||
>clodule : clodule<T>
|
||||
>T : T
|
||||
|
||||
id: string;
|
||||
>id : string
|
||||
|
||||
value: T;
|
||||
>value : T
|
||||
>T : T
|
||||
|
||||
static fn<U>(id: U) { }
|
||||
>fn : <U>(id: U) => void
|
||||
>U : U
|
||||
>id : U
|
||||
>U : U
|
||||
}
|
||||
|
||||
module clodule {
|
||||
>clodule : typeof clodule
|
||||
|
||||
// error: duplicate identifier expected
|
||||
export function fn<T>(x: T, y: T): T {
|
||||
>fn : <T>(x: T, y: T) => T
|
||||
>T : T
|
||||
>x : T
|
||||
>T : T
|
||||
>y : T
|
||||
>T : T
|
||||
>T : T
|
||||
|
||||
return x;
|
||||
>x : T
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts ===
|
||||
class clodule<T> {
|
||||
>clodule : Symbol(clodule, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts, 0, 0), Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts, 5, 1))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts, 0, 14))
|
||||
|
||||
id: string;
|
||||
>id : Symbol(clodule.id, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts, 0, 18))
|
||||
|
||||
value: T;
|
||||
>value : Symbol(clodule.value, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts, 1, 15))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts, 0, 14))
|
||||
|
||||
static fn(id: string) { }
|
||||
>fn : Symbol(clodule.fn, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts, 2, 13))
|
||||
>id : Symbol(id, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts, 4, 14))
|
||||
}
|
||||
|
||||
module clodule {
|
||||
>clodule : Symbol(clodule, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts, 0, 0), Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts, 5, 1))
|
||||
|
||||
// error: duplicate identifier expected
|
||||
export function fn<T>(x: T, y: T): T {
|
||||
>fn : Symbol(clodule.fn, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts, 7, 16))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts, 9, 23))
|
||||
>x : Symbol(x, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts, 9, 26))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts, 9, 23))
|
||||
>y : Symbol(y, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts, 9, 31))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts, 9, 23))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts, 9, 23))
|
||||
|
||||
return x;
|
||||
>x : Symbol(x, Decl(ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts, 9, 26))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts ===
|
||||
class clodule<T> {
|
||||
>clodule : clodule<T>
|
||||
>T : T
|
||||
|
||||
id: string;
|
||||
>id : string
|
||||
|
||||
value: T;
|
||||
>value : T
|
||||
>T : T
|
||||
|
||||
static fn(id: string) { }
|
||||
>fn : (id: string) => void
|
||||
>id : string
|
||||
}
|
||||
|
||||
module clodule {
|
||||
>clodule : typeof clodule
|
||||
|
||||
// error: duplicate identifier expected
|
||||
export function fn<T>(x: T, y: T): T {
|
||||
>fn : <T>(x: T, y: T) => T
|
||||
>T : T
|
||||
>x : T
|
||||
>T : T
|
||||
>y : T
|
||||
>T : T
|
||||
>T : T
|
||||
|
||||
return x;
|
||||
>x : T
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts ===
|
||||
class clodule<T> {
|
||||
>clodule : Symbol(clodule, Decl(ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts, 0, 0), Decl(ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts, 5, 1))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts, 0, 14))
|
||||
|
||||
id: string;
|
||||
>id : Symbol(clodule.id, Decl(ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts, 0, 18))
|
||||
|
||||
value: T;
|
||||
>value : Symbol(clodule.value, Decl(ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts, 1, 15))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts, 0, 14))
|
||||
|
||||
private static sfn(id: string) { return 42; }
|
||||
>sfn : Symbol(clodule.sfn, Decl(ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts, 2, 13))
|
||||
>id : Symbol(id, Decl(ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts, 4, 23))
|
||||
}
|
||||
|
||||
module clodule {
|
||||
>clodule : Symbol(clodule, Decl(ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts, 0, 0), Decl(ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts, 5, 1))
|
||||
|
||||
// error: duplicate identifier expected
|
||||
export function fn<T>(x: T, y: T): number {
|
||||
>fn : Symbol(fn, Decl(ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts, 7, 16))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts, 9, 23))
|
||||
>x : Symbol(x, Decl(ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts, 9, 26))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts, 9, 23))
|
||||
>y : Symbol(y, Decl(ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts, 9, 31))
|
||||
>T : Symbol(T, Decl(ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts, 9, 23))
|
||||
|
||||
return clodule.sfn('a');
|
||||
>clodule.sfn : Symbol(clodule.sfn, Decl(ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts, 2, 13))
|
||||
>clodule : Symbol(clodule, Decl(ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts, 0, 0), Decl(ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts, 5, 1))
|
||||
>sfn : Symbol(clodule.sfn, Decl(ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts, 2, 13))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts ===
|
||||
class clodule<T> {
|
||||
>clodule : clodule<T>
|
||||
>T : T
|
||||
|
||||
id: string;
|
||||
>id : string
|
||||
|
||||
value: T;
|
||||
>value : T
|
||||
>T : T
|
||||
|
||||
private static sfn(id: string) { return 42; }
|
||||
>sfn : (id: string) => number
|
||||
>id : string
|
||||
>42 : 42
|
||||
}
|
||||
|
||||
module clodule {
|
||||
>clodule : typeof clodule
|
||||
|
||||
// error: duplicate identifier expected
|
||||
export function fn<T>(x: T, y: T): number {
|
||||
>fn : <T>(x: T, y: T) => number
|
||||
>T : T
|
||||
>x : T
|
||||
>T : T
|
||||
>y : T
|
||||
>T : T
|
||||
|
||||
return clodule.sfn('a');
|
||||
>clodule.sfn('a') : number
|
||||
>clodule.sfn : (id: string) => number
|
||||
>clodule : typeof clodule
|
||||
>sfn : (id: string) => number
|
||||
>'a' : "a"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts ===
|
||||
class Point {
|
||||
>Point : Symbol(Point, Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 0, 0), Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 4, 1))
|
||||
|
||||
constructor(public x: number, public y: number) { }
|
||||
>x : Symbol(Point.x, Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 1, 16))
|
||||
>y : Symbol(Point.y, Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 1, 33))
|
||||
|
||||
static Origin(): Point { return { x: 0, y: 0 }; } // unexpected error here bug 840246
|
||||
>Origin : Symbol(Point.Origin, Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 1, 55))
|
||||
>Point : Symbol(Point, Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 0, 0), Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 4, 1))
|
||||
>x : Symbol(x, Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 3, 37))
|
||||
>y : Symbol(y, Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 3, 43))
|
||||
}
|
||||
|
||||
module Point {
|
||||
>Point : Symbol(Point, Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 0, 0), Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 4, 1))
|
||||
|
||||
export function Origin() { return null; } //expected duplicate identifier error
|
||||
>Origin : Symbol(Point.Origin, Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 6, 14))
|
||||
}
|
||||
|
||||
|
||||
module A {
|
||||
>A : Symbol(A, Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 8, 1))
|
||||
|
||||
export class Point {
|
||||
>Point : Symbol(Point, Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 11, 10), Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 16, 5))
|
||||
|
||||
constructor(public x: number, public y: number) { }
|
||||
>x : Symbol(Point.x, Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 13, 20))
|
||||
>y : Symbol(Point.y, Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 13, 37))
|
||||
|
||||
static Origin(): Point { return { x: 0, y: 0 }; } // unexpected error here bug 840246
|
||||
>Origin : Symbol(Point.Origin, Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 13, 59))
|
||||
>Point : Symbol(Point, Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 11, 10), Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 16, 5))
|
||||
>x : Symbol(x, Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 15, 41))
|
||||
>y : Symbol(y, Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 15, 47))
|
||||
}
|
||||
|
||||
export module Point {
|
||||
>Point : Symbol(Point, Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 11, 10), Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 16, 5))
|
||||
|
||||
export function Origin() { return ""; }//expected duplicate identifier error
|
||||
>Origin : Symbol(Point.Origin, Decl(ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts, 18, 25))
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.ts ===
|
||||
class Point {
|
||||
>Point : Point
|
||||
|
||||
constructor(public x: number, public y: number) { }
|
||||
>x : number
|
||||
>y : number
|
||||
|
||||
static Origin(): Point { return { x: 0, y: 0 }; } // unexpected error here bug 840246
|
||||
>Origin : () => Point
|
||||
>Point : Point
|
||||
>{ x: 0, y: 0 } : { x: number; y: number; }
|
||||
>x : number
|
||||
>0 : 0
|
||||
>y : number
|
||||
>0 : 0
|
||||
}
|
||||
|
||||
module Point {
|
||||
>Point : typeof Point
|
||||
|
||||
export function Origin() { return null; } //expected duplicate identifier error
|
||||
>Origin : () => any
|
||||
>null : null
|
||||
}
|
||||
|
||||
|
||||
module A {
|
||||
>A : typeof A
|
||||
|
||||
export class Point {
|
||||
>Point : Point
|
||||
|
||||
constructor(public x: number, public y: number) { }
|
||||
>x : number
|
||||
>y : number
|
||||
|
||||
static Origin(): Point { return { x: 0, y: 0 }; } // unexpected error here bug 840246
|
||||
>Origin : () => Point
|
||||
>Point : Point
|
||||
>{ x: 0, y: 0 } : { x: number; y: number; }
|
||||
>x : number
|
||||
>0 : 0
|
||||
>y : number
|
||||
>0 : 0
|
||||
}
|
||||
|
||||
export module Point {
|
||||
>Point : typeof Point
|
||||
|
||||
export function Origin() { return ""; }//expected duplicate identifier error
|
||||
>Origin : () => string
|
||||
>"" : ""
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts ===
|
||||
class Point {
|
||||
>Point : Symbol(Point, Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 0, 0), Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 4, 1))
|
||||
|
||||
constructor(public x: number, public y: number) { }
|
||||
>x : Symbol(Point.x, Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 1, 16))
|
||||
>y : Symbol(Point.y, Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 1, 33))
|
||||
|
||||
static Origin: Point = { x: 0, y: 0 };
|
||||
>Origin : Symbol(Point.Origin, Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 1, 55))
|
||||
>Point : Symbol(Point, Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 0, 0), Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 4, 1))
|
||||
>x : Symbol(x, Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 3, 28))
|
||||
>y : Symbol(y, Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 3, 34))
|
||||
}
|
||||
|
||||
module Point {
|
||||
>Point : Symbol(Point, Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 0, 0), Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 4, 1))
|
||||
|
||||
export var Origin = ""; //expected duplicate identifier error
|
||||
>Origin : Symbol(Point.Origin, Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 7, 14))
|
||||
}
|
||||
|
||||
|
||||
module A {
|
||||
>A : Symbol(A, Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 8, 1))
|
||||
|
||||
export class Point {
|
||||
>Point : Symbol(Point, Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 11, 10), Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 16, 5))
|
||||
|
||||
constructor(public x: number, public y: number) { }
|
||||
>x : Symbol(Point.x, Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 13, 20))
|
||||
>y : Symbol(Point.y, Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 13, 37))
|
||||
|
||||
static Origin: Point = { x: 0, y: 0 };
|
||||
>Origin : Symbol(Point.Origin, Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 13, 59))
|
||||
>Point : Symbol(Point, Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 11, 10), Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 16, 5))
|
||||
>x : Symbol(x, Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 15, 32))
|
||||
>y : Symbol(y, Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 15, 38))
|
||||
}
|
||||
|
||||
export module Point {
|
||||
>Point : Symbol(Point, Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 11, 10), Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 16, 5))
|
||||
|
||||
export var Origin = ""; //expected duplicate identifier error
|
||||
>Origin : Symbol(Point.Origin, Decl(ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts, 19, 18))
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.ts ===
|
||||
class Point {
|
||||
>Point : Point
|
||||
|
||||
constructor(public x: number, public y: number) { }
|
||||
>x : number
|
||||
>y : number
|
||||
|
||||
static Origin: Point = { x: 0, y: 0 };
|
||||
>Origin : Point
|
||||
>Point : Point
|
||||
>{ x: 0, y: 0 } : { x: number; y: number; }
|
||||
>x : number
|
||||
>0 : 0
|
||||
>y : number
|
||||
>0 : 0
|
||||
}
|
||||
|
||||
module Point {
|
||||
>Point : typeof Point
|
||||
|
||||
export var Origin = ""; //expected duplicate identifier error
|
||||
>Origin : string
|
||||
>"" : ""
|
||||
}
|
||||
|
||||
|
||||
module A {
|
||||
>A : typeof A
|
||||
|
||||
export class Point {
|
||||
>Point : Point
|
||||
|
||||
constructor(public x: number, public y: number) { }
|
||||
>x : number
|
||||
>y : number
|
||||
|
||||
static Origin: Point = { x: 0, y: 0 };
|
||||
>Origin : Point
|
||||
>Point : Point
|
||||
>{ x: 0, y: 0 } : { x: number; y: number; }
|
||||
>x : number
|
||||
>0 : 0
|
||||
>y : number
|
||||
>0 : 0
|
||||
}
|
||||
|
||||
export module Point {
|
||||
>Point : typeof Point
|
||||
|
||||
export var Origin = ""; //expected duplicate identifier error
|
||||
>Origin : string
|
||||
>"" : ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/class.ts ===
|
||||
module X.Y {
|
||||
>X : Symbol(X, Decl(class.ts, 0, 0), Decl(module.ts, 0, 0))
|
||||
>Y : Symbol(Y, Decl(class.ts, 0, 9), Decl(module.ts, 0, 9))
|
||||
|
||||
export class Point {
|
||||
>Point : Symbol(Point, Decl(class.ts, 0, 12), Decl(module.ts, 0, 12))
|
||||
|
||||
constructor(x: number, y: number) {
|
||||
>x : Symbol(x, Decl(class.ts, 2, 20))
|
||||
>y : Symbol(y, Decl(class.ts, 2, 30))
|
||||
|
||||
this.x = x;
|
||||
>this.x : Symbol(Point.x, Decl(class.ts, 5, 9))
|
||||
>this : Symbol(Point, Decl(class.ts, 0, 12), Decl(module.ts, 0, 12))
|
||||
>x : Symbol(Point.x, Decl(class.ts, 5, 9))
|
||||
>x : Symbol(x, Decl(class.ts, 2, 20))
|
||||
|
||||
this.y = y;
|
||||
>this.y : Symbol(Point.y, Decl(class.ts, 6, 18))
|
||||
>this : Symbol(Point, Decl(class.ts, 0, 12), Decl(module.ts, 0, 12))
|
||||
>y : Symbol(Point.y, Decl(class.ts, 6, 18))
|
||||
>y : Symbol(y, Decl(class.ts, 2, 30))
|
||||
}
|
||||
x: number;
|
||||
>x : Symbol(Point.x, Decl(class.ts, 5, 9))
|
||||
|
||||
y: number;
|
||||
>y : Symbol(Point.y, Decl(class.ts, 6, 18))
|
||||
}
|
||||
}
|
||||
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/module.ts ===
|
||||
module X.Y {
|
||||
>X : Symbol(X, Decl(class.ts, 0, 0), Decl(module.ts, 0, 0))
|
||||
>Y : Symbol(Y, Decl(class.ts, 0, 9), Decl(module.ts, 0, 9))
|
||||
|
||||
export module Point {
|
||||
>Point : Symbol(Point, Decl(class.ts, 0, 12), Decl(module.ts, 0, 12))
|
||||
|
||||
export var Origin = new Point(0, 0);
|
||||
>Origin : Symbol(Origin, Decl(module.ts, 2, 18))
|
||||
>Point : Symbol(Point, Decl(class.ts, 0, 12), Decl(module.ts, 0, 12))
|
||||
}
|
||||
}
|
||||
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/test.ts ===
|
||||
//var cl: { x: number; y: number; }
|
||||
var cl = new X.Y.Point(1,1);
|
||||
>cl : Symbol(cl, Decl(test.ts, 1, 3), Decl(test.ts, 2, 3))
|
||||
>X.Y.Point : Symbol(X.Y.Point, Decl(class.ts, 0, 12), Decl(module.ts, 0, 12))
|
||||
>X.Y : Symbol(X.Y, Decl(class.ts, 0, 9), Decl(module.ts, 0, 9))
|
||||
>X : Symbol(X, Decl(class.ts, 0, 0), Decl(module.ts, 0, 0))
|
||||
>Y : Symbol(X.Y, Decl(class.ts, 0, 9), Decl(module.ts, 0, 9))
|
||||
>Point : Symbol(X.Y.Point, Decl(class.ts, 0, 12), Decl(module.ts, 0, 12))
|
||||
|
||||
var cl = X.Y.Point.Origin; // error not expected here same as bug 83996 ?
|
||||
>cl : Symbol(cl, Decl(test.ts, 1, 3), Decl(test.ts, 2, 3))
|
||||
>X.Y.Point.Origin : Symbol(X.Y.Point.Origin, Decl(module.ts, 2, 18))
|
||||
>X.Y.Point : Symbol(X.Y.Point, Decl(class.ts, 0, 12), Decl(module.ts, 0, 12))
|
||||
>X.Y : Symbol(X.Y, Decl(class.ts, 0, 9), Decl(module.ts, 0, 9))
|
||||
>X : Symbol(X, Decl(class.ts, 0, 0), Decl(module.ts, 0, 0))
|
||||
>Y : Symbol(X.Y, Decl(class.ts, 0, 9), Decl(module.ts, 0, 9))
|
||||
>Point : Symbol(X.Y.Point, Decl(class.ts, 0, 12), Decl(module.ts, 0, 12))
|
||||
>Origin : Symbol(X.Y.Point.Origin, Decl(module.ts, 2, 18))
|
||||
|
||||
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/simple.ts ===
|
||||
class A {
|
||||
>A : Symbol(A, Decl(simple.ts, 0, 0), Decl(simple.ts, 2, 1))
|
||||
|
||||
id: string;
|
||||
>id : Symbol(A.id, Decl(simple.ts, 0, 9))
|
||||
}
|
||||
|
||||
module A {
|
||||
>A : Symbol(A, Decl(simple.ts, 0, 0), Decl(simple.ts, 2, 1))
|
||||
|
||||
export var Instance = new A();
|
||||
>Instance : Symbol(Instance, Decl(simple.ts, 5, 14))
|
||||
>A : Symbol(A, Decl(simple.ts, 0, 0), Decl(simple.ts, 2, 1))
|
||||
}
|
||||
|
||||
// ensure merging works as expected
|
||||
var a = A.Instance;
|
||||
>a : Symbol(a, Decl(simple.ts, 9, 3), Decl(simple.ts, 10, 3), Decl(simple.ts, 11, 3))
|
||||
>A.Instance : Symbol(A.Instance, Decl(simple.ts, 5, 14))
|
||||
>A : Symbol(A, Decl(simple.ts, 0, 0), Decl(simple.ts, 2, 1))
|
||||
>Instance : Symbol(A.Instance, Decl(simple.ts, 5, 14))
|
||||
|
||||
var a = new A();
|
||||
>a : Symbol(a, Decl(simple.ts, 9, 3), Decl(simple.ts, 10, 3), Decl(simple.ts, 11, 3))
|
||||
>A : Symbol(A, Decl(simple.ts, 0, 0), Decl(simple.ts, 2, 1))
|
||||
|
||||
var a: { id: string };
|
||||
>a : Symbol(a, Decl(simple.ts, 9, 3), Decl(simple.ts, 10, 3), Decl(simple.ts, 11, 3))
|
||||
>id : Symbol(id, Decl(simple.ts, 11, 8))
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/class.ts ===
|
||||
module X.Y {
|
||||
>X : typeof X
|
||||
>Y : typeof Y
|
||||
|
||||
export class Point {
|
||||
>Point : Point
|
||||
|
||||
constructor(x: number, y: number) {
|
||||
>x : number
|
||||
>y : number
|
||||
|
||||
this.x = x;
|
||||
>this.x = x : number
|
||||
>this.x : number
|
||||
>this : this
|
||||
>x : number
|
||||
>x : number
|
||||
|
||||
this.y = y;
|
||||
>this.y = y : number
|
||||
>this.y : number
|
||||
>this : this
|
||||
>y : number
|
||||
>y : number
|
||||
}
|
||||
x: number;
|
||||
>x : number
|
||||
|
||||
y: number;
|
||||
>y : number
|
||||
}
|
||||
}
|
||||
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/module.ts ===
|
||||
module X.Y {
|
||||
>X : typeof X
|
||||
>Y : typeof Y
|
||||
|
||||
export module Point {
|
||||
>Point : typeof Point
|
||||
|
||||
export var Origin = new Point(0, 0);
|
||||
>Origin : Point
|
||||
>new Point(0, 0) : Point
|
||||
>Point : typeof Point
|
||||
>0 : 0
|
||||
>0 : 0
|
||||
}
|
||||
}
|
||||
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/test.ts ===
|
||||
//var cl: { x: number; y: number; }
|
||||
var cl = new X.Y.Point(1,1);
|
||||
>cl : X.Y.Point
|
||||
>new X.Y.Point(1,1) : X.Y.Point
|
||||
>X.Y.Point : typeof X.Y.Point
|
||||
>X.Y : typeof X.Y
|
||||
>X : typeof X
|
||||
>Y : typeof X.Y
|
||||
>Point : typeof X.Y.Point
|
||||
>1 : 1
|
||||
>1 : 1
|
||||
|
||||
var cl = X.Y.Point.Origin; // error not expected here same as bug 83996 ?
|
||||
>cl : X.Y.Point
|
||||
>X.Y.Point.Origin : X.Y.Point
|
||||
>X.Y.Point : typeof X.Y.Point
|
||||
>X.Y : typeof X.Y
|
||||
>X : typeof X
|
||||
>Y : typeof X.Y
|
||||
>Point : typeof X.Y.Point
|
||||
>Origin : X.Y.Point
|
||||
|
||||
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/simple.ts ===
|
||||
class A {
|
||||
>A : A
|
||||
|
||||
id: string;
|
||||
>id : string
|
||||
}
|
||||
|
||||
module A {
|
||||
>A : typeof A
|
||||
|
||||
export var Instance = new A();
|
||||
>Instance : A
|
||||
>new A() : A
|
||||
>A : typeof A
|
||||
}
|
||||
|
||||
// ensure merging works as expected
|
||||
var a = A.Instance;
|
||||
>a : A
|
||||
>A.Instance : A
|
||||
>A : typeof A
|
||||
>Instance : A
|
||||
|
||||
var a = new A();
|
||||
>a : A
|
||||
>new A() : A
|
||||
>A : typeof A
|
||||
|
||||
var a: { id: string };
|
||||
>a : A
|
||||
>id : string
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/class.ts ===
|
||||
module X.Y {
|
||||
>X : Symbol(X, Decl(class.ts, 0, 0), Decl(module.ts, 0, 0))
|
||||
>Y : Symbol(Y, Decl(class.ts, 0, 9), Decl(module.ts, 0, 9))
|
||||
|
||||
export class Point {
|
||||
>Point : Symbol(Point, Decl(class.ts, 0, 12), Decl(module.ts, 0, 12))
|
||||
|
||||
constructor(x: number, y: number) {
|
||||
>x : Symbol(x, Decl(class.ts, 2, 20))
|
||||
>y : Symbol(y, Decl(class.ts, 2, 30))
|
||||
|
||||
this.x = x;
|
||||
>this.x : Symbol(Point.x, Decl(class.ts, 5, 9))
|
||||
>this : Symbol(Point, Decl(class.ts, 0, 12), Decl(module.ts, 0, 12))
|
||||
>x : Symbol(Point.x, Decl(class.ts, 5, 9))
|
||||
>x : Symbol(x, Decl(class.ts, 2, 20))
|
||||
|
||||
this.y = y;
|
||||
>this.y : Symbol(Point.y, Decl(class.ts, 6, 18))
|
||||
>this : Symbol(Point, Decl(class.ts, 0, 12), Decl(module.ts, 0, 12))
|
||||
>y : Symbol(Point.y, Decl(class.ts, 6, 18))
|
||||
>y : Symbol(y, Decl(class.ts, 2, 30))
|
||||
}
|
||||
x: number;
|
||||
>x : Symbol(Point.x, Decl(class.ts, 5, 9))
|
||||
|
||||
y: number;
|
||||
>y : Symbol(Point.y, Decl(class.ts, 6, 18))
|
||||
}
|
||||
}
|
||||
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/module.ts ===
|
||||
module X.Y {
|
||||
>X : Symbol(X, Decl(class.ts, 0, 0), Decl(module.ts, 0, 0))
|
||||
>Y : Symbol(Y, Decl(class.ts, 0, 9), Decl(module.ts, 0, 9))
|
||||
|
||||
export module Point {
|
||||
>Point : Symbol(Point, Decl(class.ts, 0, 12), Decl(module.ts, 0, 12))
|
||||
|
||||
export var Origin = new Point(0, 0);
|
||||
>Origin : Symbol(Origin, Decl(module.ts, 2, 18))
|
||||
>Point : Symbol(Point, Decl(class.ts, 0, 12), Decl(module.ts, 0, 12))
|
||||
}
|
||||
}
|
||||
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/test.ts ===
|
||||
//var cl: { x: number; y: number; }
|
||||
var cl = new X.Y.Point(1,1);
|
||||
>cl : Symbol(cl, Decl(test.ts, 1, 3), Decl(test.ts, 2, 3))
|
||||
>X.Y.Point : Symbol(X.Y.Point, Decl(class.ts, 0, 12), Decl(module.ts, 0, 12))
|
||||
>X.Y : Symbol(X.Y, Decl(class.ts, 0, 9), Decl(module.ts, 0, 9))
|
||||
>X : Symbol(X, Decl(class.ts, 0, 0), Decl(module.ts, 0, 0))
|
||||
>Y : Symbol(X.Y, Decl(class.ts, 0, 9), Decl(module.ts, 0, 9))
|
||||
>Point : Symbol(X.Y.Point, Decl(class.ts, 0, 12), Decl(module.ts, 0, 12))
|
||||
|
||||
var cl = X.Y.Point.Origin; // error not expected here same as bug 83996 ?
|
||||
>cl : Symbol(cl, Decl(test.ts, 1, 3), Decl(test.ts, 2, 3))
|
||||
>X.Y.Point.Origin : Symbol(X.Y.Point.Origin, Decl(module.ts, 2, 18))
|
||||
>X.Y.Point : Symbol(X.Y.Point, Decl(class.ts, 0, 12), Decl(module.ts, 0, 12))
|
||||
>X.Y : Symbol(X.Y, Decl(class.ts, 0, 9), Decl(module.ts, 0, 9))
|
||||
>X : Symbol(X, Decl(class.ts, 0, 0), Decl(module.ts, 0, 0))
|
||||
>Y : Symbol(X.Y, Decl(class.ts, 0, 9), Decl(module.ts, 0, 9))
|
||||
>Point : Symbol(X.Y.Point, Decl(class.ts, 0, 12), Decl(module.ts, 0, 12))
|
||||
>Origin : Symbol(X.Y.Point.Origin, Decl(module.ts, 2, 18))
|
||||
|
||||
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/simple.ts ===
|
||||
class A {
|
||||
>A : Symbol(A, Decl(simple.ts, 0, 0), Decl(simple.ts, 2, 1))
|
||||
|
||||
id: string;
|
||||
>id : Symbol(A.id, Decl(simple.ts, 0, 9))
|
||||
}
|
||||
|
||||
module A {
|
||||
>A : Symbol(A, Decl(simple.ts, 0, 0), Decl(simple.ts, 2, 1))
|
||||
|
||||
export var Instance = new A();
|
||||
>Instance : Symbol(Instance, Decl(simple.ts, 5, 14))
|
||||
>A : Symbol(A, Decl(simple.ts, 0, 0), Decl(simple.ts, 2, 1))
|
||||
}
|
||||
|
||||
// ensure merging works as expected
|
||||
var a = A.Instance;
|
||||
>a : Symbol(a, Decl(simple.ts, 9, 3), Decl(simple.ts, 10, 3), Decl(simple.ts, 11, 3))
|
||||
>A.Instance : Symbol(A.Instance, Decl(simple.ts, 5, 14))
|
||||
>A : Symbol(A, Decl(simple.ts, 0, 0), Decl(simple.ts, 2, 1))
|
||||
>Instance : Symbol(A.Instance, Decl(simple.ts, 5, 14))
|
||||
|
||||
var a = new A();
|
||||
>a : Symbol(a, Decl(simple.ts, 9, 3), Decl(simple.ts, 10, 3), Decl(simple.ts, 11, 3))
|
||||
>A : Symbol(A, Decl(simple.ts, 0, 0), Decl(simple.ts, 2, 1))
|
||||
|
||||
var a: { id: string };
|
||||
>a : Symbol(a, Decl(simple.ts, 9, 3), Decl(simple.ts, 10, 3), Decl(simple.ts, 11, 3))
|
||||
>id : Symbol(id, Decl(simple.ts, 11, 8))
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/class.ts ===
|
||||
module X.Y {
|
||||
>X : typeof X
|
||||
>Y : typeof Y
|
||||
|
||||
export class Point {
|
||||
>Point : Point
|
||||
|
||||
constructor(x: number, y: number) {
|
||||
>x : number
|
||||
>y : number
|
||||
|
||||
this.x = x;
|
||||
>this.x = x : number
|
||||
>this.x : number
|
||||
>this : this
|
||||
>x : number
|
||||
>x : number
|
||||
|
||||
this.y = y;
|
||||
>this.y = y : number
|
||||
>this.y : number
|
||||
>this : this
|
||||
>y : number
|
||||
>y : number
|
||||
}
|
||||
x: number;
|
||||
>x : number
|
||||
|
||||
y: number;
|
||||
>y : number
|
||||
}
|
||||
}
|
||||
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/module.ts ===
|
||||
module X.Y {
|
||||
>X : typeof X
|
||||
>Y : typeof Y
|
||||
|
||||
export module Point {
|
||||
>Point : typeof Point
|
||||
|
||||
export var Origin = new Point(0, 0);
|
||||
>Origin : Point
|
||||
>new Point(0, 0) : Point
|
||||
>Point : typeof Point
|
||||
>0 : 0
|
||||
>0 : 0
|
||||
}
|
||||
}
|
||||
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/test.ts ===
|
||||
//var cl: { x: number; y: number; }
|
||||
var cl = new X.Y.Point(1,1);
|
||||
>cl : X.Y.Point
|
||||
>new X.Y.Point(1,1) : X.Y.Point
|
||||
>X.Y.Point : typeof X.Y.Point
|
||||
>X.Y : typeof X.Y
|
||||
>X : typeof X
|
||||
>Y : typeof X.Y
|
||||
>Point : typeof X.Y.Point
|
||||
>1 : 1
|
||||
>1 : 1
|
||||
|
||||
var cl = X.Y.Point.Origin; // error not expected here same as bug 83996 ?
|
||||
>cl : X.Y.Point
|
||||
>X.Y.Point.Origin : X.Y.Point
|
||||
>X.Y.Point : typeof X.Y.Point
|
||||
>X.Y : typeof X.Y
|
||||
>X : typeof X
|
||||
>Y : typeof X.Y
|
||||
>Point : typeof X.Y.Point
|
||||
>Origin : X.Y.Point
|
||||
|
||||
|
||||
=== tests/cases/conformance/internalModules/DeclarationMerging/simple.ts ===
|
||||
class A {
|
||||
>A : A
|
||||
|
||||
id: string;
|
||||
>id : string
|
||||
}
|
||||
|
||||
module A {
|
||||
>A : typeof A
|
||||
|
||||
export var Instance = new A();
|
||||
>Instance : A
|
||||
>new A() : A
|
||||
>A : typeof A
|
||||
}
|
||||
|
||||
// ensure merging works as expected
|
||||
var a = A.Instance;
|
||||
>a : A
|
||||
>A.Instance : A
|
||||
>A : typeof A
|
||||
>Instance : A
|
||||
|
||||
var a = new A();
|
||||
>a : A
|
||||
>new A() : A
|
||||
>A : typeof A
|
||||
|
||||
var a: { id: string };
|
||||
>a : A
|
||||
>id : string
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
=== tests/cases/compiler/ClassDeclaration10.ts ===
|
||||
class C {
|
||||
>C : Symbol(C, Decl(ClassDeclaration10.ts, 0, 0))
|
||||
|
||||
constructor();
|
||||
foo();
|
||||
>foo : Symbol(C.foo, Decl(ClassDeclaration10.ts, 1, 17))
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user