Merge branch 'master' into primitive-type-guards-are-order-independent

This commit is contained in:
Nathan Shively-Sanders
2016-06-09 15:56:34 -07:00
76 changed files with 4261 additions and 631 deletions
+14 -54
View File
@@ -5,6 +5,7 @@ var os = require("os");
var path = require("path");
var child_process = require("child_process");
var Linter = require("tslint");
var runTestsInParallel = require("./scripts/mocha-parallel").runTestsInParallel;
// Variables
var compilerDirectory = "src/compiler/";
@@ -312,10 +313,7 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts
}
if (useDebugMode) {
options += " -sourcemap";
if (!opts.noMapRoot) {
options += " -mapRoot file:///" + path.resolve(path.dirname(outFile));
}
options += " --inlineSourceMap --inlineSources";
} else {
options += " --newLine LF";
}
@@ -485,7 +483,6 @@ var tscFile = path.join(builtLocalDirectory, compilerFilename);
compileFile(tscFile, compilerSources, [builtLocalDirectory, copyright].concat(compilerSources), [copyright], /*useBuiltCompiler:*/ false);
var servicesFile = path.join(builtLocalDirectory, "typescriptServices.js");
var servicesFileInBrowserTest = path.join(builtLocalDirectory, "typescriptServicesInBrowserTest.js");
var standaloneDefinitionsFile = path.join(builtLocalDirectory, "typescriptServices.d.ts");
var nodePackageFile = path.join(builtLocalDirectory, "typescript.js");
var nodeDefinitionsFile = path.join(builtLocalDirectory, "typescript.d.ts");
@@ -517,16 +514,6 @@ compileFile(servicesFile, servicesSources,[builtLocalDirectory, copyright].conca
fs.writeFileSync(nodeStandaloneDefinitionsFile, nodeStandaloneDefinitionsFileContents);
});
compileFile(servicesFileInBrowserTest, servicesSources,[builtLocalDirectory, copyright].concat(servicesSources),
/*prefixes*/ [copyright],
/*useBuiltCompiler*/ true,
{ noOutFile: false, generateDeclarations: true, preserveConstEnums: true, keepComments: true, noResolve: false, stripInternal: true, noMapRoot: true },
/*callback*/ function () {
var content = fs.readFileSync(servicesFileInBrowserTest).toString();
var i = content.lastIndexOf("\n");
fs.writeFileSync(servicesFileInBrowserTest, content.substring(0, i) + "\r\n//# sourceURL=../built/local/typeScriptServices.js" + content.substring(i));
});
var serverFile = path.join(builtLocalDirectory, "tsserver.js");
compileFile(serverFile, serverSources,[builtLocalDirectory, copyright].concat(serverSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true);
@@ -688,7 +675,6 @@ function cleanTestDirs() {
// used to pass data from jake command line directly to run.js
function writeTestConfigFile(tests, light, taskConfigsFolder, workerCount) {
var testConfigContents = JSON.stringify({ test: tests ? [tests] : undefined, light: light, workerCount: workerCount, taskConfigsFolder: taskConfigsFolder });
console.log('Running tests with config: ' + testConfigContents);
fs.writeFileSync('test.config', testConfigContents);
}
@@ -749,42 +735,16 @@ function runConsoleTests(defaultReporter, runInParallel) {
}
else {
// run task to load all tests and partition them between workers
var cmd = "mocha " + " -R min " + colors + run;
console.log(cmd);
exec(cmd, function() {
// read all configuration files and spawn a worker for every config
var configFiles = fs.readdirSync(taskConfigsFolder);
var counter = configFiles.length;
var firstErrorStatus;
// schedule work for chunks
configFiles.forEach(function (f) {
var configPath = path.join(taskConfigsFolder, f);
var workerCmd = "mocha" + " -t " + testTimeout + " -R " + reporter + " " + colors + " " + run + " --config='" + configPath + "'";
console.log(workerCmd);
exec(workerCmd, finishWorker, finishWorker)
});
function finishWorker(e, errorStatus) {
counter--;
if (firstErrorStatus === undefined && errorStatus !== undefined) {
firstErrorStatus = errorStatus;
}
if (counter !== 0) {
complete();
}
else {
// last worker clean everything and runs linter in case if there were no errors
deleteTemporaryProjectOutput();
jake.rmRf(taskConfigsFolder);
if (firstErrorStatus === undefined) {
runLinter();
complete();
}
else {
failWithStatus(firstErrorStatus);
}
}
runTestsInParallel(taskConfigsFolder, run, { testTimeout: testTimeout, noColors: colors === " --no-colors " }, function (err) {
// 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();
}
});
}
@@ -839,12 +799,12 @@ compileFile(nodeServerOutFile, [nodeServerInFile], [builtLocalDirectory, tscFile
desc("Runs browserify on run.js to produce a file suitable for running tests in the browser");
task("browserify", ["tests", builtLocalDirectory, nodeServerOutFile], function() {
var cmd = 'browserify built/local/run.js -o built/local/bundle.js';
var cmd = 'browserify built/local/run.js -d -o built/local/bundle.js';
exec(cmd);
}, {async: true});
desc("Runs the tests using the built run.js file like 'jake runtests'. Syntax is jake runtests-browser. Additional optional parameters tests=[regex], port=, browser=[chrome|IE]");
task("runtests-browser", ["tests", "browserify", builtLocalDirectory, servicesFileInBrowserTest], function() {
task("runtests-browser", ["tests", "browserify", builtLocalDirectory, servicesFile], function() {
cleanTestDirs();
host = "node";
port = process.env.port || process.env.p || '8888';
+26
View File
@@ -0,0 +1,26 @@
/**
* 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;
+367
View File
@@ -0,0 +1,367 @@
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 = child_process.spawn(
process.platform === "win32" ? "cmd" : "/bin/sh",
process.platform === "win32" ? ["/c", cmd] : ["-c", cmd], {
windowsVerbatimArguments: true,
env: { NODE_ENV: "development" }
});
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,
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 = child_process.spawn(
process.platform === "win32" ? "cmd" : "/bin/sh",
process.platform === "win32" ? ["/c", cmd] : ["-c", cmd], {
windowsVerbatimArguments: true,
env: { NODE_ENV: "development" }
});
var rl = readline.createInterface({
input: p.stdout,
terminal: false
});
rl.on("line", onmessage);
p.on("exit", onexit)
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() {
if (partition.end === undefined) {
partition.end = Date.now();
}
partition.duration = partition.end - partition.start;
var summaryColor = partition.failed ? "fail" : "green";
var summarySymbol = partition.failed ? Base.symbols.err : Base.symbols.ok;
var summaryTests = (partition.passed === partition.tests ? partition.passed : partition.passed + "/" + partition.tests) + " 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 failed = 0;
var reporter = new Base(),
stats = reporter.stats,
failures = reporter.failures;
var duration = 0;
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;
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 (failed) {
return cb(new Error("Test failures reported: " + failed));
}
else {
return cb();
}
}
}
function makeMochaTest(test) {
return {
fullTitle: function() {
return test.name;
},
err: {
message: test.output[0],
stack: test.output.join(os.EOL)
}
};
}
}
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;
}
+20 -5
View File
@@ -1198,9 +1198,9 @@ namespace ts {
lastContainer = next;
}
function declareSymbolAndAddToSymbolTable(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): void {
function declareSymbolAndAddToSymbolTable(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol {
// Just call this directly so that the return type of this function stays "void".
declareSymbolAndAddToSymbolTableWorker(node, symbolFlags, symbolExcludes);
return declareSymbolAndAddToSymbolTableWorker(node, symbolFlags, symbolExcludes);
}
function declareSymbolAndAddToSymbolTableWorker(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol {
@@ -1304,7 +1304,22 @@ namespace ts {
declareSymbolAndAddToSymbolTable(node, SymbolFlags.NamespaceModule, SymbolFlags.NamespaceModuleExcludes);
}
else {
declareSymbolAndAddToSymbolTable(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes);
let pattern: Pattern | undefined;
if (node.name.kind === SyntaxKind.StringLiteral) {
const text = (<StringLiteral>node.name).text;
if (hasZeroOrOneAsteriskCharacter(text)) {
pattern = tryParsePattern(text);
}
else {
errorOnFirstToken(node.name, Diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, text);
}
}
const symbol = declareSymbolAndAddToSymbolTable(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes);
if (pattern) {
(file.patternAmbientModules || (file.patternAmbientModules = [])).push({ pattern, symbol });
}
}
}
else {
@@ -2082,10 +2097,10 @@ namespace ts {
checkStrictModeFunctionName(<FunctionDeclaration>node);
if (inStrictMode) {
checkStrictModeFunctionDeclaration(node);
return bindBlockScopedDeclaration(node, SymbolFlags.Function, SymbolFlags.FunctionExcludes);
bindBlockScopedDeclaration(node, SymbolFlags.Function, SymbolFlags.FunctionExcludes);
}
else {
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.Function, SymbolFlags.FunctionExcludes);
declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.Function, SymbolFlags.FunctionExcludes);
}
}
+78 -44
View File
@@ -140,6 +140,12 @@ namespace ts {
const enumNumberIndexInfo = createIndexInfo(stringType, /*isReadonly*/ true);
const globals: SymbolTable = {};
/**
* List of every ambient module with a "*" wildcard.
* Unlike other ambient modules, these can't be stored in `globals` because symbol tables only deal with exact matches.
* This is only used if there is no exact match.
*/
let patternAmbientModules: PatternAmbientModule[];
let getGlobalESSymbolConstructorSymbol: () => Symbol;
@@ -1285,6 +1291,14 @@ namespace ts {
}
return undefined;
}
if (patternAmbientModules) {
const pattern = findBestPatternMatch(patternAmbientModules, _ => _.pattern, moduleName);
if (pattern) {
return getMergedSymbol(pattern.symbol);
}
}
if (moduleNotFoundError) {
// report errors only if it was requested
error(moduleReferenceLiteral, moduleNotFoundError, moduleName);
@@ -2844,7 +2858,7 @@ namespace ts {
}
// In strict null checking mode, if a default value of a non-undefined type is specified, remove
// undefined from the final type.
if (strictNullChecks && declaration.initializer && !(getNullableKind(checkExpressionCached(declaration.initializer)) & TypeFlags.Undefined)) {
if (strictNullChecks && declaration.initializer && !(getCombinedTypeFlags(checkExpressionCached(declaration.initializer)) & TypeFlags.Undefined)) {
type = getTypeWithFacts(type, TypeFacts.NEUndefined);
}
return type;
@@ -2887,7 +2901,7 @@ namespace ts {
}
function addOptionality(type: Type, optional: boolean): Type {
return strictNullChecks && optional ? addNullableKind(type, TypeFlags.Undefined) : type;
return strictNullChecks && optional ? addTypeKind(type, TypeFlags.Undefined) : type;
}
// Return the inferred type for a variable, parameter, or property declaration
@@ -3222,7 +3236,7 @@ namespace ts {
if (!links.type) {
const type = createObjectType(TypeFlags.Anonymous, symbol);
links.type = strictNullChecks && symbol.flags & SymbolFlags.Optional ?
addNullableKind(type, TypeFlags.Undefined) : type;
addTypeKind(type, TypeFlags.Undefined) : type;
}
return links.type;
}
@@ -6746,7 +6760,7 @@ namespace ts {
return getUnionType(types);
}
const supertype = forEach(primaryTypes, t => isSupertypeOfEach(t, primaryTypes) ? t : undefined);
return supertype && addNullableKind(supertype, getCombinedFlagsOfTypes(types) & TypeFlags.Nullable);
return supertype && addTypeKind(supertype, getCombinedFlagsOfTypes(types) & TypeFlags.Nullable);
}
function reportNoCommonSupertypeError(types: Type[], errorLocation: Node, errorMessageChainHead: DiagnosticMessageChain): void {
@@ -6817,28 +6831,22 @@ namespace ts {
return !!(type.flags & TypeFlags.Tuple);
}
function getNullableKind(type: Type): TypeFlags {
let flags = type.flags;
if (flags & TypeFlags.Union) {
for (const t of (type as UnionType).types) {
flags |= t.flags;
}
}
return flags & TypeFlags.Nullable;
function getCombinedTypeFlags(type: Type): TypeFlags {
return type.flags & TypeFlags.Union ? getCombinedFlagsOfTypes((<UnionType>type).types) : type.flags;
}
function addNullableKind(type: Type, kind: TypeFlags): Type {
if ((getNullableKind(type) & kind) !== kind) {
const types = [type];
if (kind & TypeFlags.Undefined) {
types.push(undefinedType);
}
if (kind & TypeFlags.Null) {
types.push(nullType);
}
type = getUnionType(types);
function addTypeKind(type: Type, kind: TypeFlags) {
if ((getCombinedTypeFlags(type) & kind) === kind) {
return type;
}
return type;
const types = [type];
if (kind & TypeFlags.String) types.push(stringType);
if (kind & TypeFlags.Number) types.push(numberType);
if (kind & TypeFlags.Boolean) types.push(booleanType);
if (kind & TypeFlags.Void) types.push(voidType);
if (kind & TypeFlags.Undefined) types.push(undefinedType);
if (kind & TypeFlags.Null) types.push(nullType);
return getUnionType(types);
}
function getNonNullableType(type: Type): Type {
@@ -7662,12 +7670,27 @@ namespace ts {
getInitialTypeOfBindingElement(<BindingElement>node);
}
function getReferenceFromExpression(node: Expression): Expression {
switch (node.kind) {
case SyntaxKind.ParenthesizedExpression:
return getReferenceFromExpression((<ParenthesizedExpression>node).expression);
case SyntaxKind.BinaryExpression:
switch ((<BinaryExpression>node).operatorToken.kind) {
case SyntaxKind.EqualsToken:
return getReferenceFromExpression((<BinaryExpression>node).left);
case SyntaxKind.CommaToken:
return getReferenceFromExpression((<BinaryExpression>node).right);
}
}
return node;
}
function getFlowTypeOfReference(reference: Node, declaredType: Type, assumeInitialized: boolean, includeOuterFunctions: boolean) {
let key: string;
if (!reference.flowNode || assumeInitialized && !(declaredType.flags & TypeFlags.Narrowable)) {
return declaredType;
}
const initialType = assumeInitialized ? declaredType : addNullableKind(declaredType, TypeFlags.Undefined);
const initialType = assumeInitialized ? declaredType : addTypeKind(declaredType, TypeFlags.Undefined);
const visitedFlowStart = visitedFlowCount;
const result = getTypeAtFlowNode(reference.flowNode);
visitedFlowCount = visitedFlowStart;
@@ -7885,7 +7908,7 @@ namespace ts {
if (operator === SyntaxKind.ExclamationEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) {
assumeTrue = !assumeTrue;
}
if (!strictNullChecks || !isMatchingReference(reference, narrowed)) {
if (!strictNullChecks || !isMatchingReference(reference, getReferenceFromExpression(narrowed))) {
return type;
}
const doubleEquals = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken;
@@ -7900,12 +7923,12 @@ namespace ts {
function narrowTypeByTypeof(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
// We have '==', '!=', '====', or !==' operator with 'typeof xxx' on the left
// and string literal on the right
const typeOf = <TypeOfExpression>(expr.left.kind === SyntaxKind.TypeOfExpression ? expr.left : expr.right);
const narrowed = getReferenceFromExpression((<TypeOfExpression>(expr.left.kind === SyntaxKind.TypeOfExpression ? expr.left : expr.right)).expression);
const literal = <LiteralExpression>(expr.right.kind === SyntaxKind.StringLiteral ? expr.right : expr.left);
if (!isMatchingReference(reference, typeOf.expression)) {
if (!isMatchingReference(reference, narrowed)) {
// For a reference of the form 'x.y', a 'typeof x === ...' type guard resets the
// narrowed type of 'y' to its declared type.
if (containsMatchingReference(reference, typeOf.expression)) {
if (containsMatchingReference(reference, narrowed)) {
return declaredType;
}
return type;
@@ -7930,10 +7953,11 @@ namespace ts {
}
function narrowTypeByInstanceof(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
if (!isMatchingReference(reference, expr.left)) {
const left = getReferenceFromExpression(expr.left);
if (!isMatchingReference(reference, left)) {
// For a reference of the form 'x.y', an 'x instanceof T' type guard resets the
// narrowed type of 'y' to its declared type.
if (containsMatchingReference(reference, expr.left)) {
if (containsMatchingReference(reference, left)) {
return declaredType;
}
return type;
@@ -8000,7 +8024,7 @@ namespace ts {
const targetType = type.flags & TypeFlags.TypeParameter ? getApparentType(type) : type;
return isTypeAssignableTo(candidate, targetType) ? candidate :
isTypeAssignableTo(type, candidate) ? type :
neverType;
getIntersectionType([type, candidate]);
}
function narrowTypeByTypePredicate(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type {
@@ -8175,7 +8199,7 @@ namespace ts {
getRootDeclaration(declaration).kind === SyntaxKind.Parameter || isInAmbientContext(declaration) ||
!isDeclarationIncludedInFlow(node, declaration, includeOuterFunctions);
const flowType = getFlowTypeOfReference(node, type, assumeInitialized, includeOuterFunctions);
if (!assumeInitialized && !(getNullableKind(type) & TypeFlags.Undefined) && getNullableKind(flowType) & TypeFlags.Undefined) {
if (!assumeInitialized && !(getCombinedTypeFlags(type) & TypeFlags.Undefined) && getCombinedTypeFlags(flowType) & TypeFlags.Undefined) {
error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol));
// Return the declared type to reduce follow-on errors
return type;
@@ -8749,6 +8773,16 @@ namespace ts {
function getContextualTypeForReturnExpression(node: Expression): Type {
const func = getContainingFunction(node);
if (isAsyncFunctionLike(func)) {
const contextualReturnType = getContextualReturnType(func);
if (contextualReturnType) {
return getPromisedType(contextualReturnType);
}
return undefined;
}
if (func && !func.asteriskToken) {
return getContextualReturnType(func);
}
@@ -9957,7 +9991,7 @@ namespace ts {
function checkNonNullExpression(node: Expression | QualifiedName) {
const type = checkExpression(node);
if (strictNullChecks) {
const kind = getNullableKind(type);
const kind = getCombinedTypeFlags(type) & TypeFlags.Nullable;
if (kind) {
error(node, kind & TypeFlags.Undefined ? kind & TypeFlags.Null ?
Diagnostics.Object_is_possibly_null_or_undefined :
@@ -11491,7 +11525,7 @@ namespace ts {
if (strictNullChecks) {
const declaration = symbol.valueDeclaration;
if (declaration && (<VariableLikeDeclaration>declaration).initializer) {
return addNullableKind(type, TypeFlags.Undefined);
return addTypeKind(type, TypeFlags.Undefined);
}
}
return type;
@@ -12417,7 +12451,7 @@ namespace ts {
case SyntaxKind.InKeyword:
return checkInExpression(left, right, leftType, rightType);
case SyntaxKind.AmpersandAmpersandToken:
return strictNullChecks ? addNullableKind(rightType, getNullableKind(leftType)) : rightType;
return strictNullChecks ? addTypeKind(rightType, getCombinedTypeFlags(leftType) & TypeFlags.Falsy) : rightType;
case SyntaxKind.BarBarToken:
return getUnionType([getNonNullableType(leftType), rightType]);
case SyntaxKind.EqualsToken:
@@ -16866,10 +16900,7 @@ namespace ts {
return getIntrinsicTagSymbol(<JsxOpeningLikeElement>entityName.parent);
}
// Include aliases in the meaning, this ensures that we do not follow aliases to where they point and instead
// return the alias symbol.
const meaning: SymbolFlags = SymbolFlags.Value | SymbolFlags.Alias;
return resolveEntityName(<Identifier>entityName, meaning);
return resolveEntityName(<Identifier>entityName, SymbolFlags.Value, /*ignoreErrors*/ false, /*dontResolveAlias*/ true);
}
else if (entityName.kind === SyntaxKind.PropertyAccessExpression) {
const symbol = getNodeLinks(entityName).resolvedSymbol;
@@ -16887,11 +16918,8 @@ namespace ts {
}
}
else if (isTypeReferenceIdentifier(<EntityName>entityName)) {
let meaning = (entityName.parent.kind === SyntaxKind.TypeReference || entityName.parent.kind === SyntaxKind.JSDocTypeReference) ? SymbolFlags.Type : SymbolFlags.Namespace;
// Include aliases in the meaning, this ensures that we do not follow aliases to where they point and instead
// return the alias symbol.
meaning |= SymbolFlags.Alias;
return resolveEntityName(<EntityName>entityName, meaning);
const meaning = (entityName.parent.kind === SyntaxKind.TypeReference || entityName.parent.kind === SyntaxKind.JSDocTypeReference) ? SymbolFlags.Type : SymbolFlags.Namespace;
return resolveEntityName(<EntityName>entityName, meaning, /*ignoreErrors*/ false, /*dontResolveAlias*/true);
}
else if (entityName.parent.kind === SyntaxKind.JsxAttribute) {
return getJsxAttributePropertySymbol(<JsxAttribute>entityName.parent);
@@ -17635,6 +17663,10 @@ namespace ts {
if (!isExternalOrCommonJsModule(file)) {
mergeSymbolTable(globals, file.locals);
}
if (file.patternAmbientModules && file.patternAmbientModules.length) {
patternAmbientModules = concatenate(patternAmbientModules, file.patternAmbientModules);
}
if (file.moduleAugmentations.length) {
(augmentations || (augmentations = [])).push(file.moduleAugmentations);
}
@@ -17765,6 +17797,8 @@ namespace ts {
case SyntaxKind.ImportEqualsDeclaration:
case SyntaxKind.ExportDeclaration:
case SyntaxKind.ExportAssignment:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
case SyntaxKind.Parameter:
break;
case SyntaxKind.FunctionDeclaration:
+1 -1
View File
@@ -6,7 +6,7 @@
namespace ts {
/* @internal */
export let optionDeclarations: CommandLineOption[] = [
export const optionDeclarations: CommandLineOption[] = [
{
name: "charset",
type: "string",
+11 -2
View File
@@ -849,13 +849,22 @@ namespace ts {
const extensionsToRemove = [".d.ts", ".ts", ".js", ".tsx", ".jsx"];
export function removeFileExtension(path: string): string {
for (const ext of extensionsToRemove) {
if (fileExtensionIs(path, ext)) {
return path.substr(0, path.length - ext.length);
const extensionless = tryRemoveExtension(path, ext);
if (extensionless !== undefined) {
return extensionless;
}
}
return path;
}
export function tryRemoveExtension(path: string, extension: string): string {
return fileExtensionIs(path, extension) ? path.substring(0, path.length - extension.length) : undefined;
}
export function isJsxOrTsxExtension(ext: string): boolean {
return ext === ".jsx" || ext === ".tsx";
}
export interface ObjectAllocator {
getNodeConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => Node;
getSourceFileConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => SourceFile;
+5 -1
View File
@@ -2260,7 +2260,7 @@
"category": "Error",
"code": 5047
},
"Option 'inlineSources' can only be used when either option '--inlineSourceMap' or option '--sourceMap' is provided.": {
"Option '{0} can only be used when either option '--inlineSourceMap' or option '--sourceMap' is provided.": {
"category": "Error",
"code": 5051
},
@@ -2772,6 +2772,10 @@
"category": "Error",
"code": 6131
},
"File name '{0}' has a '{1}' extension - stripping it": {
"category": "Message",
"code": 6132
},
"Variable '{0}' implicitly has an '{1}' type.": {
"category": "Error",
+105 -48
View File
@@ -95,7 +95,8 @@ namespace ts {
return compilerOptions.traceResolution && host.trace !== undefined;
}
function hasZeroOrOneAsteriskCharacter(str: string): boolean {
/* @internal */
export function hasZeroOrOneAsteriskCharacter(str: string): boolean {
let seenAsterisk = false;
for (let i = 0; i < str.length; i++) {
if (str.charCodeAt(i) === CharacterCodes.asterisk) {
@@ -496,48 +497,23 @@ namespace ts {
trace(state.host, Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, state.compilerOptions.baseUrl, moduleName);
}
let longestMatchPrefixLength = -1;
let matchedPattern: string;
let matchedStar: string;
// string is for exact match
let matchedPattern: Pattern | string | undefined = undefined;
if (state.compilerOptions.paths) {
if (state.traceEnabled) {
trace(state.host, Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, moduleName);
}
for (const key in state.compilerOptions.paths) {
const pattern: string = key;
const indexOfStar = pattern.indexOf("*");
if (indexOfStar !== -1) {
const prefix = pattern.substr(0, indexOfStar);
const suffix = pattern.substr(indexOfStar + 1);
if (moduleName.length >= prefix.length + suffix.length &&
startsWith(moduleName, prefix) &&
endsWith(moduleName, suffix)) {
// use length of prefix as betterness criteria
if (prefix.length > longestMatchPrefixLength) {
longestMatchPrefixLength = prefix.length;
matchedPattern = pattern;
matchedStar = moduleName.substr(prefix.length, moduleName.length - suffix.length);
}
}
}
else if (pattern === moduleName) {
// pattern was matched as is - no need to search further
matchedPattern = pattern;
matchedStar = undefined;
break;
}
}
matchedPattern = matchPatternOrExact(getKeys(state.compilerOptions.paths), moduleName);
}
if (matchedPattern) {
const matchedStar = typeof matchedPattern === "string" ? undefined : matchedText(matchedPattern, moduleName);
const matchedPatternText = typeof matchedPattern === "string" ? matchedPattern : patternText(matchedPattern);
if (state.traceEnabled) {
trace(state.host, Diagnostics.Module_name_0_matched_pattern_1, moduleName, matchedPattern);
trace(state.host, Diagnostics.Module_name_0_matched_pattern_1, moduleName, matchedPatternText);
}
for (const subst of state.compilerOptions.paths[matchedPattern]) {
const path = matchedStar ? subst.replace("\*", matchedStar) : subst;
for (const subst of state.compilerOptions.paths[matchedPatternText]) {
const path = matchedStar ? subst.replace("*", matchedStar) : subst;
const candidate = normalizePath(combinePaths(state.compilerOptions.baseUrl, path));
if (state.traceEnabled) {
trace(state.host, Diagnostics.Trying_substitution_0_candidate_module_location_Colon_1, subst, path);
@@ -560,6 +536,75 @@ namespace ts {
}
}
/**
* patternStrings contains both pattern strings (containing "*") and regular strings.
* Return an exact match if possible, or a pattern match, or undefined.
* (These are verified by verifyCompilerOptions to have 0 or 1 "*" characters.)
*/
function matchPatternOrExact(patternStrings: string[], candidate: string): string | Pattern | undefined {
const patterns: Pattern[] = [];
for (const patternString of patternStrings) {
const pattern = tryParsePattern(patternString);
if (pattern) {
patterns.push(pattern);
}
else if (patternString === candidate) {
// pattern was matched as is - no need to search further
return patternString;
}
}
return findBestPatternMatch(patterns, _ => _, candidate);
}
function patternText({prefix, suffix}: Pattern): string {
return `${prefix}*${suffix}`;
}
/**
* Given that candidate matches pattern, returns the text matching the '*'.
* E.g.: matchedText(tryParsePattern("foo*baz"), "foobarbaz") === "bar"
*/
function matchedText(pattern: Pattern, candidate: string): string {
Debug.assert(isPatternMatch(pattern, candidate));
return candidate.substr(pattern.prefix.length, candidate.length - pattern.suffix.length);
}
/** Return the object corresponding to the best pattern to match `candidate`. */
/* @internal */
export function findBestPatternMatch<T>(values: T[], getPattern: (value: T) => Pattern, candidate: string): T | undefined {
let matchedValue: T | undefined = undefined;
// use length of prefix as betterness criteria
let longestMatchPrefixLength = -1;
for (const v of values) {
const pattern = getPattern(v);
if (isPatternMatch(pattern, candidate) && pattern.prefix.length > longestMatchPrefixLength) {
longestMatchPrefixLength = pattern.prefix.length;
matchedValue = v;
}
}
return matchedValue;
}
function isPatternMatch({prefix, suffix}: Pattern, candidate: string) {
return candidate.length >= prefix.length + suffix.length &&
startsWith(candidate, prefix) &&
endsWith(candidate, suffix);
}
/* @internal */
export function tryParsePattern(pattern: string): Pattern | undefined {
// This should be verified outside of here and a proper error thrown.
Debug.assert(hasZeroOrOneAsteriskCharacter(pattern));
const indexOfStar = pattern.indexOf("*");
return indexOfStar === -1 ? undefined : {
prefix: pattern.substr(0, indexOfStar),
suffix: pattern.substr(indexOfStar + 1)
};
}
export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
const containingDirectory = getDirectoryPath(containingFile);
const supportedExtensions = getSupportedExtensions(compilerOptions);
@@ -619,8 +664,25 @@ namespace ts {
* in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations.
*/
function loadModuleFromFile(candidate: string, extensions: string[], failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string {
// First try to keep/add an extension: importing "./foo.ts" can be matched by a file "./foo.ts", and "./foo" by "./foo.d.ts"
const resolvedByAddingOrKeepingExtension = loadModuleFromFileWorker(candidate, extensions, failedLookupLocation, onlyRecordFailures, state);
if (resolvedByAddingOrKeepingExtension) {
return resolvedByAddingOrKeepingExtension;
}
// Then try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one, e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts"
if (hasJavaScriptFileExtension(candidate)) {
const extensionless = removeFileExtension(candidate);
if (state.traceEnabled) {
const extension = candidate.substring(extensionless.length);
trace(state.host, Diagnostics.File_name_0_has_a_1_extension_stripping_it, candidate, extension);
}
return loadModuleFromFileWorker(extensionless, extensions, failedLookupLocation, onlyRecordFailures, state);
}
}
function loadModuleFromFileWorker(candidate: string, extensions: string[], failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string {
if (!onlyRecordFailures) {
// check if containig folder exists - if it doesn't then just record failures for all supported extensions without disk probing
// check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing
const directory = getDirectoryPath(candidate);
if (directory) {
onlyRecordFailures = !directoryProbablyExists(directory, state.host);
@@ -629,7 +691,7 @@ namespace ts {
return forEach(extensions, tryLoad);
function tryLoad(ext: string): string {
if (ext === ".tsx" && state.skipTsx) {
if (state.skipTsx && isJsxOrTsxExtension(ext)) {
return undefined;
}
const fileName = fileExtensionIs(candidate, ext) ? candidate : candidate + ext;
@@ -2043,12 +2105,12 @@ namespace ts {
}
}
if (options.inlineSources) {
if (!options.sourceMap && !options.inlineSourceMap) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_inlineSources_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided));
if (!options.sourceMap && !options.inlineSourceMap) {
if (options.inlineSources) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "inlineSources"));
}
if (options.sourceRoot) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "sourceRoot", "inlineSources"));
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "sourceRoot"));
}
}
@@ -2056,14 +2118,9 @@ namespace ts {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "out", "outFile"));
}
if (!options.sourceMap && (options.mapRoot || options.sourceRoot)) {
// Error to specify --mapRoot or --sourceRoot without mapSourceFiles
if (options.mapRoot) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "mapRoot", "sourceMap"));
}
if (options.sourceRoot && !options.inlineSourceMap) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "sourceRoot", "sourceMap"));
}
if (options.mapRoot && !options.sourceMap) {
// Error to specify --mapRoot without --sourcemap
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "mapRoot", "sourceMap"));
}
if (options.declarationDir) {
+16
View File
@@ -1658,6 +1658,7 @@ namespace ts {
/* @internal */ resolvedTypeReferenceDirectiveNames: Map<ResolvedTypeReferenceDirective>;
/* @internal */ imports: LiteralExpression[];
/* @internal */ moduleAugmentations: LiteralExpression[];
/* @internal */ patternAmbientModules?: PatternAmbientModule[];
}
export interface ScriptReferenceHost {
@@ -2135,6 +2136,20 @@ namespace ts {
[index: string]: Symbol;
}
/** Represents a "prefix*suffix" pattern. */
/* @internal */
export interface Pattern {
prefix: string;
suffix: string;
}
/** Used to track a `declare module "foo*"`-like declaration. */
/* @internal */
export interface PatternAmbientModule {
pattern: Pattern;
symbol: Symbol;
}
/* @internal */
export const enum NodeCheckFlags {
TypeChecked = 0x00000001, // Node has been type checked
@@ -2209,6 +2224,7 @@ namespace ts {
/* @internal */
Nullable = Undefined | Null,
Falsy = String | Number | Boolean | Void | Undefined | Null,
/* @internal */
Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null | Never,
/* @internal */
-3
View File
@@ -1692,6 +1692,3 @@ namespace Harness {
if (Error) (<any>Error).stackTraceLimit = 1;
}
// TODO: not sure why Utils.evalFile isn't working with this, eventually will concat it like old compiler instead of eval
eval(Harness.tcServicesFile);
+5 -1
View File
@@ -1207,7 +1207,11 @@ namespace ts.server {
// Handle cancellation exceptions
}
this.logError(err, message);
this.output(undefined, request ? request.command : CommandNames.Unknown, request ? request.seq : 0, "Error processing request. " + err.message);
this.output(
undefined,
request ? request.command : CommandNames.Unknown,
request ? request.seq : 0,
"Error processing request. " + (<StackTraceError>err).message + "\n" + (<StackTraceError>err).stack);
}
}
}
+1 -1
View File
@@ -722,5 +722,5 @@ namespace ts.BreakpointResolver {
return spanInNode(node.parent);
}
}
}
}
}
+142 -18
View File
@@ -1064,10 +1064,10 @@ namespace ts {
getCancellationToken?(): HostCancellationToken;
getCurrentDirectory(): string;
getDefaultLibFileName(options: CompilerOptions): string;
log? (s: string): void;
trace? (s: string): void;
error? (s: string): void;
useCaseSensitiveFileNames? (): boolean;
log?(s: string): void;
trace?(s: string): void;
error?(s: string): void;
useCaseSensitiveFileNames?(): boolean;
/*
* LS host can optionally implement this method if it wants to be completely in charge of module name resolution.
@@ -1939,6 +1939,40 @@ namespace ts {
sourceMapText?: string;
}
let commandLineOptions_stringToEnum: CommandLineOptionOfCustomType[];
/** JS users may pass in string values for enum compiler options (such as ModuleKind), so convert. */
function fixupCompilerOptions(options: CompilerOptions, diagnostics: Diagnostic[]): CompilerOptions {
// Lazily create this value to fix module loading errors.
commandLineOptions_stringToEnum = commandLineOptions_stringToEnum || <CommandLineOptionOfCustomType[]>filter(optionDeclarations, o =>
typeof o.type === "object" && !forEachValue(<Map<any>> o.type, v => typeof v !== "number"));
options = clone(options);
for (const opt of commandLineOptions_stringToEnum) {
if (!hasProperty(options, opt.name)) {
continue;
}
const value = options[opt.name];
// Value should be a key of opt.type
if (typeof value === "string") {
// If value is not a string, this will fail
options[opt.name] = parseCustomTypeOption(opt, value, diagnostics);
}
else {
if (!forEachValue(opt.type, v => v === value)) {
// Supplied value isn't a valid enum value.
diagnostics.push(createCompilerDiagnosticForInvalidCustomType(opt));
}
}
}
return options;
}
/*
* This function will compile source text from 'input' argument using specified compiler options.
* If not options are provided - it will use a set of default compiler options.
@@ -1949,7 +1983,9 @@ namespace ts {
* - noResolve = true
*/
export function transpileModule(input: string, transpileOptions: TranspileOptions): TranspileOutput {
const options = transpileOptions.compilerOptions ? clone(transpileOptions.compilerOptions) : getDefaultCompilerOptions();
const diagnostics: Diagnostic[] = [];
const options: CompilerOptions = transpileOptions.compilerOptions ? fixupCompilerOptions(transpileOptions.compilerOptions, diagnostics) : getDefaultCompilerOptions();
options.isolatedModules = true;
@@ -2007,9 +2043,7 @@ namespace ts {
const program = createProgram([inputFileName], options, compilerHost);
let diagnostics: Diagnostic[];
if (transpileOptions.reportDiagnostics) {
diagnostics = [];
addRange(/*to*/ diagnostics, /*from*/ program.getSyntacticDiagnostics(sourceFile));
addRange(/*to*/ diagnostics, /*from*/ program.getOptionsDiagnostics());
}
@@ -2499,7 +2533,7 @@ namespace ts {
}
// should be start of dependency list
if (token !== SyntaxKind.OpenBracketToken) {
if (token !== SyntaxKind.OpenBracketToken) {
return true;
}
@@ -4032,10 +4066,15 @@ namespace ts {
}
}
function getCompletionsAtPosition(fileName: string, position: number): CompletionInfo {
synchronizeHostData();
const sourceFile = getValidSourceFile(fileName);
if (isInString(sourceFile, position)) {
return getStringLiteralCompletionEntries(sourceFile, position);
}
const completionData = getCompletionData(fileName, position);
if (!completionData) {
return undefined;
@@ -4048,12 +4087,10 @@ namespace ts {
return { isMemberCompletion: false, isNewIdentifierLocation: false, entries: getAllJsDocCompletionEntries() };
}
const sourceFile = getValidSourceFile(fileName);
const entries: CompletionEntry[] = [];
if (isSourceFileJavaScript(sourceFile)) {
const uniqueNames = getCompletionEntriesFromSymbols(symbols, entries);
const uniqueNames = getCompletionEntriesFromSymbols(symbols, entries, location, /*performCharacterChecks*/ false);
addRange(entries, getJavaScriptCompletionEntries(sourceFile, location.pos, uniqueNames));
}
else {
@@ -4077,7 +4114,7 @@ namespace ts {
}
}
getCompletionEntriesFromSymbols(symbols, entries);
getCompletionEntriesFromSymbols(symbols, entries, location, /*performCharacterChecks*/ true);
}
// Add keywords if this is not a member completion list
@@ -4127,11 +4164,11 @@ namespace ts {
}));
}
function createCompletionEntry(symbol: Symbol, location: Node): CompletionEntry {
function createCompletionEntry(symbol: Symbol, location: Node, performCharacterChecks: boolean): CompletionEntry {
// Try to get a valid display name for this symbol, if we could not find one, then ignore it.
// We would like to only show things that can be added after a dot, so for instance numeric properties can
// not be accessed with a dot (a.1 <- invalid)
const displayName = getCompletionEntryDisplayNameForSymbol(symbol, program.getCompilerOptions().target, /*performCharacterChecks*/ true, location);
const displayName = getCompletionEntryDisplayNameForSymbol(symbol, program.getCompilerOptions().target, performCharacterChecks, location);
if (!displayName) {
return undefined;
}
@@ -4152,12 +4189,12 @@ namespace ts {
};
}
function getCompletionEntriesFromSymbols(symbols: Symbol[], entries: CompletionEntry[]): Map<string> {
function getCompletionEntriesFromSymbols(symbols: Symbol[], entries: CompletionEntry[], location: Node, performCharacterChecks: boolean): Map<string> {
const start = new Date().getTime();
const uniqueNames: Map<string> = {};
if (symbols) {
for (const symbol of symbols) {
const entry = createCompletionEntry(symbol, location);
const entry = createCompletionEntry(symbol, location, performCharacterChecks);
if (entry) {
const id = escapeIdentifier(entry.name);
if (!lookUp(uniqueNames, id)) {
@@ -4171,6 +4208,93 @@ namespace ts {
log("getCompletionsAtPosition: getCompletionEntriesFromSymbols: " + (new Date().getTime() - start));
return uniqueNames;
}
function getStringLiteralCompletionEntries(sourceFile: SourceFile, position: number) {
const node = findPrecedingToken(position, sourceFile);
if (!node || node.kind !== SyntaxKind.StringLiteral) {
return undefined;
}
const argumentInfo = SignatureHelp.getContainingArgumentInfo(node, position, sourceFile);
if (argumentInfo) {
// Get string literal completions from specialized signatures of the target
return getStringLiteralCompletionEntriesFromCallExpression(argumentInfo);
}
else if (isElementAccessExpression(node.parent) && node.parent.argumentExpression === node) {
// Get all names of properties on the expression
return getStringLiteralCompletionEntriesFromElementAccess(node.parent);
}
else {
// Otherwise, get the completions from the contextual type if one exists
return getStringLiteralCompletionEntriesFromContextualType(<StringLiteral>node);
}
}
function getStringLiteralCompletionEntriesFromCallExpression(argumentInfo: SignatureHelp.ArgumentListInfo) {
const typeChecker = program.getTypeChecker();
const candidates: Signature[] = [];
const entries: CompletionEntry[] = [];
typeChecker.getResolvedSignature(argumentInfo.invocation, candidates);
for (const candidate of candidates) {
if (candidate.parameters.length > argumentInfo.argumentIndex) {
const parameter = candidate.parameters[argumentInfo.argumentIndex];
addStringLiteralCompletionsFromType(typeChecker.getTypeAtLocation(parameter.valueDeclaration), entries);
}
}
if (entries.length) {
return { isMemberCompletion: false, isNewIdentifierLocation: true, entries };
}
return undefined;
}
function getStringLiteralCompletionEntriesFromElementAccess(node: ElementAccessExpression) {
const typeChecker = program.getTypeChecker();
const type = typeChecker.getTypeAtLocation(node.expression);
const entries: CompletionEntry[] = [];
if (type) {
getCompletionEntriesFromSymbols(type.getApparentProperties(), entries, node, /*performCharacterChecks*/false);
if (entries.length) {
return { isMemberCompletion: true, isNewIdentifierLocation: true, entries };
}
}
return undefined;
}
function getStringLiteralCompletionEntriesFromContextualType(node: StringLiteral) {
const typeChecker = program.getTypeChecker();
const type = typeChecker.getContextualType(node);
if (type) {
const entries: CompletionEntry[] = [];
addStringLiteralCompletionsFromType(type, entries);
if (entries.length) {
return { isMemberCompletion: false, isNewIdentifierLocation: false, entries };
}
}
return undefined;
}
function addStringLiteralCompletionsFromType(type: Type, result: CompletionEntry[]): void {
if (!type) {
return;
}
if (type.flags & TypeFlags.Union) {
forEach((<UnionType>type).types, t => addStringLiteralCompletionsFromType(t, result));
}
else {
if (type.flags & TypeFlags.StringLiteral) {
result.push({
name: (<StringLiteralType>type).text,
kindModifiers: ScriptElementKindModifier.none,
kind: ScriptElementKind.variableElement,
sortText: "0"
});
}
}
}
}
function getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails {
@@ -4335,7 +4459,7 @@ namespace ts {
// try get the call/construct signature from the type if it matches
let callExpression: CallExpression;
if (location.kind === SyntaxKind.CallExpression || location.kind === SyntaxKind.NewExpression) {
callExpression = <CallExpression> location;
callExpression = <CallExpression>location;
}
else if (isCallExpressionTarget(location) || isNewExpressionTarget(location)) {
callExpression = <CallExpression>location.parent;
+379 -376
View File
@@ -162,15 +162,16 @@ namespace ts.SignatureHelp {
// // Did not find matching token
// return null;
// }
const emptyArray: any[] = [];
const enum ArgumentListKind {
export const enum ArgumentListKind {
TypeArguments,
CallArguments,
TaggedTemplateArguments
}
interface ArgumentListInfo {
export interface ArgumentListInfo {
kind: ArgumentListKind;
invocation: CallLikeExpression;
argumentsSpan: TextSpan;
@@ -188,7 +189,8 @@ namespace ts.SignatureHelp {
return undefined;
}
const argumentInfo = getContainingArgumentInfo(startingToken);
const argumentInfo = getContainingArgumentInfo(startingToken, position, sourceFile);
cancellationToken.throwIfCancellationRequested();
// Semantic filtering of signature help
@@ -205,431 +207,432 @@ namespace ts.SignatureHelp {
// We didn't have any sig help items produced by the TS compiler. If this is a JS
// file, then see if we can figure out anything better.
if (isSourceFileJavaScript(sourceFile)) {
return createJavaScriptSignatureHelpItems(argumentInfo);
return createJavaScriptSignatureHelpItems(argumentInfo, program);
}
return undefined;
}
return createSignatureHelpItems(candidates, resolvedSignature, argumentInfo);
return createSignatureHelpItems(candidates, resolvedSignature, argumentInfo, typeChecker);
}
function createJavaScriptSignatureHelpItems(argumentInfo: ArgumentListInfo): SignatureHelpItems {
if (argumentInfo.invocation.kind !== SyntaxKind.CallExpression) {
return undefined;
}
function createJavaScriptSignatureHelpItems(argumentInfo: ArgumentListInfo, program: Program): SignatureHelpItems {
if (argumentInfo.invocation.kind !== SyntaxKind.CallExpression) {
return undefined;
}
// See if we can find some symbol with the call expression name that has call signatures.
const callExpression = <CallExpression>argumentInfo.invocation;
const expression = callExpression.expression;
const name = expression.kind === SyntaxKind.Identifier
? <Identifier> expression
: expression.kind === SyntaxKind.PropertyAccessExpression
? (<PropertyAccessExpression>expression).name
: undefined;
// See if we can find some symbol with the call expression name that has call signatures.
const callExpression = <CallExpression>argumentInfo.invocation;
const expression = callExpression.expression;
const name = expression.kind === SyntaxKind.Identifier
? <Identifier>expression
: expression.kind === SyntaxKind.PropertyAccessExpression
? (<PropertyAccessExpression>expression).name
: undefined;
if (!name || !name.text) {
return undefined;
}
if (!name || !name.text) {
return undefined;
}
const typeChecker = program.getTypeChecker();
for (const sourceFile of program.getSourceFiles()) {
const nameToDeclarations = sourceFile.getNamedDeclarations();
const declarations = getProperty(nameToDeclarations, name.text);
const typeChecker = program.getTypeChecker();
for (const sourceFile of program.getSourceFiles()) {
const nameToDeclarations = sourceFile.getNamedDeclarations();
const declarations = getProperty(nameToDeclarations, name.text);
if (declarations) {
for (const declaration of declarations) {
const symbol = declaration.symbol;
if (symbol) {
const type = typeChecker.getTypeOfSymbolAtLocation(symbol, declaration);
if (type) {
const callSignatures = type.getCallSignatures();
if (callSignatures && callSignatures.length) {
return createSignatureHelpItems(callSignatures, callSignatures[0], argumentInfo);
}
if (declarations) {
for (const declaration of declarations) {
const symbol = declaration.symbol;
if (symbol) {
const type = typeChecker.getTypeOfSymbolAtLocation(symbol, declaration);
if (type) {
const callSignatures = type.getCallSignatures();
if (callSignatures && callSignatures.length) {
return createSignatureHelpItems(callSignatures, callSignatures[0], argumentInfo, typeChecker);
}
}
}
}
}
}
}
/**
* Returns relevant information for the argument list and the current argument if we are
* in the argument of an invocation; returns undefined otherwise.
*/
function getImmediatelyContainingArgumentInfo(node: Node): ArgumentListInfo {
if (node.parent.kind === SyntaxKind.CallExpression || node.parent.kind === SyntaxKind.NewExpression) {
const callExpression = <CallExpression>node.parent;
// There are 3 cases to handle:
// 1. The token introduces a list, and should begin a sig help session
// 2. The token is either not associated with a list, or ends a list, so the session should end
// 3. The token is buried inside a list, and should give sig help
//
// The following are examples of each:
//
// Case 1:
// foo<#T, U>(#a, b) -> The token introduces a list, and should begin a sig help session
// Case 2:
// fo#o<T, U>#(a, b)# -> The token is either not associated with a list, or ends a list, so the session should end
// Case 3:
// foo<T#, U#>(a#, #b#) -> The token is buried inside a list, and should give sig help
// Find out if 'node' is an argument, a type argument, or neither
if (node.kind === SyntaxKind.LessThanToken ||
node.kind === SyntaxKind.OpenParenToken) {
// Find the list that starts right *after* the < or ( token.
// If the user has just opened a list, consider this item 0.
const list = getChildListThatStartsWithOpenerToken(callExpression, node, sourceFile);
const isTypeArgList = callExpression.typeArguments && callExpression.typeArguments.pos === list.pos;
Debug.assert(list !== undefined);
return {
kind: isTypeArgList ? ArgumentListKind.TypeArguments : ArgumentListKind.CallArguments,
invocation: callExpression,
argumentsSpan: getApplicableSpanForArguments(list),
argumentIndex: 0,
argumentCount: getArgumentCount(list)
};
}
// findListItemInfo can return undefined if we are not in parent's argument list
// or type argument list. This includes cases where the cursor is:
// - To the right of the closing paren, non-substitution template, or template tail.
// - Between the type arguments and the arguments (greater than token)
// - On the target of the call (parent.func)
// - On the 'new' keyword in a 'new' expression
const listItemInfo = findListItemInfo(node);
if (listItemInfo) {
const list = listItemInfo.list;
const isTypeArgList = callExpression.typeArguments && callExpression.typeArguments.pos === list.pos;
const argumentIndex = getArgumentIndex(list, node);
const argumentCount = getArgumentCount(list);
Debug.assert(argumentIndex === 0 || argumentIndex < argumentCount,
`argumentCount < argumentIndex, ${argumentCount} < ${argumentIndex}`);
return {
kind: isTypeArgList ? ArgumentListKind.TypeArguments : ArgumentListKind.CallArguments,
invocation: callExpression,
argumentsSpan: getApplicableSpanForArguments(list),
argumentIndex: argumentIndex,
argumentCount: argumentCount
};
}
}
else if (node.kind === SyntaxKind.NoSubstitutionTemplateLiteral && node.parent.kind === SyntaxKind.TaggedTemplateExpression) {
// Check if we're actually inside the template;
// otherwise we'll fall out and return undefined.
if (isInsideTemplateLiteral(<LiteralExpression>node, position)) {
return getArgumentListInfoForTemplate(<TaggedTemplateExpression>node.parent, /*argumentIndex*/ 0);
}
}
else if (node.kind === SyntaxKind.TemplateHead && node.parent.parent.kind === SyntaxKind.TaggedTemplateExpression) {
const templateExpression = <TemplateExpression>node.parent;
const tagExpression = <TaggedTemplateExpression>templateExpression.parent;
Debug.assert(templateExpression.kind === SyntaxKind.TemplateExpression);
const argumentIndex = isInsideTemplateLiteral(<LiteralExpression>node, position) ? 0 : 1;
return getArgumentListInfoForTemplate(tagExpression, argumentIndex);
}
else if (node.parent.kind === SyntaxKind.TemplateSpan && node.parent.parent.parent.kind === SyntaxKind.TaggedTemplateExpression) {
const templateSpan = <TemplateSpan>node.parent;
const templateExpression = <TemplateExpression>templateSpan.parent;
const tagExpression = <TaggedTemplateExpression>templateExpression.parent;
Debug.assert(templateExpression.kind === SyntaxKind.TemplateExpression);
// If we're just after a template tail, don't show signature help.
if (node.kind === SyntaxKind.TemplateTail && !isInsideTemplateLiteral(<LiteralExpression>node, position)) {
return undefined;
}
const spanIndex = templateExpression.templateSpans.indexOf(templateSpan);
const argumentIndex = getArgumentIndexForTemplatePiece(spanIndex, node);
return getArgumentListInfoForTemplate(tagExpression, argumentIndex);
}
return undefined;
}
function getArgumentIndex(argumentsList: Node, node: Node) {
// The list we got back can include commas. In the presence of errors it may
// also just have nodes without commas. For example "Foo(a b c)" will have 3
// args without commas. We want to find what index we're at. So we count
// forward until we hit ourselves, only incrementing the index if it isn't a
// comma.
/**
* Returns relevant information for the argument list and the current argument if we are
* in the argument of an invocation; returns undefined otherwise.
*/
function getImmediatelyContainingArgumentInfo(node: Node, position: number, sourceFile: SourceFile): ArgumentListInfo {
if (node.parent.kind === SyntaxKind.CallExpression || node.parent.kind === SyntaxKind.NewExpression) {
const callExpression = <CallExpression>node.parent;
// There are 3 cases to handle:
// 1. The token introduces a list, and should begin a sig help session
// 2. The token is either not associated with a list, or ends a list, so the session should end
// 3. The token is buried inside a list, and should give sig help
//
// Note: the subtlety around trailing commas (in getArgumentCount) does not apply
// here. That's because we're only walking forward until we hit the node we're
// on. In that case, even if we're after the trailing comma, we'll still see
// that trailing comma in the list, and we'll have generated the appropriate
// arg index.
let argumentIndex = 0;
const listChildren = argumentsList.getChildren();
for (const child of listChildren) {
if (child === node) {
break;
}
if (child.kind !== SyntaxKind.CommaToken) {
argumentIndex++;
}
// The following are examples of each:
//
// Case 1:
// foo<#T, U>(#a, b) -> The token introduces a list, and should begin a sig help session
// Case 2:
// fo#o<T, U>#(a, b)# -> The token is either not associated with a list, or ends a list, so the session should end
// Case 3:
// foo<T#, U#>(a#, #b#) -> The token is buried inside a list, and should give sig help
// Find out if 'node' is an argument, a type argument, or neither
if (node.kind === SyntaxKind.LessThanToken ||
node.kind === SyntaxKind.OpenParenToken) {
// Find the list that starts right *after* the < or ( token.
// If the user has just opened a list, consider this item 0.
const list = getChildListThatStartsWithOpenerToken(callExpression, node, sourceFile);
const isTypeArgList = callExpression.typeArguments && callExpression.typeArguments.pos === list.pos;
Debug.assert(list !== undefined);
return {
kind: isTypeArgList ? ArgumentListKind.TypeArguments : ArgumentListKind.CallArguments,
invocation: callExpression,
argumentsSpan: getApplicableSpanForArguments(list, sourceFile),
argumentIndex: 0,
argumentCount: getArgumentCount(list)
};
}
return argumentIndex;
}
// findListItemInfo can return undefined if we are not in parent's argument list
// or type argument list. This includes cases where the cursor is:
// - To the right of the closing paren, non-substitution template, or template tail.
// - Between the type arguments and the arguments (greater than token)
// - On the target of the call (parent.func)
// - On the 'new' keyword in a 'new' expression
const listItemInfo = findListItemInfo(node);
if (listItemInfo) {
const list = listItemInfo.list;
const isTypeArgList = callExpression.typeArguments && callExpression.typeArguments.pos === list.pos;
function getArgumentCount(argumentsList: Node) {
// The argument count for a list is normally the number of non-comma children it has.
// For example, if you have "Foo(a,b)" then there will be three children of the arg
// list 'a' '<comma>' 'b'. So, in this case the arg count will be 2. However, there
// is a small subtlety. If you have "Foo(a,)", then the child list will just have
// 'a' '<comma>'. So, in the case where the last child is a comma, we increase the
// arg count by one to compensate.
//
// Note: this subtlety only applies to the last comma. If you had "Foo(a,," then
// we'll have: 'a' '<comma>' '<missing>'
// That will give us 2 non-commas. We then add one for the last comma, givin us an
// arg count of 3.
const listChildren = argumentsList.getChildren();
const argumentIndex = getArgumentIndex(list, node);
const argumentCount = getArgumentCount(list);
let argumentCount = countWhere(listChildren, arg => arg.kind !== SyntaxKind.CommaToken);
if (listChildren.length > 0 && lastOrUndefined(listChildren).kind === SyntaxKind.CommaToken) {
argumentCount++;
}
Debug.assert(argumentIndex === 0 || argumentIndex < argumentCount,
`argumentCount < argumentIndex, ${argumentCount} < ${argumentIndex}`);
return argumentCount;
}
// spanIndex is either the index for a given template span.
// This does not give appropriate results for a NoSubstitutionTemplateLiteral
function getArgumentIndexForTemplatePiece(spanIndex: number, node: Node): number {
// Because the TemplateStringsArray is the first argument, we have to offset each substitution expression by 1.
// There are three cases we can encounter:
// 1. We are precisely in the template literal (argIndex = 0).
// 2. We are in or to the right of the substitution expression (argIndex = spanIndex + 1).
// 3. We are directly to the right of the template literal, but because we look for the token on the left,
// not enough to put us in the substitution expression; we should consider ourselves part of
// the *next* span's expression by offsetting the index (argIndex = (spanIndex + 1) + 1).
//
// Example: f `# abcd $#{# 1 + 1# }# efghi ${ #"#hello"# } # `
// ^ ^ ^ ^ ^ ^ ^ ^ ^
// Case: 1 1 3 2 1 3 2 2 1
Debug.assert(position >= node.getStart(), "Assumed 'position' could not occur before node.");
if (isTemplateLiteralKind(node.kind)) {
if (isInsideTemplateLiteral(<LiteralExpression>node, position)) {
return 0;
}
return spanIndex + 2;
}
return spanIndex + 1;
}
function getArgumentListInfoForTemplate(tagExpression: TaggedTemplateExpression, argumentIndex: number): ArgumentListInfo {
// argumentCount is either 1 or (numSpans + 1) to account for the template strings array argument.
const argumentCount = tagExpression.template.kind === SyntaxKind.NoSubstitutionTemplateLiteral
? 1
: (<TemplateExpression>tagExpression.template).templateSpans.length + 1;
Debug.assert(argumentIndex === 0 || argumentIndex < argumentCount, `argumentCount < argumentIndex, ${argumentCount} < ${argumentIndex}`);
return {
kind: ArgumentListKind.TaggedTemplateArguments,
invocation: tagExpression,
argumentsSpan: getApplicableSpanForTaggedTemplate(tagExpression),
argumentIndex: argumentIndex,
argumentCount: argumentCount
};
}
function getApplicableSpanForArguments(argumentsList: Node): TextSpan {
// We use full start and skip trivia on the end because we want to include trivia on
// both sides. For example,
//
// foo( /*comment */ a, b, c /*comment*/ )
// | |
//
// The applicable span is from the first bar to the second bar (inclusive,
// but not including parentheses)
const applicableSpanStart = argumentsList.getFullStart();
const applicableSpanEnd = skipTrivia(sourceFile.text, argumentsList.getEnd(), /*stopAfterLineBreak*/ false);
return createTextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart);
}
function getApplicableSpanForTaggedTemplate(taggedTemplate: TaggedTemplateExpression): TextSpan {
const template = taggedTemplate.template;
const applicableSpanStart = template.getStart();
let applicableSpanEnd = template.getEnd();
// We need to adjust the end position for the case where the template does not have a tail.
// Otherwise, we will not show signature help past the expression.
// For example,
//
// ` ${ 1 + 1 foo(10)
// | |
//
// This is because a Missing node has no width. However, what we actually want is to include trivia
// leading up to the next token in case the user is about to type in a TemplateMiddle or TemplateTail.
if (template.kind === SyntaxKind.TemplateExpression) {
const lastSpan = lastOrUndefined((<TemplateExpression>template).templateSpans);
if (lastSpan.literal.getFullWidth() === 0) {
applicableSpanEnd = skipTrivia(sourceFile.text, applicableSpanEnd, /*stopAfterLineBreak*/ false);
}
}
return createTextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart);
}
function getContainingArgumentInfo(node: Node): ArgumentListInfo {
for (let n = node; n.kind !== SyntaxKind.SourceFile; n = n.parent) {
if (isFunctionBlock(n)) {
return undefined;
}
// If the node is not a subspan of its parent, this is a big problem.
// There have been crashes that might be caused by this violation.
if (n.pos < n.parent.pos || n.end > n.parent.end) {
Debug.fail("Node of kind " + n.kind + " is not a subspan of its parent of kind " + n.parent.kind);
}
const argumentInfo = getImmediatelyContainingArgumentInfo(n);
if (argumentInfo) {
return argumentInfo;
}
// TODO: Handle generic call with incomplete syntax
return {
kind: isTypeArgList ? ArgumentListKind.TypeArguments : ArgumentListKind.CallArguments,
invocation: callExpression,
argumentsSpan: getApplicableSpanForArguments(list, sourceFile),
argumentIndex: argumentIndex,
argumentCount: argumentCount
};
}
return undefined;
}
function getChildListThatStartsWithOpenerToken(parent: Node, openerToken: Node, sourceFile: SourceFile): Node {
const children = parent.getChildren(sourceFile);
const indexOfOpenerToken = children.indexOf(openerToken);
Debug.assert(indexOfOpenerToken >= 0 && children.length > indexOfOpenerToken + 1);
return children[indexOfOpenerToken + 1];
else if (node.kind === SyntaxKind.NoSubstitutionTemplateLiteral && node.parent.kind === SyntaxKind.TaggedTemplateExpression) {
// Check if we're actually inside the template;
// otherwise we'll fall out and return undefined.
if (isInsideTemplateLiteral(<LiteralExpression>node, position)) {
return getArgumentListInfoForTemplate(<TaggedTemplateExpression>node.parent, /*argumentIndex*/ 0, sourceFile);
}
}
else if (node.kind === SyntaxKind.TemplateHead && node.parent.parent.kind === SyntaxKind.TaggedTemplateExpression) {
const templateExpression = <TemplateExpression>node.parent;
const tagExpression = <TaggedTemplateExpression>templateExpression.parent;
Debug.assert(templateExpression.kind === SyntaxKind.TemplateExpression);
/**
* The selectedItemIndex could be negative for several reasons.
* 1. There are too many arguments for all of the overloads
* 2. None of the overloads were type compatible
* The solution here is to try to pick the best overload by picking
* either the first one that has an appropriate number of parameters,
* or the one with the most parameters.
*/
function selectBestInvalidOverloadIndex(candidates: Signature[], argumentCount: number): number {
let maxParamsSignatureIndex = -1;
let maxParams = -1;
for (let i = 0; i < candidates.length; i++) {
const candidate = candidates[i];
const argumentIndex = isInsideTemplateLiteral(<LiteralExpression>node, position) ? 0 : 1;
if (candidate.hasRestParameter || candidate.parameters.length >= argumentCount) {
return i;
}
return getArgumentListInfoForTemplate(tagExpression, argumentIndex, sourceFile);
}
else if (node.parent.kind === SyntaxKind.TemplateSpan && node.parent.parent.parent.kind === SyntaxKind.TaggedTemplateExpression) {
const templateSpan = <TemplateSpan>node.parent;
const templateExpression = <TemplateExpression>templateSpan.parent;
const tagExpression = <TaggedTemplateExpression>templateExpression.parent;
Debug.assert(templateExpression.kind === SyntaxKind.TemplateExpression);
if (candidate.parameters.length > maxParams) {
maxParams = candidate.parameters.length;
maxParamsSignatureIndex = i;
}
// If we're just after a template tail, don't show signature help.
if (node.kind === SyntaxKind.TemplateTail && !isInsideTemplateLiteral(<LiteralExpression>node, position)) {
return undefined;
}
return maxParamsSignatureIndex;
const spanIndex = templateExpression.templateSpans.indexOf(templateSpan);
const argumentIndex = getArgumentIndexForTemplatePiece(spanIndex, node, position);
return getArgumentListInfoForTemplate(tagExpression, argumentIndex, sourceFile);
}
function createSignatureHelpItems(candidates: Signature[], bestSignature: Signature, argumentListInfo: ArgumentListInfo): SignatureHelpItems {
const applicableSpan = argumentListInfo.argumentsSpan;
const isTypeParameterList = argumentListInfo.kind === ArgumentListKind.TypeArguments;
return undefined;
}
const invocation = argumentListInfo.invocation;
const callTarget = getInvokedExpression(invocation);
const callTargetSymbol = typeChecker.getSymbolAtLocation(callTarget);
const callTargetDisplayParts = callTargetSymbol && symbolToDisplayParts(typeChecker, callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined);
const items: SignatureHelpItem[] = map(candidates, candidateSignature => {
let signatureHelpParameters: SignatureHelpParameter[];
const prefixDisplayParts: SymbolDisplayPart[] = [];
const suffixDisplayParts: SymbolDisplayPart[] = [];
function getArgumentIndex(argumentsList: Node, node: Node) {
// The list we got back can include commas. In the presence of errors it may
// also just have nodes without commas. For example "Foo(a b c)" will have 3
// args without commas. We want to find what index we're at. So we count
// forward until we hit ourselves, only incrementing the index if it isn't a
// comma.
//
// Note: the subtlety around trailing commas (in getArgumentCount) does not apply
// here. That's because we're only walking forward until we hit the node we're
// on. In that case, even if we're after the trailing comma, we'll still see
// that trailing comma in the list, and we'll have generated the appropriate
// arg index.
let argumentIndex = 0;
const listChildren = argumentsList.getChildren();
for (const child of listChildren) {
if (child === node) {
break;
}
if (child.kind !== SyntaxKind.CommaToken) {
argumentIndex++;
}
}
if (callTargetDisplayParts) {
addRange(prefixDisplayParts, callTargetDisplayParts);
}
return argumentIndex;
}
if (isTypeParameterList) {
prefixDisplayParts.push(punctuationPart(SyntaxKind.LessThanToken));
const typeParameters = candidateSignature.typeParameters;
signatureHelpParameters = typeParameters && typeParameters.length > 0 ? map(typeParameters, createSignatureHelpParameterForTypeParameter) : emptyArray;
suffixDisplayParts.push(punctuationPart(SyntaxKind.GreaterThanToken));
const parameterParts = mapToDisplayParts(writer =>
typeChecker.getSymbolDisplayBuilder().buildDisplayForParametersAndDelimiters(candidateSignature.thisType, candidateSignature.parameters, writer, invocation));
addRange(suffixDisplayParts, parameterParts);
}
else {
const typeParameterParts = mapToDisplayParts(writer =>
typeChecker.getSymbolDisplayBuilder().buildDisplayForTypeParametersAndDelimiters(candidateSignature.typeParameters, writer, invocation));
addRange(prefixDisplayParts, typeParameterParts);
prefixDisplayParts.push(punctuationPart(SyntaxKind.OpenParenToken));
function getArgumentCount(argumentsList: Node) {
// The argument count for a list is normally the number of non-comma children it has.
// For example, if you have "Foo(a,b)" then there will be three children of the arg
// list 'a' '<comma>' 'b'. So, in this case the arg count will be 2. However, there
// is a small subtlety. If you have "Foo(a,)", then the child list will just have
// 'a' '<comma>'. So, in the case where the last child is a comma, we increase the
// arg count by one to compensate.
//
// Note: this subtlety only applies to the last comma. If you had "Foo(a,," then
// we'll have: 'a' '<comma>' '<missing>'
// That will give us 2 non-commas. We then add one for the last comma, givin us an
// arg count of 3.
const listChildren = argumentsList.getChildren();
const parameters = candidateSignature.parameters;
signatureHelpParameters = parameters.length > 0 ? map(parameters, createSignatureHelpParameterForParameter) : emptyArray;
suffixDisplayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
}
let argumentCount = countWhere(listChildren, arg => arg.kind !== SyntaxKind.CommaToken);
if (listChildren.length > 0 && lastOrUndefined(listChildren).kind === SyntaxKind.CommaToken) {
argumentCount++;
}
const returnTypeParts = mapToDisplayParts(writer =>
typeChecker.getSymbolDisplayBuilder().buildReturnTypeDisplay(candidateSignature, writer, invocation));
addRange(suffixDisplayParts, returnTypeParts);
return argumentCount;
}
return {
isVariadic: candidateSignature.hasRestParameter,
prefixDisplayParts,
suffixDisplayParts,
separatorDisplayParts: [punctuationPart(SyntaxKind.CommaToken), spacePart()],
parameters: signatureHelpParameters,
documentation: candidateSignature.getDocumentationComment()
};
});
// spanIndex is either the index for a given template span.
// This does not give appropriate results for a NoSubstitutionTemplateLiteral
function getArgumentIndexForTemplatePiece(spanIndex: number, node: Node, position: number): number {
// Because the TemplateStringsArray is the first argument, we have to offset each substitution expression by 1.
// There are three cases we can encounter:
// 1. We are precisely in the template literal (argIndex = 0).
// 2. We are in or to the right of the substitution expression (argIndex = spanIndex + 1).
// 3. We are directly to the right of the template literal, but because we look for the token on the left,
// not enough to put us in the substitution expression; we should consider ourselves part of
// the *next* span's expression by offsetting the index (argIndex = (spanIndex + 1) + 1).
//
// Example: f `# abcd $#{# 1 + 1# }# efghi ${ #"#hello"# } # `
// ^ ^ ^ ^ ^ ^ ^ ^ ^
// Case: 1 1 3 2 1 3 2 2 1
Debug.assert(position >= node.getStart(), "Assumed 'position' could not occur before node.");
if (isTemplateLiteralKind(node.kind)) {
if (isInsideTemplateLiteral(<LiteralExpression>node, position)) {
return 0;
}
return spanIndex + 2;
}
return spanIndex + 1;
}
const argumentIndex = argumentListInfo.argumentIndex;
function getArgumentListInfoForTemplate(tagExpression: TaggedTemplateExpression, argumentIndex: number, sourceFile: SourceFile): ArgumentListInfo {
// argumentCount is either 1 or (numSpans + 1) to account for the template strings array argument.
const argumentCount = tagExpression.template.kind === SyntaxKind.NoSubstitutionTemplateLiteral
? 1
: (<TemplateExpression>tagExpression.template).templateSpans.length + 1;
// argumentCount is the *apparent* number of arguments.
const argumentCount = argumentListInfo.argumentCount;
Debug.assert(argumentIndex === 0 || argumentIndex < argumentCount, `argumentCount < argumentIndex, ${argumentCount} < ${argumentIndex}`);
let selectedItemIndex = candidates.indexOf(bestSignature);
if (selectedItemIndex < 0) {
selectedItemIndex = selectBestInvalidOverloadIndex(candidates, argumentCount);
return {
kind: ArgumentListKind.TaggedTemplateArguments,
invocation: tagExpression,
argumentsSpan: getApplicableSpanForTaggedTemplate(tagExpression, sourceFile),
argumentIndex: argumentIndex,
argumentCount: argumentCount
};
}
function getApplicableSpanForArguments(argumentsList: Node, sourceFile: SourceFile): TextSpan {
// We use full start and skip trivia on the end because we want to include trivia on
// both sides. For example,
//
// foo( /*comment */ a, b, c /*comment*/ )
// | |
//
// The applicable span is from the first bar to the second bar (inclusive,
// but not including parentheses)
const applicableSpanStart = argumentsList.getFullStart();
const applicableSpanEnd = skipTrivia(sourceFile.text, argumentsList.getEnd(), /*stopAfterLineBreak*/ false);
return createTextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart);
}
function getApplicableSpanForTaggedTemplate(taggedTemplate: TaggedTemplateExpression, sourceFile: SourceFile): TextSpan {
const template = taggedTemplate.template;
const applicableSpanStart = template.getStart();
let applicableSpanEnd = template.getEnd();
// We need to adjust the end position for the case where the template does not have a tail.
// Otherwise, we will not show signature help past the expression.
// For example,
//
// ` ${ 1 + 1 foo(10)
// | |
//
// This is because a Missing node has no width. However, what we actually want is to include trivia
// leading up to the next token in case the user is about to type in a TemplateMiddle or TemplateTail.
if (template.kind === SyntaxKind.TemplateExpression) {
const lastSpan = lastOrUndefined((<TemplateExpression>template).templateSpans);
if (lastSpan.literal.getFullWidth() === 0) {
applicableSpanEnd = skipTrivia(sourceFile.text, applicableSpanEnd, /*stopAfterLineBreak*/ false);
}
}
return createTextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart);
}
export function getContainingArgumentInfo(node: Node, position: number, sourceFile: SourceFile): ArgumentListInfo {
for (let n = node; n.kind !== SyntaxKind.SourceFile; n = n.parent) {
if (isFunctionBlock(n)) {
return undefined;
}
Debug.assert(argumentIndex === 0 || argumentIndex < argumentCount, `argumentCount < argumentIndex, ${argumentCount} < ${argumentIndex}`);
// If the node is not a subspan of its parent, this is a big problem.
// There have been crashes that might be caused by this violation.
if (n.pos < n.parent.pos || n.end > n.parent.end) {
Debug.fail("Node of kind " + n.kind + " is not a subspan of its parent of kind " + n.parent.kind);
}
const argumentInfo = getImmediatelyContainingArgumentInfo(n, position, sourceFile);
if (argumentInfo) {
return argumentInfo;
}
// TODO: Handle generic call with incomplete syntax
}
return undefined;
}
function getChildListThatStartsWithOpenerToken(parent: Node, openerToken: Node, sourceFile: SourceFile): Node {
const children = parent.getChildren(sourceFile);
const indexOfOpenerToken = children.indexOf(openerToken);
Debug.assert(indexOfOpenerToken >= 0 && children.length > indexOfOpenerToken + 1);
return children[indexOfOpenerToken + 1];
}
/**
* The selectedItemIndex could be negative for several reasons.
* 1. There are too many arguments for all of the overloads
* 2. None of the overloads were type compatible
* The solution here is to try to pick the best overload by picking
* either the first one that has an appropriate number of parameters,
* or the one with the most parameters.
*/
function selectBestInvalidOverloadIndex(candidates: Signature[], argumentCount: number): number {
let maxParamsSignatureIndex = -1;
let maxParams = -1;
for (let i = 0; i < candidates.length; i++) {
const candidate = candidates[i];
if (candidate.hasRestParameter || candidate.parameters.length >= argumentCount) {
return i;
}
if (candidate.parameters.length > maxParams) {
maxParams = candidate.parameters.length;
maxParamsSignatureIndex = i;
}
}
return maxParamsSignatureIndex;
}
function createSignatureHelpItems(candidates: Signature[], bestSignature: Signature, argumentListInfo: ArgumentListInfo, typeChecker: TypeChecker): SignatureHelpItems {
const applicableSpan = argumentListInfo.argumentsSpan;
const isTypeParameterList = argumentListInfo.kind === ArgumentListKind.TypeArguments;
const invocation = argumentListInfo.invocation;
const callTarget = getInvokedExpression(invocation);
const callTargetSymbol = typeChecker.getSymbolAtLocation(callTarget);
const callTargetDisplayParts = callTargetSymbol && symbolToDisplayParts(typeChecker, callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined);
const items: SignatureHelpItem[] = map(candidates, candidateSignature => {
let signatureHelpParameters: SignatureHelpParameter[];
const prefixDisplayParts: SymbolDisplayPart[] = [];
const suffixDisplayParts: SymbolDisplayPart[] = [];
if (callTargetDisplayParts) {
addRange(prefixDisplayParts, callTargetDisplayParts);
}
if (isTypeParameterList) {
prefixDisplayParts.push(punctuationPart(SyntaxKind.LessThanToken));
const typeParameters = candidateSignature.typeParameters;
signatureHelpParameters = typeParameters && typeParameters.length > 0 ? map(typeParameters, createSignatureHelpParameterForTypeParameter) : emptyArray;
suffixDisplayParts.push(punctuationPart(SyntaxKind.GreaterThanToken));
const parameterParts = mapToDisplayParts(writer =>
typeChecker.getSymbolDisplayBuilder().buildDisplayForParametersAndDelimiters(candidateSignature.thisType, candidateSignature.parameters, writer, invocation));
addRange(suffixDisplayParts, parameterParts);
}
else {
const typeParameterParts = mapToDisplayParts(writer =>
typeChecker.getSymbolDisplayBuilder().buildDisplayForTypeParametersAndDelimiters(candidateSignature.typeParameters, writer, invocation));
addRange(prefixDisplayParts, typeParameterParts);
prefixDisplayParts.push(punctuationPart(SyntaxKind.OpenParenToken));
const parameters = candidateSignature.parameters;
signatureHelpParameters = parameters.length > 0 ? map(parameters, createSignatureHelpParameterForParameter) : emptyArray;
suffixDisplayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
}
const returnTypeParts = mapToDisplayParts(writer =>
typeChecker.getSymbolDisplayBuilder().buildReturnTypeDisplay(candidateSignature, writer, invocation));
addRange(suffixDisplayParts, returnTypeParts);
return {
items,
applicableSpan,
selectedItemIndex,
argumentIndex,
argumentCount
isVariadic: candidateSignature.hasRestParameter,
prefixDisplayParts,
suffixDisplayParts,
separatorDisplayParts: [punctuationPart(SyntaxKind.CommaToken), spacePart()],
parameters: signatureHelpParameters,
documentation: candidateSignature.getDocumentationComment()
};
});
function createSignatureHelpParameterForParameter(parameter: Symbol): SignatureHelpParameter {
const displayParts = mapToDisplayParts(writer =>
typeChecker.getSymbolDisplayBuilder().buildParameterDisplay(parameter, writer, invocation));
const argumentIndex = argumentListInfo.argumentIndex;
return {
name: parameter.name,
documentation: parameter.getDocumentationComment(),
displayParts,
isOptional: typeChecker.isOptionalParameter(<ParameterDeclaration>parameter.valueDeclaration)
};
}
// argumentCount is the *apparent* number of arguments.
const argumentCount = argumentListInfo.argumentCount;
function createSignatureHelpParameterForTypeParameter(typeParameter: TypeParameter): SignatureHelpParameter {
const displayParts = mapToDisplayParts(writer =>
typeChecker.getSymbolDisplayBuilder().buildTypeParameterDisplay(typeParameter, writer, invocation));
let selectedItemIndex = candidates.indexOf(bestSignature);
if (selectedItemIndex < 0) {
selectedItemIndex = selectBestInvalidOverloadIndex(candidates, argumentCount);
}
return {
name: typeParameter.symbol.name,
documentation: emptyArray,
displayParts,
isOptional: false
};
}
Debug.assert(argumentIndex === 0 || argumentIndex < argumentCount, `argumentCount < argumentIndex, ${argumentCount} < ${argumentIndex}`);
return {
items,
applicableSpan,
selectedItemIndex,
argumentIndex,
argumentCount
};
function createSignatureHelpParameterForParameter(parameter: Symbol): SignatureHelpParameter {
const displayParts = mapToDisplayParts(writer =>
typeChecker.getSymbolDisplayBuilder().buildParameterDisplay(parameter, writer, invocation));
return {
name: parameter.name,
documentation: parameter.getDocumentationComment(),
displayParts,
isOptional: typeChecker.isOptionalParameter(<ParameterDeclaration>parameter.valueDeclaration)
};
}
function createSignatureHelpParameterForTypeParameter(typeParameter: TypeParameter): SignatureHelpParameter {
const displayParts = mapToDisplayParts(writer =>
typeChecker.getSymbolDisplayBuilder().buildTypeParameterDisplay(typeParameter, writer, invocation));
return {
name: typeParameter.symbol.name,
documentation: emptyArray,
displayParts,
isOptional: false
};
}
}
}
+21 -3
View File
@@ -426,9 +426,27 @@ namespace ts {
}
}
export function isInString(sourceFile: SourceFile, position: number) {
const token = getTokenAtPosition(sourceFile, position);
return token && (token.kind === SyntaxKind.StringLiteral || token.kind === SyntaxKind.StringLiteralType) && position > token.getStart(sourceFile);
export function isInString(sourceFile: SourceFile, position: number): boolean {
const previousToken = findPrecedingToken(position, sourceFile);
if (previousToken &&
(previousToken.kind === SyntaxKind.StringLiteral || previousToken.kind === SyntaxKind.StringLiteralType)) {
const start = previousToken.getStart();
const end = previousToken.getEnd();
// To be "in" one of these literals, the position has to be:
// 1. entirely within the token text.
// 2. at the end position of an unterminated token.
// 3. at the end of a regular expression (due to trailing flags like '/foo/g').
if (start < position && position < end) {
return true;
}
if (position === end) {
return !!(<LiteralExpression>previousToken).isUnterminated;
}
}
return false;
}
export function isInComment(sourceFile: SourceFile, position: number) {
@@ -0,0 +1,44 @@
//// [tests/cases/conformance/ambient/ambientDeclarationsPatterns.ts] ////
//// [declarations.d.ts]
declare module "foo*baz" {
export function foo(s: string): void;
}
// Augmentations still work
declare module "foo*baz" {
export const baz: string;
}
// Longest prefix wins
declare module "foos*" {
export const foos: string;
}
declare module "*!text" {
const x: string;
export default x;
}
//// [user.ts]
///<reference path="declarations.d.ts" />
import {foo, baz} from "foobarbaz";
foo(baz);
import {foos} from "foosball";
foo(foos);
// Works with relative file name
import fileText from "./file!text";
foo(fileText);
//// [user.js]
"use strict";
///<reference path="declarations.d.ts" />
var foobarbaz_1 = require("foobarbaz");
foobarbaz_1.foo(foobarbaz_1.baz);
var foosball_1 = require("foosball");
foobarbaz_1.foo(foosball_1.foos);
// Works with relative file name
var file_text_1 = require("./file!text");
foobarbaz_1.foo(file_text_1["default"]);
@@ -0,0 +1,51 @@
=== tests/cases/conformance/ambient/user.ts ===
///<reference path="declarations.d.ts" />
import {foo, baz} from "foobarbaz";
>foo : Symbol(foo, Decl(user.ts, 1, 8))
>baz : Symbol(baz, Decl(user.ts, 1, 12))
foo(baz);
>foo : Symbol(foo, Decl(user.ts, 1, 8))
>baz : Symbol(baz, Decl(user.ts, 1, 12))
import {foos} from "foosball";
>foos : Symbol(foos, Decl(user.ts, 4, 8))
foo(foos);
>foo : Symbol(foo, Decl(user.ts, 1, 8))
>foos : Symbol(foos, Decl(user.ts, 4, 8))
// Works with relative file name
import fileText from "./file!text";
>fileText : Symbol(fileText, Decl(user.ts, 8, 6))
foo(fileText);
>foo : Symbol(foo, Decl(user.ts, 1, 8))
>fileText : Symbol(fileText, Decl(user.ts, 8, 6))
=== tests/cases/conformance/ambient/declarations.d.ts ===
declare module "foo*baz" {
export function foo(s: string): void;
>foo : Symbol(foo, Decl(declarations.d.ts, 0, 26))
>s : Symbol(s, Decl(declarations.d.ts, 1, 24))
}
// Augmentations still work
declare module "foo*baz" {
export const baz: string;
>baz : Symbol(baz, Decl(declarations.d.ts, 5, 16))
}
// Longest prefix wins
declare module "foos*" {
export const foos: string;
>foos : Symbol(foos, Decl(declarations.d.ts, 10, 16))
}
declare module "*!text" {
const x: string;
>x : Symbol(x, Decl(declarations.d.ts, 14, 9))
export default x;
>x : Symbol(x, Decl(declarations.d.ts, 14, 9))
}
@@ -0,0 +1,54 @@
=== tests/cases/conformance/ambient/user.ts ===
///<reference path="declarations.d.ts" />
import {foo, baz} from "foobarbaz";
>foo : (s: string) => void
>baz : string
foo(baz);
>foo(baz) : void
>foo : (s: string) => void
>baz : string
import {foos} from "foosball";
>foos : string
foo(foos);
>foo(foos) : void
>foo : (s: string) => void
>foos : string
// Works with relative file name
import fileText from "./file!text";
>fileText : string
foo(fileText);
>foo(fileText) : void
>foo : (s: string) => void
>fileText : string
=== tests/cases/conformance/ambient/declarations.d.ts ===
declare module "foo*baz" {
export function foo(s: string): void;
>foo : (s: string) => void
>s : string
}
// Augmentations still work
declare module "foo*baz" {
export const baz: string;
>baz : string
}
// Longest prefix wins
declare module "foos*" {
export const foos: string;
>foos : string
}
declare module "*!text" {
const x: string;
>x : string
export default x;
>x : string
}
@@ -0,0 +1,8 @@
tests/cases/conformance/ambient/ambientDeclarationsPatterns_tooManyAsterisks.ts(1,16): error TS5061: Pattern 'too*many*asterisks' can have at most one '*' character
==== tests/cases/conformance/ambient/ambientDeclarationsPatterns_tooManyAsterisks.ts (1 errors) ====
declare module "too*many*asterisks" { }
~~~~~~~~~~~~~~~~~~~~
!!! error TS5061: Pattern 'too*many*asterisks' can have at most one '*' character
@@ -0,0 +1,5 @@
//// [ambientDeclarationsPatterns_tooManyAsterisks.ts]
declare module "too*many*asterisks" { }
//// [ambientDeclarationsPatterns_tooManyAsterisks.js]
@@ -0,0 +1,33 @@
//// [asyncFunctionReturnType.ts]
async function fAsync() {
// Without explicit type annotation, this is just an array.
return [1, true];
}
async function fAsyncExplicit(): Promise<[number, boolean]> {
// This is contextually typed as a tuple.
return [1, true];
}
//// [asyncFunctionReturnType.js]
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments)).next());
});
};
function fAsync() {
return __awaiter(this, void 0, void 0, function* () {
// Without explicit type annotation, this is just an array.
return [1, true];
});
}
function fAsyncExplicit() {
return __awaiter(this, void 0, void 0, function* () {
// This is contextually typed as a tuple.
return [1, true];
});
}
@@ -0,0 +1,16 @@
=== tests/cases/compiler/asyncFunctionReturnType.ts ===
async function fAsync() {
>fAsync : Symbol(fAsync, Decl(asyncFunctionReturnType.ts, 0, 0))
// Without explicit type annotation, this is just an array.
return [1, true];
}
async function fAsyncExplicit(): Promise<[number, boolean]> {
>fAsyncExplicit : Symbol(fAsyncExplicit, Decl(asyncFunctionReturnType.ts, 3, 1))
>Promise : Symbol(Promise, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
// This is contextually typed as a tuple.
return [1, true];
}
@@ -0,0 +1,22 @@
=== tests/cases/compiler/asyncFunctionReturnType.ts ===
async function fAsync() {
>fAsync : () => Promise<(number | boolean)[]>
// Without explicit type annotation, this is just an array.
return [1, true];
>[1, true] : (number | boolean)[]
>1 : number
>true : boolean
}
async function fAsyncExplicit(): Promise<[number, boolean]> {
>fAsyncExplicit : () => Promise<[number, boolean]>
>Promise : Promise<T>
// This is contextually typed as a tuple.
return [1, true];
>[1, true] : [number, boolean]
>1 : number
>true : boolean
}
@@ -0,0 +1,27 @@
error TS2318: Cannot find global type 'Promise'.
tests/cases/compiler/disallowAsyncModifierInES5.ts(2,1): error TS1311: Async functions are only available when targeting ECMAScript 6 and higher.
tests/cases/compiler/disallowAsyncModifierInES5.ts(2,16): error TS1057: An async function or method must have a valid awaitable return type.
tests/cases/compiler/disallowAsyncModifierInES5.ts(3,11): error TS1057: An async function or method must have a valid awaitable return type.
tests/cases/compiler/disallowAsyncModifierInES5.ts(3,11): error TS1311: Async functions are only available when targeting ECMAScript 6 and higher.
tests/cases/compiler/disallowAsyncModifierInES5.ts(4,11): error TS1311: Async functions are only available when targeting ECMAScript 6 and higher.
tests/cases/compiler/disallowAsyncModifierInES5.ts(4,11): error TS1057: An async function or method must have a valid awaitable return type.
!!! error TS2318: Cannot find global type 'Promise'.
==== tests/cases/compiler/disallowAsyncModifierInES5.ts (6 errors) ====
async function foo() { return 42; } // ERROR: Async functions are only available in ES6+
~~~~~
!!! error TS1311: Async functions are only available when targeting ECMAScript 6 and higher.
~~~
!!! error TS1057: An async function or method must have a valid awaitable return type.
let bar = async function () { return 42; } // OK, but should be an error
~~~~~
!!! error TS1057: An async function or method must have a valid awaitable return type.
~~~~~
!!! error TS1311: Async functions are only available when targeting ECMAScript 6 and higher.
let baz = async () => 42; // OK, but should be an error
~~~~~
!!! error TS1311: Async functions are only available when targeting ECMAScript 6 and higher.
~~~~~~~~~~~~~~
!!! error TS1057: An async function or method must have a valid awaitable return type.
@@ -0,0 +1,22 @@
//// [disallowAsyncModifierInES5.ts]
async function foo() { return 42; } // ERROR: Async functions are only available in ES6+
let bar = async function () { return 42; } // OK, but should be an error
let baz = async () => 42; // OK, but should be an error
//// [disallowAsyncModifierInES5.js]
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments)).next());
});
};
function foo() {
return __awaiter(this, void 0, void 0, function* () { return 42; });
} // ERROR: Async functions are only available in ES6+
var bar = function () {
return __awaiter(this, void 0, void 0, function* () { return 42; });
}; // OK, but should be an error
var baz = function () __awaiter(this, void 0, void 0, function* () { return 42; }); // OK, but should be an error
@@ -133,8 +133,8 @@ function fn5(x: Derived1) {
// 1.5: y: Derived1
// Want: ???
let y = x;
>y : never
>x : never
>y : Derived1 & Derived2
>x : Derived1 & Derived2
}
}
@@ -0,0 +1,156 @@
//// [logicalAndOperatorStrictMode.ts]
const a = [0];
const s = "";
const x = 0;
const b = false;
const v: void = undefined;
const u = undefined;
const n = null;
const z = s || x || u;
const a1 = a && a;
const a2 = a && s;
const a3 = a && x;
const a4 = a && b;
const a5 = a && v;
const a6 = a && u;
const a7 = a && n;
const a8 = a && z;
const s1 = s && a;
const s2 = s && s;
const s3 = s && x;
const s4 = s && b;
const s5 = s && v;
const s6 = s && u;
const s7 = s && n;
const s8 = s && z;
const x1 = x && a;
const x2 = x && s;
const x3 = x && x;
const x4 = x && b;
const x5 = x && v;
const x6 = x && u;
const x7 = x && n;
const x8 = x && z;
const b1 = b && a;
const b2 = b && s;
const b3 = b && x;
const b4 = b && b;
const b5 = b && v;
const b6 = b && u;
const b7 = b && n;
const b8 = b && z;
const v1 = v && a;
const v2 = v && s;
const v3 = v && x;
const v4 = v && b;
const v5 = v && v;
const v6 = v && u;
const v7 = v && n;
const v8 = v && z;
const u1 = u && a;
const u2 = u && s;
const u3 = u && x;
const u4 = u && b;
const u5 = u && v;
const u6 = u && u;
const u7 = u && n;
const u8 = u && z;
const n1 = n && a;
const n2 = n && s;
const n3 = n && x;
const n4 = n && b;
const n5 = n && v;
const n6 = n && u;
const n7 = n && n;
const n8 = n && z;
const z1 = z && a;
const z2 = z && s;
const z3 = z && x;
const z4 = z && b;
const z5 = z && v;
const z6 = z && u;
const z7 = z && n;
const z8 = z && z;
//// [logicalAndOperatorStrictMode.js]
var a = [0];
var s = "";
var x = 0;
var b = false;
var v = undefined;
var u = undefined;
var n = null;
var z = s || x || u;
var a1 = a && a;
var a2 = a && s;
var a3 = a && x;
var a4 = a && b;
var a5 = a && v;
var a6 = a && u;
var a7 = a && n;
var a8 = a && z;
var s1 = s && a;
var s2 = s && s;
var s3 = s && x;
var s4 = s && b;
var s5 = s && v;
var s6 = s && u;
var s7 = s && n;
var s8 = s && z;
var x1 = x && a;
var x2 = x && s;
var x3 = x && x;
var x4 = x && b;
var x5 = x && v;
var x6 = x && u;
var x7 = x && n;
var x8 = x && z;
var b1 = b && a;
var b2 = b && s;
var b3 = b && x;
var b4 = b && b;
var b5 = b && v;
var b6 = b && u;
var b7 = b && n;
var b8 = b && z;
var v1 = v && a;
var v2 = v && s;
var v3 = v && x;
var v4 = v && b;
var v5 = v && v;
var v6 = v && u;
var v7 = v && n;
var v8 = v && z;
var u1 = u && a;
var u2 = u && s;
var u3 = u && x;
var u4 = u && b;
var u5 = u && v;
var u6 = u && u;
var u7 = u && n;
var u8 = u && z;
var n1 = n && a;
var n2 = n && s;
var n3 = n && x;
var n4 = n && b;
var n5 = n && v;
var n6 = n && u;
var n7 = n && n;
var n8 = n && z;
var z1 = z && a;
var z2 = z && s;
var z3 = z && x;
var z4 = z && b;
var z5 = z && v;
var z6 = z && u;
var z7 = z && n;
var z8 = z && z;
@@ -0,0 +1,351 @@
=== tests/cases/conformance/expressions/binaryOperators/logicalAndOperator/logicalAndOperatorStrictMode.ts ===
const a = [0];
>a : Symbol(a, Decl(logicalAndOperatorStrictMode.ts, 1, 5))
const s = "";
>s : Symbol(s, Decl(logicalAndOperatorStrictMode.ts, 2, 5))
const x = 0;
>x : Symbol(x, Decl(logicalAndOperatorStrictMode.ts, 3, 5))
const b = false;
>b : Symbol(b, Decl(logicalAndOperatorStrictMode.ts, 4, 5))
const v: void = undefined;
>v : Symbol(v, Decl(logicalAndOperatorStrictMode.ts, 5, 5))
>undefined : Symbol(undefined)
const u = undefined;
>u : Symbol(u, Decl(logicalAndOperatorStrictMode.ts, 6, 5))
>undefined : Symbol(undefined)
const n = null;
>n : Symbol(n, Decl(logicalAndOperatorStrictMode.ts, 7, 5))
const z = s || x || u;
>z : Symbol(z, Decl(logicalAndOperatorStrictMode.ts, 8, 5))
>s : Symbol(s, Decl(logicalAndOperatorStrictMode.ts, 2, 5))
>x : Symbol(x, Decl(logicalAndOperatorStrictMode.ts, 3, 5))
>u : Symbol(u, Decl(logicalAndOperatorStrictMode.ts, 6, 5))
const a1 = a && a;
>a1 : Symbol(a1, Decl(logicalAndOperatorStrictMode.ts, 10, 5))
>a : Symbol(a, Decl(logicalAndOperatorStrictMode.ts, 1, 5))
>a : Symbol(a, Decl(logicalAndOperatorStrictMode.ts, 1, 5))
const a2 = a && s;
>a2 : Symbol(a2, Decl(logicalAndOperatorStrictMode.ts, 11, 5))
>a : Symbol(a, Decl(logicalAndOperatorStrictMode.ts, 1, 5))
>s : Symbol(s, Decl(logicalAndOperatorStrictMode.ts, 2, 5))
const a3 = a && x;
>a3 : Symbol(a3, Decl(logicalAndOperatorStrictMode.ts, 12, 5))
>a : Symbol(a, Decl(logicalAndOperatorStrictMode.ts, 1, 5))
>x : Symbol(x, Decl(logicalAndOperatorStrictMode.ts, 3, 5))
const a4 = a && b;
>a4 : Symbol(a4, Decl(logicalAndOperatorStrictMode.ts, 13, 5))
>a : Symbol(a, Decl(logicalAndOperatorStrictMode.ts, 1, 5))
>b : Symbol(b, Decl(logicalAndOperatorStrictMode.ts, 4, 5))
const a5 = a && v;
>a5 : Symbol(a5, Decl(logicalAndOperatorStrictMode.ts, 14, 5))
>a : Symbol(a, Decl(logicalAndOperatorStrictMode.ts, 1, 5))
>v : Symbol(v, Decl(logicalAndOperatorStrictMode.ts, 5, 5))
const a6 = a && u;
>a6 : Symbol(a6, Decl(logicalAndOperatorStrictMode.ts, 15, 5))
>a : Symbol(a, Decl(logicalAndOperatorStrictMode.ts, 1, 5))
>u : Symbol(u, Decl(logicalAndOperatorStrictMode.ts, 6, 5))
const a7 = a && n;
>a7 : Symbol(a7, Decl(logicalAndOperatorStrictMode.ts, 16, 5))
>a : Symbol(a, Decl(logicalAndOperatorStrictMode.ts, 1, 5))
>n : Symbol(n, Decl(logicalAndOperatorStrictMode.ts, 7, 5))
const a8 = a && z;
>a8 : Symbol(a8, Decl(logicalAndOperatorStrictMode.ts, 17, 5))
>a : Symbol(a, Decl(logicalAndOperatorStrictMode.ts, 1, 5))
>z : Symbol(z, Decl(logicalAndOperatorStrictMode.ts, 8, 5))
const s1 = s && a;
>s1 : Symbol(s1, Decl(logicalAndOperatorStrictMode.ts, 19, 5))
>s : Symbol(s, Decl(logicalAndOperatorStrictMode.ts, 2, 5))
>a : Symbol(a, Decl(logicalAndOperatorStrictMode.ts, 1, 5))
const s2 = s && s;
>s2 : Symbol(s2, Decl(logicalAndOperatorStrictMode.ts, 20, 5))
>s : Symbol(s, Decl(logicalAndOperatorStrictMode.ts, 2, 5))
>s : Symbol(s, Decl(logicalAndOperatorStrictMode.ts, 2, 5))
const s3 = s && x;
>s3 : Symbol(s3, Decl(logicalAndOperatorStrictMode.ts, 21, 5))
>s : Symbol(s, Decl(logicalAndOperatorStrictMode.ts, 2, 5))
>x : Symbol(x, Decl(logicalAndOperatorStrictMode.ts, 3, 5))
const s4 = s && b;
>s4 : Symbol(s4, Decl(logicalAndOperatorStrictMode.ts, 22, 5))
>s : Symbol(s, Decl(logicalAndOperatorStrictMode.ts, 2, 5))
>b : Symbol(b, Decl(logicalAndOperatorStrictMode.ts, 4, 5))
const s5 = s && v;
>s5 : Symbol(s5, Decl(logicalAndOperatorStrictMode.ts, 23, 5))
>s : Symbol(s, Decl(logicalAndOperatorStrictMode.ts, 2, 5))
>v : Symbol(v, Decl(logicalAndOperatorStrictMode.ts, 5, 5))
const s6 = s && u;
>s6 : Symbol(s6, Decl(logicalAndOperatorStrictMode.ts, 24, 5))
>s : Symbol(s, Decl(logicalAndOperatorStrictMode.ts, 2, 5))
>u : Symbol(u, Decl(logicalAndOperatorStrictMode.ts, 6, 5))
const s7 = s && n;
>s7 : Symbol(s7, Decl(logicalAndOperatorStrictMode.ts, 25, 5))
>s : Symbol(s, Decl(logicalAndOperatorStrictMode.ts, 2, 5))
>n : Symbol(n, Decl(logicalAndOperatorStrictMode.ts, 7, 5))
const s8 = s && z;
>s8 : Symbol(s8, Decl(logicalAndOperatorStrictMode.ts, 26, 5))
>s : Symbol(s, Decl(logicalAndOperatorStrictMode.ts, 2, 5))
>z : Symbol(z, Decl(logicalAndOperatorStrictMode.ts, 8, 5))
const x1 = x && a;
>x1 : Symbol(x1, Decl(logicalAndOperatorStrictMode.ts, 28, 5))
>x : Symbol(x, Decl(logicalAndOperatorStrictMode.ts, 3, 5))
>a : Symbol(a, Decl(logicalAndOperatorStrictMode.ts, 1, 5))
const x2 = x && s;
>x2 : Symbol(x2, Decl(logicalAndOperatorStrictMode.ts, 29, 5))
>x : Symbol(x, Decl(logicalAndOperatorStrictMode.ts, 3, 5))
>s : Symbol(s, Decl(logicalAndOperatorStrictMode.ts, 2, 5))
const x3 = x && x;
>x3 : Symbol(x3, Decl(logicalAndOperatorStrictMode.ts, 30, 5))
>x : Symbol(x, Decl(logicalAndOperatorStrictMode.ts, 3, 5))
>x : Symbol(x, Decl(logicalAndOperatorStrictMode.ts, 3, 5))
const x4 = x && b;
>x4 : Symbol(x4, Decl(logicalAndOperatorStrictMode.ts, 31, 5))
>x : Symbol(x, Decl(logicalAndOperatorStrictMode.ts, 3, 5))
>b : Symbol(b, Decl(logicalAndOperatorStrictMode.ts, 4, 5))
const x5 = x && v;
>x5 : Symbol(x5, Decl(logicalAndOperatorStrictMode.ts, 32, 5))
>x : Symbol(x, Decl(logicalAndOperatorStrictMode.ts, 3, 5))
>v : Symbol(v, Decl(logicalAndOperatorStrictMode.ts, 5, 5))
const x6 = x && u;
>x6 : Symbol(x6, Decl(logicalAndOperatorStrictMode.ts, 33, 5))
>x : Symbol(x, Decl(logicalAndOperatorStrictMode.ts, 3, 5))
>u : Symbol(u, Decl(logicalAndOperatorStrictMode.ts, 6, 5))
const x7 = x && n;
>x7 : Symbol(x7, Decl(logicalAndOperatorStrictMode.ts, 34, 5))
>x : Symbol(x, Decl(logicalAndOperatorStrictMode.ts, 3, 5))
>n : Symbol(n, Decl(logicalAndOperatorStrictMode.ts, 7, 5))
const x8 = x && z;
>x8 : Symbol(x8, Decl(logicalAndOperatorStrictMode.ts, 35, 5))
>x : Symbol(x, Decl(logicalAndOperatorStrictMode.ts, 3, 5))
>z : Symbol(z, Decl(logicalAndOperatorStrictMode.ts, 8, 5))
const b1 = b && a;
>b1 : Symbol(b1, Decl(logicalAndOperatorStrictMode.ts, 37, 5))
>b : Symbol(b, Decl(logicalAndOperatorStrictMode.ts, 4, 5))
>a : Symbol(a, Decl(logicalAndOperatorStrictMode.ts, 1, 5))
const b2 = b && s;
>b2 : Symbol(b2, Decl(logicalAndOperatorStrictMode.ts, 38, 5))
>b : Symbol(b, Decl(logicalAndOperatorStrictMode.ts, 4, 5))
>s : Symbol(s, Decl(logicalAndOperatorStrictMode.ts, 2, 5))
const b3 = b && x;
>b3 : Symbol(b3, Decl(logicalAndOperatorStrictMode.ts, 39, 5))
>b : Symbol(b, Decl(logicalAndOperatorStrictMode.ts, 4, 5))
>x : Symbol(x, Decl(logicalAndOperatorStrictMode.ts, 3, 5))
const b4 = b && b;
>b4 : Symbol(b4, Decl(logicalAndOperatorStrictMode.ts, 40, 5))
>b : Symbol(b, Decl(logicalAndOperatorStrictMode.ts, 4, 5))
>b : Symbol(b, Decl(logicalAndOperatorStrictMode.ts, 4, 5))
const b5 = b && v;
>b5 : Symbol(b5, Decl(logicalAndOperatorStrictMode.ts, 41, 5))
>b : Symbol(b, Decl(logicalAndOperatorStrictMode.ts, 4, 5))
>v : Symbol(v, Decl(logicalAndOperatorStrictMode.ts, 5, 5))
const b6 = b && u;
>b6 : Symbol(b6, Decl(logicalAndOperatorStrictMode.ts, 42, 5))
>b : Symbol(b, Decl(logicalAndOperatorStrictMode.ts, 4, 5))
>u : Symbol(u, Decl(logicalAndOperatorStrictMode.ts, 6, 5))
const b7 = b && n;
>b7 : Symbol(b7, Decl(logicalAndOperatorStrictMode.ts, 43, 5))
>b : Symbol(b, Decl(logicalAndOperatorStrictMode.ts, 4, 5))
>n : Symbol(n, Decl(logicalAndOperatorStrictMode.ts, 7, 5))
const b8 = b && z;
>b8 : Symbol(b8, Decl(logicalAndOperatorStrictMode.ts, 44, 5))
>b : Symbol(b, Decl(logicalAndOperatorStrictMode.ts, 4, 5))
>z : Symbol(z, Decl(logicalAndOperatorStrictMode.ts, 8, 5))
const v1 = v && a;
>v1 : Symbol(v1, Decl(logicalAndOperatorStrictMode.ts, 46, 5))
>v : Symbol(v, Decl(logicalAndOperatorStrictMode.ts, 5, 5))
>a : Symbol(a, Decl(logicalAndOperatorStrictMode.ts, 1, 5))
const v2 = v && s;
>v2 : Symbol(v2, Decl(logicalAndOperatorStrictMode.ts, 47, 5))
>v : Symbol(v, Decl(logicalAndOperatorStrictMode.ts, 5, 5))
>s : Symbol(s, Decl(logicalAndOperatorStrictMode.ts, 2, 5))
const v3 = v && x;
>v3 : Symbol(v3, Decl(logicalAndOperatorStrictMode.ts, 48, 5))
>v : Symbol(v, Decl(logicalAndOperatorStrictMode.ts, 5, 5))
>x : Symbol(x, Decl(logicalAndOperatorStrictMode.ts, 3, 5))
const v4 = v && b;
>v4 : Symbol(v4, Decl(logicalAndOperatorStrictMode.ts, 49, 5))
>v : Symbol(v, Decl(logicalAndOperatorStrictMode.ts, 5, 5))
>b : Symbol(b, Decl(logicalAndOperatorStrictMode.ts, 4, 5))
const v5 = v && v;
>v5 : Symbol(v5, Decl(logicalAndOperatorStrictMode.ts, 50, 5))
>v : Symbol(v, Decl(logicalAndOperatorStrictMode.ts, 5, 5))
>v : Symbol(v, Decl(logicalAndOperatorStrictMode.ts, 5, 5))
const v6 = v && u;
>v6 : Symbol(v6, Decl(logicalAndOperatorStrictMode.ts, 51, 5))
>v : Symbol(v, Decl(logicalAndOperatorStrictMode.ts, 5, 5))
>u : Symbol(u, Decl(logicalAndOperatorStrictMode.ts, 6, 5))
const v7 = v && n;
>v7 : Symbol(v7, Decl(logicalAndOperatorStrictMode.ts, 52, 5))
>v : Symbol(v, Decl(logicalAndOperatorStrictMode.ts, 5, 5))
>n : Symbol(n, Decl(logicalAndOperatorStrictMode.ts, 7, 5))
const v8 = v && z;
>v8 : Symbol(v8, Decl(logicalAndOperatorStrictMode.ts, 53, 5))
>v : Symbol(v, Decl(logicalAndOperatorStrictMode.ts, 5, 5))
>z : Symbol(z, Decl(logicalAndOperatorStrictMode.ts, 8, 5))
const u1 = u && a;
>u1 : Symbol(u1, Decl(logicalAndOperatorStrictMode.ts, 55, 5))
>u : Symbol(u, Decl(logicalAndOperatorStrictMode.ts, 6, 5))
>a : Symbol(a, Decl(logicalAndOperatorStrictMode.ts, 1, 5))
const u2 = u && s;
>u2 : Symbol(u2, Decl(logicalAndOperatorStrictMode.ts, 56, 5))
>u : Symbol(u, Decl(logicalAndOperatorStrictMode.ts, 6, 5))
>s : Symbol(s, Decl(logicalAndOperatorStrictMode.ts, 2, 5))
const u3 = u && x;
>u3 : Symbol(u3, Decl(logicalAndOperatorStrictMode.ts, 57, 5))
>u : Symbol(u, Decl(logicalAndOperatorStrictMode.ts, 6, 5))
>x : Symbol(x, Decl(logicalAndOperatorStrictMode.ts, 3, 5))
const u4 = u && b;
>u4 : Symbol(u4, Decl(logicalAndOperatorStrictMode.ts, 58, 5))
>u : Symbol(u, Decl(logicalAndOperatorStrictMode.ts, 6, 5))
>b : Symbol(b, Decl(logicalAndOperatorStrictMode.ts, 4, 5))
const u5 = u && v;
>u5 : Symbol(u5, Decl(logicalAndOperatorStrictMode.ts, 59, 5))
>u : Symbol(u, Decl(logicalAndOperatorStrictMode.ts, 6, 5))
>v : Symbol(v, Decl(logicalAndOperatorStrictMode.ts, 5, 5))
const u6 = u && u;
>u6 : Symbol(u6, Decl(logicalAndOperatorStrictMode.ts, 60, 5))
>u : Symbol(u, Decl(logicalAndOperatorStrictMode.ts, 6, 5))
>u : Symbol(u, Decl(logicalAndOperatorStrictMode.ts, 6, 5))
const u7 = u && n;
>u7 : Symbol(u7, Decl(logicalAndOperatorStrictMode.ts, 61, 5))
>u : Symbol(u, Decl(logicalAndOperatorStrictMode.ts, 6, 5))
>n : Symbol(n, Decl(logicalAndOperatorStrictMode.ts, 7, 5))
const u8 = u && z;
>u8 : Symbol(u8, Decl(logicalAndOperatorStrictMode.ts, 62, 5))
>u : Symbol(u, Decl(logicalAndOperatorStrictMode.ts, 6, 5))
>z : Symbol(z, Decl(logicalAndOperatorStrictMode.ts, 8, 5))
const n1 = n && a;
>n1 : Symbol(n1, Decl(logicalAndOperatorStrictMode.ts, 64, 5))
>n : Symbol(n, Decl(logicalAndOperatorStrictMode.ts, 7, 5))
>a : Symbol(a, Decl(logicalAndOperatorStrictMode.ts, 1, 5))
const n2 = n && s;
>n2 : Symbol(n2, Decl(logicalAndOperatorStrictMode.ts, 65, 5))
>n : Symbol(n, Decl(logicalAndOperatorStrictMode.ts, 7, 5))
>s : Symbol(s, Decl(logicalAndOperatorStrictMode.ts, 2, 5))
const n3 = n && x;
>n3 : Symbol(n3, Decl(logicalAndOperatorStrictMode.ts, 66, 5))
>n : Symbol(n, Decl(logicalAndOperatorStrictMode.ts, 7, 5))
>x : Symbol(x, Decl(logicalAndOperatorStrictMode.ts, 3, 5))
const n4 = n && b;
>n4 : Symbol(n4, Decl(logicalAndOperatorStrictMode.ts, 67, 5))
>n : Symbol(n, Decl(logicalAndOperatorStrictMode.ts, 7, 5))
>b : Symbol(b, Decl(logicalAndOperatorStrictMode.ts, 4, 5))
const n5 = n && v;
>n5 : Symbol(n5, Decl(logicalAndOperatorStrictMode.ts, 68, 5))
>n : Symbol(n, Decl(logicalAndOperatorStrictMode.ts, 7, 5))
>v : Symbol(v, Decl(logicalAndOperatorStrictMode.ts, 5, 5))
const n6 = n && u;
>n6 : Symbol(n6, Decl(logicalAndOperatorStrictMode.ts, 69, 5))
>n : Symbol(n, Decl(logicalAndOperatorStrictMode.ts, 7, 5))
>u : Symbol(u, Decl(logicalAndOperatorStrictMode.ts, 6, 5))
const n7 = n && n;
>n7 : Symbol(n7, Decl(logicalAndOperatorStrictMode.ts, 70, 5))
>n : Symbol(n, Decl(logicalAndOperatorStrictMode.ts, 7, 5))
>n : Symbol(n, Decl(logicalAndOperatorStrictMode.ts, 7, 5))
const n8 = n && z;
>n8 : Symbol(n8, Decl(logicalAndOperatorStrictMode.ts, 71, 5))
>n : Symbol(n, Decl(logicalAndOperatorStrictMode.ts, 7, 5))
>z : Symbol(z, Decl(logicalAndOperatorStrictMode.ts, 8, 5))
const z1 = z && a;
>z1 : Symbol(z1, Decl(logicalAndOperatorStrictMode.ts, 73, 5))
>z : Symbol(z, Decl(logicalAndOperatorStrictMode.ts, 8, 5))
>a : Symbol(a, Decl(logicalAndOperatorStrictMode.ts, 1, 5))
const z2 = z && s;
>z2 : Symbol(z2, Decl(logicalAndOperatorStrictMode.ts, 74, 5))
>z : Symbol(z, Decl(logicalAndOperatorStrictMode.ts, 8, 5))
>s : Symbol(s, Decl(logicalAndOperatorStrictMode.ts, 2, 5))
const z3 = z && x;
>z3 : Symbol(z3, Decl(logicalAndOperatorStrictMode.ts, 75, 5))
>z : Symbol(z, Decl(logicalAndOperatorStrictMode.ts, 8, 5))
>x : Symbol(x, Decl(logicalAndOperatorStrictMode.ts, 3, 5))
const z4 = z && b;
>z4 : Symbol(z4, Decl(logicalAndOperatorStrictMode.ts, 76, 5))
>z : Symbol(z, Decl(logicalAndOperatorStrictMode.ts, 8, 5))
>b : Symbol(b, Decl(logicalAndOperatorStrictMode.ts, 4, 5))
const z5 = z && v;
>z5 : Symbol(z5, Decl(logicalAndOperatorStrictMode.ts, 77, 5))
>z : Symbol(z, Decl(logicalAndOperatorStrictMode.ts, 8, 5))
>v : Symbol(v, Decl(logicalAndOperatorStrictMode.ts, 5, 5))
const z6 = z && u;
>z6 : Symbol(z6, Decl(logicalAndOperatorStrictMode.ts, 78, 5))
>z : Symbol(z, Decl(logicalAndOperatorStrictMode.ts, 8, 5))
>u : Symbol(u, Decl(logicalAndOperatorStrictMode.ts, 6, 5))
const z7 = z && n;
>z7 : Symbol(z7, Decl(logicalAndOperatorStrictMode.ts, 79, 5))
>z : Symbol(z, Decl(logicalAndOperatorStrictMode.ts, 8, 5))
>n : Symbol(n, Decl(logicalAndOperatorStrictMode.ts, 7, 5))
const z8 = z && z;
>z8 : Symbol(z8, Decl(logicalAndOperatorStrictMode.ts, 80, 5))
>z : Symbol(z, Decl(logicalAndOperatorStrictMode.ts, 8, 5))
>z : Symbol(z, Decl(logicalAndOperatorStrictMode.ts, 8, 5))
@@ -0,0 +1,423 @@
=== tests/cases/conformance/expressions/binaryOperators/logicalAndOperator/logicalAndOperatorStrictMode.ts ===
const a = [0];
>a : number[]
>[0] : number[]
>0 : number
const s = "";
>s : string
>"" : string
const x = 0;
>x : number
>0 : number
const b = false;
>b : boolean
>false : boolean
const v: void = undefined;
>v : void
>undefined : undefined
const u = undefined;
>u : undefined
>undefined : undefined
const n = null;
>n : null
>null : null
const z = s || x || u;
>z : string | number | undefined
>s || x || u : string | number | undefined
>s || x : string | number
>s : string
>x : number
>u : undefined
const a1 = a && a;
>a1 : number[]
>a && a : number[]
>a : number[]
>a : number[]
const a2 = a && s;
>a2 : string
>a && s : string
>a : number[]
>s : string
const a3 = a && x;
>a3 : number
>a && x : number
>a : number[]
>x : number
const a4 = a && b;
>a4 : boolean
>a && b : boolean
>a : number[]
>b : boolean
const a5 = a && v;
>a5 : void
>a && v : void
>a : number[]
>v : void
const a6 = a && u;
>a6 : undefined
>a && u : undefined
>a : number[]
>u : undefined
const a7 = a && n;
>a7 : null
>a && n : null
>a : number[]
>n : null
const a8 = a && z;
>a8 : string | number | undefined
>a && z : string | number | undefined
>a : number[]
>z : string | number | undefined
const s1 = s && a;
>s1 : number[] | string
>s && a : number[] | string
>s : string
>a : number[]
const s2 = s && s;
>s2 : string
>s && s : string
>s : string
>s : string
const s3 = s && x;
>s3 : number | string
>s && x : number | string
>s : string
>x : number
const s4 = s && b;
>s4 : boolean | string
>s && b : boolean | string
>s : string
>b : boolean
const s5 = s && v;
>s5 : void | string
>s && v : void | string
>s : string
>v : void
const s6 = s && u;
>s6 : string | undefined
>s && u : string | undefined
>s : string
>u : undefined
const s7 = s && n;
>s7 : string | null
>s && n : string | null
>s : string
>n : null
const s8 = s && z;
>s8 : string | number | undefined
>s && z : string | number | undefined
>s : string
>z : string | number | undefined
const x1 = x && a;
>x1 : number[] | number
>x && a : number[] | number
>x : number
>a : number[]
const x2 = x && s;
>x2 : string | number
>x && s : string | number
>x : number
>s : string
const x3 = x && x;
>x3 : number
>x && x : number
>x : number
>x : number
const x4 = x && b;
>x4 : boolean | number
>x && b : boolean | number
>x : number
>b : boolean
const x5 = x && v;
>x5 : void | number
>x && v : void | number
>x : number
>v : void
const x6 = x && u;
>x6 : number | undefined
>x && u : number | undefined
>x : number
>u : undefined
const x7 = x && n;
>x7 : number | null
>x && n : number | null
>x : number
>n : null
const x8 = x && z;
>x8 : string | number | undefined
>x && z : string | number | undefined
>x : number
>z : string | number | undefined
const b1 = b && a;
>b1 : number[] | boolean
>b && a : number[] | boolean
>b : boolean
>a : number[]
const b2 = b && s;
>b2 : string | boolean
>b && s : string | boolean
>b : boolean
>s : string
const b3 = b && x;
>b3 : number | boolean
>b && x : number | boolean
>b : boolean
>x : number
const b4 = b && b;
>b4 : boolean
>b && b : boolean
>b : boolean
>b : boolean
const b5 = b && v;
>b5 : void | boolean
>b && v : void | boolean
>b : boolean
>v : void
const b6 = b && u;
>b6 : boolean | undefined
>b && u : boolean | undefined
>b : boolean
>u : undefined
const b7 = b && n;
>b7 : boolean | null
>b && n : boolean | null
>b : boolean
>n : null
const b8 = b && z;
>b8 : string | number | boolean | undefined
>b && z : string | number | boolean | undefined
>b : boolean
>z : string | number | undefined
const v1 = v && a;
>v1 : number[] | void
>v && a : number[] | void
>v : void
>a : number[]
const v2 = v && s;
>v2 : string | void
>v && s : string | void
>v : void
>s : string
const v3 = v && x;
>v3 : number | void
>v && x : number | void
>v : void
>x : number
const v4 = v && b;
>v4 : boolean | void
>v && b : boolean | void
>v : void
>b : boolean
const v5 = v && v;
>v5 : void
>v && v : void
>v : void
>v : never
const v6 = v && u;
>v6 : void
>v && u : void
>v : void
>u : undefined
const v7 = v && n;
>v7 : void | null
>v && n : void | null
>v : void
>n : null
const v8 = v && z;
>v8 : string | number | void
>v && z : string | number | void
>v : void
>z : string | number | undefined
const u1 = u && a;
>u1 : number[] | undefined
>u && a : number[] | undefined
>u : undefined
>a : number[]
const u2 = u && s;
>u2 : string | undefined
>u && s : string | undefined
>u : undefined
>s : string
const u3 = u && x;
>u3 : number | undefined
>u && x : number | undefined
>u : undefined
>x : number
const u4 = u && b;
>u4 : boolean | undefined
>u && b : boolean | undefined
>u : undefined
>b : boolean
const u5 = u && v;
>u5 : void
>u && v : void
>u : undefined
>v : void
const u6 = u && u;
>u6 : undefined
>u && u : undefined
>u : undefined
>u : never
const u7 = u && n;
>u7 : null | undefined
>u && n : null | undefined
>u : undefined
>n : null
const u8 = u && z;
>u8 : string | number | undefined
>u && z : string | number | undefined
>u : undefined
>z : string | number | undefined
const n1 = n && a;
>n1 : number[] | null
>n && a : number[] | null
>n : null
>a : number[]
const n2 = n && s;
>n2 : string | null
>n && s : string | null
>n : null
>s : string
const n3 = n && x;
>n3 : number | null
>n && x : number | null
>n : null
>x : number
const n4 = n && b;
>n4 : boolean | null
>n && b : boolean | null
>n : null
>b : boolean
const n5 = n && v;
>n5 : void | null
>n && v : void | null
>n : null
>v : void
const n6 = n && u;
>n6 : null | undefined
>n && u : null | undefined
>n : null
>u : undefined
const n7 = n && n;
>n7 : null
>n && n : null
>n : null
>n : never
const n8 = n && z;
>n8 : string | number | null | undefined
>n && z : string | number | null | undefined
>n : null
>z : string | number | undefined
const z1 = z && a;
>z1 : number[] | string | number | undefined
>z && a : number[] | string | number | undefined
>z : string | number | undefined
>a : number[]
const z2 = z && s;
>z2 : string | number | undefined
>z && s : string | number | undefined
>z : string | number | undefined
>s : string
const z3 = z && x;
>z3 : number | string | undefined
>z && x : number | string | undefined
>z : string | number | undefined
>x : number
const z4 = z && b;
>z4 : boolean | string | number | undefined
>z && b : boolean | string | number | undefined
>z : string | number | undefined
>b : boolean
const z5 = z && v;
>z5 : void | string | number
>z && v : void | string | number
>z : string | number | undefined
>v : void
const z6 = z && u;
>z6 : string | number | undefined
>z && u : string | number | undefined
>z : string | number | undefined
>u : undefined
const z7 = z && n;
>z7 : string | number | null | undefined
>z && n : string | number | null | undefined
>z : string | number | undefined
>n : null
const z8 = z && z;
>z8 : string | number | undefined
>z && z : string | number | undefined
>z : string | number | undefined
>z : string | number
@@ -0,0 +1,46 @@
//// [tests/cases/conformance/externalModules/moduleResolutionWithExtensions.ts] ////
//// [a.ts]
export default 0;
// No extension: '.ts' added
//// [b.ts]
import a from './a';
// Matching extension
//// [c.ts]
import a from './a.ts';
// '.js' extension: stripped and replaced with '.ts'
//// [d.ts]
import a from './a.js';
//// [jquery.d.ts]
declare var x: number;
export default x;
// No extension: '.d.ts' added
//// [jquery_user_1.ts]
import j from "./jquery";
// '.js' extension: stripped and replaced with '.d.ts'
//// [jquery_user_1.ts]
import j from "./jquery.js"
//// [a.js]
"use strict";
exports.__esModule = true;
exports["default"] = 0;
// No extension: '.ts' added
//// [b.js]
"use strict";
// Matching extension
//// [c.js]
"use strict";
// '.js' extension: stripped and replaced with '.ts'
//// [d.js]
"use strict";
//// [jquery_user_1.js]
"use strict";
@@ -0,0 +1,37 @@
=== /src/a.ts ===
No type information for this code.export default 0;
No type information for this code.
No type information for this code.// No extension: '.ts' added
No type information for this code.=== /src/b.ts ===
import a from './a';
>a : Symbol(a, Decl(b.ts, 0, 6))
// Matching extension
=== /src/c.ts ===
import a from './a.ts';
>a : Symbol(a, Decl(c.ts, 0, 6))
// '.js' extension: stripped and replaced with '.ts'
=== /src/d.ts ===
import a from './a.js';
>a : Symbol(a, Decl(d.ts, 0, 6))
=== /src/jquery.d.ts ===
declare var x: number;
>x : Symbol(x, Decl(jquery.d.ts, 0, 11))
export default x;
>x : Symbol(x, Decl(jquery.d.ts, 0, 11))
// No extension: '.d.ts' added
=== /src/jquery_user_1.ts ===
import j from "./jquery";
>j : Symbol(j, Decl(jquery_user_1.ts, 0, 6))
// '.js' extension: stripped and replaced with '.d.ts'
=== /src/jquery_user_1.ts ===
import j from "./jquery.js"
>j : Symbol(j, Decl(jquery_user_1.ts, 0, 6))
>j : Symbol(j, Decl(jquery_user_1.ts, 0, 6))
@@ -0,0 +1,32 @@
[
"======== Resolving module './a' from '/src/b.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"Loading module as file / folder, candidate module location '/src/a'.",
"File '/src/a.ts' exist - use it as a name resolution result.",
"======== Module name './a' was successfully resolved to '/src/a.ts'. ========",
"======== Resolving module './a.ts' from '/src/c.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"Loading module as file / folder, candidate module location '/src/a.ts'.",
"File '/src/a.ts' exist - use it as a name resolution result.",
"======== Module name './a.ts' was successfully resolved to '/src/a.ts'. ========",
"======== Resolving module './a.js' from '/src/d.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"Loading module as file / folder, candidate module location '/src/a.js'.",
"File '/src/a.js.ts' does not exist.",
"File '/src/a.js.tsx' does not exist.",
"File '/src/a.js.d.ts' does not exist.",
"File name '/src/a.js' has a '.js' extension - stripping it",
"File '/src/a.ts' exist - use it as a name resolution result.",
"======== Module name './a.js' was successfully resolved to '/src/a.ts'. ========",
"======== Resolving module './jquery.js' from '/src/jquery_user_1.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"Loading module as file / folder, candidate module location '/src/jquery.js'.",
"File '/src/jquery.js.ts' does not exist.",
"File '/src/jquery.js.tsx' does not exist.",
"File '/src/jquery.js.d.ts' does not exist.",
"File name '/src/jquery.js' has a '.js' extension - stripping it",
"File '/src/jquery.ts' does not exist.",
"File '/src/jquery.tsx' does not exist.",
"File '/src/jquery.d.ts' exist - use it as a name resolution result.",
"======== Module name './jquery.js' was successfully resolved to '/src/jquery.d.ts'. ========"
]
@@ -0,0 +1,37 @@
=== /src/a.ts ===
No type information for this code.export default 0;
No type information for this code.
No type information for this code.// No extension: '.ts' added
No type information for this code.=== /src/b.ts ===
import a from './a';
>a : number
// Matching extension
=== /src/c.ts ===
import a from './a.ts';
>a : number
// '.js' extension: stripped and replaced with '.ts'
=== /src/d.ts ===
import a from './a.js';
>a : number
=== /src/jquery.d.ts ===
declare var x: number;
>x : number
export default x;
>x : number
// No extension: '.d.ts' added
=== /src/jquery_user_1.ts ===
import j from "./jquery";
>j : number
// '.js' extension: stripped and replaced with '.d.ts'
=== /src/jquery_user_1.ts ===
import j from "./jquery.js"
>j : number
>j : number
@@ -1,12 +0,0 @@
tests/cases/conformance/externalModules/foo_1.ts(1,22): error TS2307: Cannot find module './foo_0.js'.
==== tests/cases/conformance/externalModules/foo_1.ts (1 errors) ====
import foo = require('./foo_0.js');
~~~~~~~~~~~~
!!! error TS2307: Cannot find module './foo_0.js'.
var x = foo.foo + 42;
==== tests/cases/conformance/externalModules/foo_0.ts (0 errors) ====
export var foo = 42;
@@ -8,6 +8,9 @@ import foo = require('./foo_0.js');
var x = foo.foo + 42;
//// [foo_0.js]
"use strict";
exports.foo = 42;
//// [foo_1.js]
"use strict";
var foo = require('./foo_0.js');
@@ -0,0 +1,14 @@
=== tests/cases/conformance/externalModules/foo_1.ts ===
import foo = require('./foo_0.js');
>foo : Symbol(foo, Decl(foo_1.ts, 0, 0))
var x = foo.foo + 42;
>x : Symbol(x, Decl(foo_1.ts, 1, 3))
>foo.foo : Symbol(foo.foo, Decl(foo_0.ts, 0, 10))
>foo : Symbol(foo, Decl(foo_1.ts, 0, 0))
>foo : Symbol(foo.foo, Decl(foo_0.ts, 0, 10))
=== tests/cases/conformance/externalModules/foo_0.ts ===
export var foo = 42;
>foo : Symbol(foo, Decl(foo_0.ts, 0, 10))
@@ -0,0 +1,17 @@
=== tests/cases/conformance/externalModules/foo_1.ts ===
import foo = require('./foo_0.js');
>foo : typeof foo
var x = foo.foo + 42;
>x : number
>foo.foo + 42 : number
>foo.foo : number
>foo : typeof foo
>foo : number
>42 : number
=== tests/cases/conformance/externalModules/foo_0.ts ===
export var foo = 42;
>foo : number
>42 : number
@@ -1,7 +0,0 @@
error TS5053: Option 'sourceRoot' cannot be specified with option 'inlineSources'.
!!! error TS5053: Option 'sourceRoot' cannot be specified with option 'inlineSources'.
==== tests/cases/compiler/optionsSourcemapInlineSourcesSourceRoot.ts (0 errors) ====
var a = 10;
@@ -0,0 +1,5 @@
=== tests/cases/compiler/optionsSourcemapInlineSourcesSourceRoot.ts ===
var a = 10;
>a : Symbol(a, Decl(optionsSourcemapInlineSourcesSourceRoot.ts, 1, 3))
@@ -0,0 +1,6 @@
=== tests/cases/compiler/optionsSourcemapInlineSourcesSourceRoot.ts ===
var a = 10;
>a : number
>10 : number
@@ -1,12 +1,12 @@
decl.ts(1,26): error TS2307: Cannot find module './foo/bar.js'.
decl.ts(1,26): error TS2307: Cannot find module './foo/bar.tx'.
decl.ts(2,26): error TS2307: Cannot find module 'baz'.
decl.ts(3,26): error TS2307: Cannot find module './baz'.
==== decl.ts (3 errors) ====
import modErr = require("./foo/bar.js");
import modErr = require("./foo/bar.tx");
~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module './foo/bar.js'.
!!! error TS2307: Cannot find module './foo/bar.tx'.
import modErr1 = require("baz");
~~~~~
!!! error TS2307: Cannot find module 'baz'.
@@ -1,12 +1,12 @@
decl.ts(1,26): error TS2307: Cannot find module './foo/bar.js'.
decl.ts(1,26): error TS2307: Cannot find module './foo/bar.tx'.
decl.ts(2,26): error TS2307: Cannot find module 'baz'.
decl.ts(3,26): error TS2307: Cannot find module './baz'.
==== decl.ts (3 errors) ====
import modErr = require("./foo/bar.js");
import modErr = require("./foo/bar.tx");
~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module './foo/bar.js'.
!!! error TS2307: Cannot find module './foo/bar.tx'.
import modErr1 = require("baz");
~~~~~
!!! error TS2307: Cannot find module 'baz'.
@@ -1,9 +1,9 @@
error TS5051: Option 'sourceRoot can only be used when either option '--inlineSourceMap' or option '--sourceMap' is provided.
error TS5052: Option 'mapRoot' cannot be specified without specifying option 'sourceMap'.
error TS5052: Option 'sourceRoot' cannot be specified without specifying option 'sourceMap'.
!!! error TS5051: Option 'sourceRoot can only be used when either option '--inlineSourceMap' or option '--sourceMap' is provided.
!!! error TS5052: Option 'mapRoot' cannot be specified without specifying option 'sourceMap'.
!!! error TS5052: Option 'sourceRoot' cannot be specified without specifying option 'sourceMap'.
==== m1.ts (0 errors) ====
var m1_a1 = 10;
class m1_c1 {
@@ -1,9 +1,9 @@
error TS5051: Option 'sourceRoot can only be used when either option '--inlineSourceMap' or option '--sourceMap' is provided.
error TS5052: Option 'mapRoot' cannot be specified without specifying option 'sourceMap'.
error TS5052: Option 'sourceRoot' cannot be specified without specifying option 'sourceMap'.
!!! error TS5051: Option 'sourceRoot can only be used when either option '--inlineSourceMap' or option '--sourceMap' is provided.
!!! error TS5052: Option 'mapRoot' cannot be specified without specifying option 'sourceMap'.
!!! error TS5052: Option 'sourceRoot' cannot be specified without specifying option 'sourceMap'.
==== m1.ts (0 errors) ====
var m1_a1 = 10;
class m1_c1 {
@@ -1,7 +1,7 @@
error TS5052: Option 'sourceRoot' cannot be specified without specifying option 'sourceMap'.
error TS5051: Option 'sourceRoot can only be used when either option '--inlineSourceMap' or option '--sourceMap' is provided.
!!! error TS5052: Option 'sourceRoot' cannot be specified without specifying option 'sourceMap'.
!!! error TS5051: Option 'sourceRoot can only be used when either option '--inlineSourceMap' or option '--sourceMap' is provided.
==== m1.ts (0 errors) ====
var m1_a1 = 10;
class m1_c1 {
@@ -1,7 +1,7 @@
error TS5052: Option 'sourceRoot' cannot be specified without specifying option 'sourceMap'.
error TS5051: Option 'sourceRoot can only be used when either option '--inlineSourceMap' or option '--sourceMap' is provided.
!!! error TS5052: Option 'sourceRoot' cannot be specified without specifying option 'sourceMap'.
!!! error TS5051: Option 'sourceRoot can only be used when either option '--inlineSourceMap' or option '--sourceMap' is provided.
==== m1.ts (0 errors) ====
var m1_a1 = 10;
class m1_c1 {
@@ -116,6 +116,6 @@ if (!hasKind(x, "B")) {
}
else {
let d = x;
>d : never
>x : never
>d : A & B
>x : A & B
}
@@ -110,6 +110,6 @@ if (!hasKind(x, "B")) {
}
else {
let d = x;
>d : never
>x : never
>d : A & B
>x : A & B
}
@@ -113,6 +113,6 @@ if (!hasKind(x, "B")) {
}
else {
let d = x;
>d : never
>x : never
>d : A & B
>x : A & B
}
@@ -0,0 +1,179 @@
//// [typeGuardIntersectionTypes.ts]
interface X {
x: string;
}
interface Y {
y: string;
}
interface Z {
z: string;
}
declare function isX(obj: any): obj is X;
declare function isY(obj: any): obj is Y;
declare function isZ(obj: any): obj is Z;
function f1(obj: Object) {
if (isX(obj) || isY(obj) || isZ(obj)) {
obj;
}
if (isX(obj) && isY(obj) && isZ(obj)) {
obj;
}
}
// Repro from #8911
// two interfaces
interface A {
a: string;
}
interface B {
b: string;
}
// a type guard for B
function isB(toTest: any): toTest is B {
return toTest && toTest.b;
}
// a function that turns an A into an A & B
function union(a: A): A & B | null {
if (isB(a)) {
return a;
} else {
return null;
}
}
// Repro from #9016
declare function log(s: string): void;
// Supported beast features
interface Beast { wings?: boolean; legs?: number }
interface Legged { legs: number; }
interface Winged { wings: boolean; }
// Beast feature detection via user-defined type guards
function hasLegs(x: Beast): x is Legged { return x && typeof x.legs === 'number'; }
function hasWings(x: Beast): x is Winged { return x && !!x.wings; }
// Function to identify a given beast by detecting its features
function identifyBeast(beast: Beast) {
// All beasts with legs
if (hasLegs(beast)) {
// All winged beasts with legs
if (hasWings(beast)) {
if (beast.legs === 4) {
log(`pegasus - 4 legs, wings`);
}
else if (beast.legs === 2) {
log(`bird - 2 legs, wings`);
}
else {
log(`unknown - ${beast.legs} legs, wings`);
}
}
// All non-winged beasts with legs
else {
log(`manbearpig - ${beast.legs} legs, no wings`);
}
}
// All beasts without legs
else {
if (hasWings(beast)) {
log(`quetzalcoatl - no legs, wings`)
}
else {
log(`snake - no legs, no wings`)
}
}
}
function beastFoo(beast: Object) {
if (hasWings(beast) && hasLegs(beast)) {
beast; // Winged & Legged
}
else {
beast;
}
if (hasLegs(beast) && hasWings(beast)) {
beast; // Legged & Winged
}
}
//// [typeGuardIntersectionTypes.js]
function f1(obj) {
if (isX(obj) || isY(obj) || isZ(obj)) {
obj;
}
if (isX(obj) && isY(obj) && isZ(obj)) {
obj;
}
}
// a type guard for B
function isB(toTest) {
return toTest && toTest.b;
}
// a function that turns an A into an A & B
function union(a) {
if (isB(a)) {
return a;
}
else {
return null;
}
}
// Beast feature detection via user-defined type guards
function hasLegs(x) { return x && typeof x.legs === 'number'; }
function hasWings(x) { return x && !!x.wings; }
// Function to identify a given beast by detecting its features
function identifyBeast(beast) {
// All beasts with legs
if (hasLegs(beast)) {
// All winged beasts with legs
if (hasWings(beast)) {
if (beast.legs === 4) {
log("pegasus - 4 legs, wings");
}
else if (beast.legs === 2) {
log("bird - 2 legs, wings");
}
else {
log("unknown - " + beast.legs + " legs, wings");
}
}
else {
log("manbearpig - " + beast.legs + " legs, no wings");
}
}
else {
if (hasWings(beast)) {
log("quetzalcoatl - no legs, wings");
}
else {
log("snake - no legs, no wings");
}
}
}
function beastFoo(beast) {
if (hasWings(beast) && hasLegs(beast)) {
beast; // Winged & Legged
}
else {
beast;
}
if (hasLegs(beast) && hasWings(beast)) {
beast; // Legged & Winged
}
}
@@ -0,0 +1,258 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardIntersectionTypes.ts ===
interface X {
>X : Symbol(X, Decl(typeGuardIntersectionTypes.ts, 0, 0))
x: string;
>x : Symbol(X.x, Decl(typeGuardIntersectionTypes.ts, 1, 13))
}
interface Y {
>Y : Symbol(Y, Decl(typeGuardIntersectionTypes.ts, 3, 1))
y: string;
>y : Symbol(Y.y, Decl(typeGuardIntersectionTypes.ts, 5, 13))
}
interface Z {
>Z : Symbol(Z, Decl(typeGuardIntersectionTypes.ts, 7, 1))
z: string;
>z : Symbol(Z.z, Decl(typeGuardIntersectionTypes.ts, 9, 13))
}
declare function isX(obj: any): obj is X;
>isX : Symbol(isX, Decl(typeGuardIntersectionTypes.ts, 11, 1))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 13, 21))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 13, 21))
>X : Symbol(X, Decl(typeGuardIntersectionTypes.ts, 0, 0))
declare function isY(obj: any): obj is Y;
>isY : Symbol(isY, Decl(typeGuardIntersectionTypes.ts, 13, 41))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 14, 21))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 14, 21))
>Y : Symbol(Y, Decl(typeGuardIntersectionTypes.ts, 3, 1))
declare function isZ(obj: any): obj is Z;
>isZ : Symbol(isZ, Decl(typeGuardIntersectionTypes.ts, 14, 41))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 15, 21))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 15, 21))
>Z : Symbol(Z, Decl(typeGuardIntersectionTypes.ts, 7, 1))
function f1(obj: Object) {
>f1 : Symbol(f1, Decl(typeGuardIntersectionTypes.ts, 15, 41))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 17, 12))
>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
if (isX(obj) || isY(obj) || isZ(obj)) {
>isX : Symbol(isX, Decl(typeGuardIntersectionTypes.ts, 11, 1))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 17, 12))
>isY : Symbol(isY, Decl(typeGuardIntersectionTypes.ts, 13, 41))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 17, 12))
>isZ : Symbol(isZ, Decl(typeGuardIntersectionTypes.ts, 14, 41))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 17, 12))
obj;
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 17, 12))
}
if (isX(obj) && isY(obj) && isZ(obj)) {
>isX : Symbol(isX, Decl(typeGuardIntersectionTypes.ts, 11, 1))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 17, 12))
>isY : Symbol(isY, Decl(typeGuardIntersectionTypes.ts, 13, 41))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 17, 12))
>isZ : Symbol(isZ, Decl(typeGuardIntersectionTypes.ts, 14, 41))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 17, 12))
obj;
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 17, 12))
}
}
// Repro from #8911
// two interfaces
interface A {
>A : Symbol(A, Decl(typeGuardIntersectionTypes.ts, 24, 1))
a: string;
>a : Symbol(A.a, Decl(typeGuardIntersectionTypes.ts, 29, 13))
}
interface B {
>B : Symbol(B, Decl(typeGuardIntersectionTypes.ts, 31, 1))
b: string;
>b : Symbol(B.b, Decl(typeGuardIntersectionTypes.ts, 33, 13))
}
// a type guard for B
function isB(toTest: any): toTest is B {
>isB : Symbol(isB, Decl(typeGuardIntersectionTypes.ts, 35, 1))
>toTest : Symbol(toTest, Decl(typeGuardIntersectionTypes.ts, 38, 13))
>toTest : Symbol(toTest, Decl(typeGuardIntersectionTypes.ts, 38, 13))
>B : Symbol(B, Decl(typeGuardIntersectionTypes.ts, 31, 1))
return toTest && toTest.b;
>toTest : Symbol(toTest, Decl(typeGuardIntersectionTypes.ts, 38, 13))
>toTest : Symbol(toTest, Decl(typeGuardIntersectionTypes.ts, 38, 13))
}
// a function that turns an A into an A & B
function union(a: A): A & B | null {
>union : Symbol(union, Decl(typeGuardIntersectionTypes.ts, 40, 1))
>a : Symbol(a, Decl(typeGuardIntersectionTypes.ts, 43, 15))
>A : Symbol(A, Decl(typeGuardIntersectionTypes.ts, 24, 1))
>A : Symbol(A, Decl(typeGuardIntersectionTypes.ts, 24, 1))
>B : Symbol(B, Decl(typeGuardIntersectionTypes.ts, 31, 1))
if (isB(a)) {
>isB : Symbol(isB, Decl(typeGuardIntersectionTypes.ts, 35, 1))
>a : Symbol(a, Decl(typeGuardIntersectionTypes.ts, 43, 15))
return a;
>a : Symbol(a, Decl(typeGuardIntersectionTypes.ts, 43, 15))
} else {
return null;
}
}
// Repro from #9016
declare function log(s: string): void;
>log : Symbol(log, Decl(typeGuardIntersectionTypes.ts, 49, 1))
>s : Symbol(s, Decl(typeGuardIntersectionTypes.ts, 53, 21))
// Supported beast features
interface Beast { wings?: boolean; legs?: number }
>Beast : Symbol(Beast, Decl(typeGuardIntersectionTypes.ts, 53, 38))
>wings : Symbol(Beast.wings, Decl(typeGuardIntersectionTypes.ts, 56, 21))
>legs : Symbol(Beast.legs, Decl(typeGuardIntersectionTypes.ts, 56, 38))
interface Legged { legs: number; }
>Legged : Symbol(Legged, Decl(typeGuardIntersectionTypes.ts, 56, 54))
>legs : Symbol(Legged.legs, Decl(typeGuardIntersectionTypes.ts, 57, 21))
interface Winged { wings: boolean; }
>Winged : Symbol(Winged, Decl(typeGuardIntersectionTypes.ts, 57, 37))
>wings : Symbol(Winged.wings, Decl(typeGuardIntersectionTypes.ts, 58, 21))
// Beast feature detection via user-defined type guards
function hasLegs(x: Beast): x is Legged { return x && typeof x.legs === 'number'; }
>hasLegs : Symbol(hasLegs, Decl(typeGuardIntersectionTypes.ts, 58, 39))
>x : Symbol(x, Decl(typeGuardIntersectionTypes.ts, 61, 17))
>Beast : Symbol(Beast, Decl(typeGuardIntersectionTypes.ts, 53, 38))
>x : Symbol(x, Decl(typeGuardIntersectionTypes.ts, 61, 17))
>Legged : Symbol(Legged, Decl(typeGuardIntersectionTypes.ts, 56, 54))
>x : Symbol(x, Decl(typeGuardIntersectionTypes.ts, 61, 17))
>x.legs : Symbol(Beast.legs, Decl(typeGuardIntersectionTypes.ts, 56, 38))
>x : Symbol(x, Decl(typeGuardIntersectionTypes.ts, 61, 17))
>legs : Symbol(Beast.legs, Decl(typeGuardIntersectionTypes.ts, 56, 38))
function hasWings(x: Beast): x is Winged { return x && !!x.wings; }
>hasWings : Symbol(hasWings, Decl(typeGuardIntersectionTypes.ts, 61, 83))
>x : Symbol(x, Decl(typeGuardIntersectionTypes.ts, 62, 18))
>Beast : Symbol(Beast, Decl(typeGuardIntersectionTypes.ts, 53, 38))
>x : Symbol(x, Decl(typeGuardIntersectionTypes.ts, 62, 18))
>Winged : Symbol(Winged, Decl(typeGuardIntersectionTypes.ts, 57, 37))
>x : Symbol(x, Decl(typeGuardIntersectionTypes.ts, 62, 18))
>x.wings : Symbol(Beast.wings, Decl(typeGuardIntersectionTypes.ts, 56, 21))
>x : Symbol(x, Decl(typeGuardIntersectionTypes.ts, 62, 18))
>wings : Symbol(Beast.wings, Decl(typeGuardIntersectionTypes.ts, 56, 21))
// Function to identify a given beast by detecting its features
function identifyBeast(beast: Beast) {
>identifyBeast : Symbol(identifyBeast, Decl(typeGuardIntersectionTypes.ts, 62, 67))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 65, 23))
>Beast : Symbol(Beast, Decl(typeGuardIntersectionTypes.ts, 53, 38))
// All beasts with legs
if (hasLegs(beast)) {
>hasLegs : Symbol(hasLegs, Decl(typeGuardIntersectionTypes.ts, 58, 39))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 65, 23))
// All winged beasts with legs
if (hasWings(beast)) {
>hasWings : Symbol(hasWings, Decl(typeGuardIntersectionTypes.ts, 61, 83))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 65, 23))
if (beast.legs === 4) {
>beast.legs : Symbol(Legged.legs, Decl(typeGuardIntersectionTypes.ts, 57, 21))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 65, 23))
>legs : Symbol(Legged.legs, Decl(typeGuardIntersectionTypes.ts, 57, 21))
log(`pegasus - 4 legs, wings`);
>log : Symbol(log, Decl(typeGuardIntersectionTypes.ts, 49, 1))
}
else if (beast.legs === 2) {
>beast.legs : Symbol(Legged.legs, Decl(typeGuardIntersectionTypes.ts, 57, 21))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 65, 23))
>legs : Symbol(Legged.legs, Decl(typeGuardIntersectionTypes.ts, 57, 21))
log(`bird - 2 legs, wings`);
>log : Symbol(log, Decl(typeGuardIntersectionTypes.ts, 49, 1))
}
else {
log(`unknown - ${beast.legs} legs, wings`);
>log : Symbol(log, Decl(typeGuardIntersectionTypes.ts, 49, 1))
>beast.legs : Symbol(Legged.legs, Decl(typeGuardIntersectionTypes.ts, 57, 21))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 65, 23))
>legs : Symbol(Legged.legs, Decl(typeGuardIntersectionTypes.ts, 57, 21))
}
}
// All non-winged beasts with legs
else {
log(`manbearpig - ${beast.legs} legs, no wings`);
>log : Symbol(log, Decl(typeGuardIntersectionTypes.ts, 49, 1))
>beast.legs : Symbol(Legged.legs, Decl(typeGuardIntersectionTypes.ts, 57, 21))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 65, 23))
>legs : Symbol(Legged.legs, Decl(typeGuardIntersectionTypes.ts, 57, 21))
}
}
// All beasts without legs
else {
if (hasWings(beast)) {
>hasWings : Symbol(hasWings, Decl(typeGuardIntersectionTypes.ts, 61, 83))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 65, 23))
log(`quetzalcoatl - no legs, wings`)
>log : Symbol(log, Decl(typeGuardIntersectionTypes.ts, 49, 1))
}
else {
log(`snake - no legs, no wings`)
>log : Symbol(log, Decl(typeGuardIntersectionTypes.ts, 49, 1))
}
}
}
function beastFoo(beast: Object) {
>beastFoo : Symbol(beastFoo, Decl(typeGuardIntersectionTypes.ts, 98, 1))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 100, 18))
>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
if (hasWings(beast) && hasLegs(beast)) {
>hasWings : Symbol(hasWings, Decl(typeGuardIntersectionTypes.ts, 61, 83))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 100, 18))
>hasLegs : Symbol(hasLegs, Decl(typeGuardIntersectionTypes.ts, 58, 39))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 100, 18))
beast; // Winged & Legged
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 100, 18))
}
else {
beast;
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 100, 18))
}
if (hasLegs(beast) && hasWings(beast)) {
>hasLegs : Symbol(hasLegs, Decl(typeGuardIntersectionTypes.ts, 58, 39))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 100, 18))
>hasWings : Symbol(hasWings, Decl(typeGuardIntersectionTypes.ts, 61, 83))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 100, 18))
beast; // Legged & Winged
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 100, 18))
}
}
@@ -0,0 +1,306 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardIntersectionTypes.ts ===
interface X {
>X : X
x: string;
>x : string
}
interface Y {
>Y : Y
y: string;
>y : string
}
interface Z {
>Z : Z
z: string;
>z : string
}
declare function isX(obj: any): obj is X;
>isX : (obj: any) => obj is X
>obj : any
>obj : any
>X : X
declare function isY(obj: any): obj is Y;
>isY : (obj: any) => obj is Y
>obj : any
>obj : any
>Y : Y
declare function isZ(obj: any): obj is Z;
>isZ : (obj: any) => obj is Z
>obj : any
>obj : any
>Z : Z
function f1(obj: Object) {
>f1 : (obj: Object) => void
>obj : Object
>Object : Object
if (isX(obj) || isY(obj) || isZ(obj)) {
>isX(obj) || isY(obj) || isZ(obj) : boolean
>isX(obj) || isY(obj) : boolean
>isX(obj) : boolean
>isX : (obj: any) => obj is X
>obj : Object
>isY(obj) : boolean
>isY : (obj: any) => obj is Y
>obj : Object
>isZ(obj) : boolean
>isZ : (obj: any) => obj is Z
>obj : Object
obj;
>obj : X | Y | Z
}
if (isX(obj) && isY(obj) && isZ(obj)) {
>isX(obj) && isY(obj) && isZ(obj) : boolean
>isX(obj) && isY(obj) : boolean
>isX(obj) : boolean
>isX : (obj: any) => obj is X
>obj : Object
>isY(obj) : boolean
>isY : (obj: any) => obj is Y
>obj : X
>isZ(obj) : boolean
>isZ : (obj: any) => obj is Z
>obj : X & Y
obj;
>obj : X & Y & Z
}
}
// Repro from #8911
// two interfaces
interface A {
>A : A
a: string;
>a : string
}
interface B {
>B : B
b: string;
>b : string
}
// a type guard for B
function isB(toTest: any): toTest is B {
>isB : (toTest: any) => toTest is B
>toTest : any
>toTest : any
>B : B
return toTest && toTest.b;
>toTest && toTest.b : any
>toTest : any
>toTest.b : any
>toTest : any
>b : any
}
// a function that turns an A into an A & B
function union(a: A): A & B | null {
>union : (a: A) => (A & B) | null
>a : A
>A : A
>A : A
>B : B
>null : null
if (isB(a)) {
>isB(a) : boolean
>isB : (toTest: any) => toTest is B
>a : A
return a;
>a : A & B
} else {
return null;
>null : null
}
}
// Repro from #9016
declare function log(s: string): void;
>log : (s: string) => void
>s : string
// Supported beast features
interface Beast { wings?: boolean; legs?: number }
>Beast : Beast
>wings : boolean | undefined
>legs : number | undefined
interface Legged { legs: number; }
>Legged : Legged
>legs : number
interface Winged { wings: boolean; }
>Winged : Winged
>wings : boolean
// Beast feature detection via user-defined type guards
function hasLegs(x: Beast): x is Legged { return x && typeof x.legs === 'number'; }
>hasLegs : (x: Beast) => x is Legged
>x : Beast
>Beast : Beast
>x : any
>Legged : Legged
>x && typeof x.legs === 'number' : boolean
>x : Beast
>typeof x.legs === 'number' : boolean
>typeof x.legs : string
>x.legs : number | undefined
>x : Beast
>legs : number | undefined
>'number' : string
function hasWings(x: Beast): x is Winged { return x && !!x.wings; }
>hasWings : (x: Beast) => x is Winged
>x : Beast
>Beast : Beast
>x : any
>Winged : Winged
>x && !!x.wings : boolean
>x : Beast
>!!x.wings : boolean
>!x.wings : boolean
>x.wings : boolean | undefined
>x : Beast
>wings : boolean | undefined
// Function to identify a given beast by detecting its features
function identifyBeast(beast: Beast) {
>identifyBeast : (beast: Beast) => void
>beast : Beast
>Beast : Beast
// All beasts with legs
if (hasLegs(beast)) {
>hasLegs(beast) : boolean
>hasLegs : (x: Beast) => x is Legged
>beast : Beast
// All winged beasts with legs
if (hasWings(beast)) {
>hasWings(beast) : boolean
>hasWings : (x: Beast) => x is Winged
>beast : Legged
if (beast.legs === 4) {
>beast.legs === 4 : boolean
>beast.legs : number
>beast : Legged & Winged
>legs : number
>4 : number
log(`pegasus - 4 legs, wings`);
>log(`pegasus - 4 legs, wings`) : void
>log : (s: string) => void
>`pegasus - 4 legs, wings` : string
}
else if (beast.legs === 2) {
>beast.legs === 2 : boolean
>beast.legs : number
>beast : Legged & Winged
>legs : number
>2 : number
log(`bird - 2 legs, wings`);
>log(`bird - 2 legs, wings`) : void
>log : (s: string) => void
>`bird - 2 legs, wings` : string
}
else {
log(`unknown - ${beast.legs} legs, wings`);
>log(`unknown - ${beast.legs} legs, wings`) : void
>log : (s: string) => void
>`unknown - ${beast.legs} legs, wings` : string
>beast.legs : number
>beast : Legged & Winged
>legs : number
}
}
// All non-winged beasts with legs
else {
log(`manbearpig - ${beast.legs} legs, no wings`);
>log(`manbearpig - ${beast.legs} legs, no wings`) : void
>log : (s: string) => void
>`manbearpig - ${beast.legs} legs, no wings` : string
>beast.legs : number
>beast : Legged
>legs : number
}
}
// All beasts without legs
else {
if (hasWings(beast)) {
>hasWings(beast) : boolean
>hasWings : (x: Beast) => x is Winged
>beast : Beast
log(`quetzalcoatl - no legs, wings`)
>log(`quetzalcoatl - no legs, wings`) : void
>log : (s: string) => void
>`quetzalcoatl - no legs, wings` : string
}
else {
log(`snake - no legs, no wings`)
>log(`snake - no legs, no wings`) : void
>log : (s: string) => void
>`snake - no legs, no wings` : string
}
}
}
function beastFoo(beast: Object) {
>beastFoo : (beast: Object) => void
>beast : Object
>Object : Object
if (hasWings(beast) && hasLegs(beast)) {
>hasWings(beast) && hasLegs(beast) : boolean
>hasWings(beast) : boolean
>hasWings : (x: Beast) => x is Winged
>beast : Object
>hasLegs(beast) : boolean
>hasLegs : (x: Beast) => x is Legged
>beast : Winged
beast; // Winged & Legged
>beast : Winged & Legged
}
else {
beast;
>beast : Object
}
if (hasLegs(beast) && hasWings(beast)) {
>hasLegs(beast) && hasWings(beast) : boolean
>hasLegs(beast) : boolean
>hasLegs : (x: Beast) => x is Legged
>beast : Object
>hasWings(beast) : boolean
>hasWings : (x: Beast) => x is Winged
>beast : Legged
beast; // Legged & Winged
>beast : Legged & Winged
}
}
@@ -0,0 +1,86 @@
//// [typeGuardsNestedAssignments.ts]
class Foo {
x: string;
}
declare function getFooOrNull(): Foo | null;
declare function getStringOrNumberOrNull(): string | number | null;
function f1() {
let foo: Foo | null;
if ((foo = getFooOrNull()) !== null) {
foo; // Foo
}
}
function f2() {
let foo1: Foo | null;
let foo2: Foo | null;
if ((foo1 = getFooOrNull(), foo2 = foo1) !== null) {
foo1; // Foo | null
foo2; // Foo
}
}
function f3() {
let obj: Object | null;
if ((obj = getFooOrNull()) instanceof Foo) {
obj;
}
}
function f4() {
let x: string | number | null;
if (typeof (x = getStringOrNumberOrNull()) === "number") {
x;
}
}
// Repro from #8851
const re = /./g
let match: RegExpExecArray | null
while ((match = re.exec("xxx")) != null) {
const length = match[1].length + match[2].length
}
//// [typeGuardsNestedAssignments.js]
var Foo = (function () {
function Foo() {
}
return Foo;
}());
function f1() {
var foo;
if ((foo = getFooOrNull()) !== null) {
foo; // Foo
}
}
function f2() {
var foo1;
var foo2;
if ((foo1 = getFooOrNull(), foo2 = foo1) !== null) {
foo1; // Foo | null
foo2; // Foo
}
}
function f3() {
var obj;
if ((obj = getFooOrNull()) instanceof Foo) {
obj;
}
}
function f4() {
var x;
if (typeof (x = getStringOrNumberOrNull()) === "number") {
x;
}
}
// Repro from #8851
var re = /./g;
var match;
while ((match = re.exec("xxx")) != null) {
var length = match[1].length + match[2].length;
}
@@ -0,0 +1,113 @@
=== tests/cases/conformance/controlFlow/typeGuardsNestedAssignments.ts ===
class Foo {
>Foo : Symbol(Foo, Decl(typeGuardsNestedAssignments.ts, 0, 0))
x: string;
>x : Symbol(Foo.x, Decl(typeGuardsNestedAssignments.ts, 1, 11))
}
declare function getFooOrNull(): Foo | null;
>getFooOrNull : Symbol(getFooOrNull, Decl(typeGuardsNestedAssignments.ts, 3, 1))
>Foo : Symbol(Foo, Decl(typeGuardsNestedAssignments.ts, 0, 0))
declare function getStringOrNumberOrNull(): string | number | null;
>getStringOrNumberOrNull : Symbol(getStringOrNumberOrNull, Decl(typeGuardsNestedAssignments.ts, 5, 44))
function f1() {
>f1 : Symbol(f1, Decl(typeGuardsNestedAssignments.ts, 6, 67))
let foo: Foo | null;
>foo : Symbol(foo, Decl(typeGuardsNestedAssignments.ts, 9, 7))
>Foo : Symbol(Foo, Decl(typeGuardsNestedAssignments.ts, 0, 0))
if ((foo = getFooOrNull()) !== null) {
>foo : Symbol(foo, Decl(typeGuardsNestedAssignments.ts, 9, 7))
>getFooOrNull : Symbol(getFooOrNull, Decl(typeGuardsNestedAssignments.ts, 3, 1))
foo; // Foo
>foo : Symbol(foo, Decl(typeGuardsNestedAssignments.ts, 9, 7))
}
}
function f2() {
>f2 : Symbol(f2, Decl(typeGuardsNestedAssignments.ts, 13, 1))
let foo1: Foo | null;
>foo1 : Symbol(foo1, Decl(typeGuardsNestedAssignments.ts, 16, 7))
>Foo : Symbol(Foo, Decl(typeGuardsNestedAssignments.ts, 0, 0))
let foo2: Foo | null;
>foo2 : Symbol(foo2, Decl(typeGuardsNestedAssignments.ts, 17, 7))
>Foo : Symbol(Foo, Decl(typeGuardsNestedAssignments.ts, 0, 0))
if ((foo1 = getFooOrNull(), foo2 = foo1) !== null) {
>foo1 : Symbol(foo1, Decl(typeGuardsNestedAssignments.ts, 16, 7))
>getFooOrNull : Symbol(getFooOrNull, Decl(typeGuardsNestedAssignments.ts, 3, 1))
>foo2 : Symbol(foo2, Decl(typeGuardsNestedAssignments.ts, 17, 7))
>foo1 : Symbol(foo1, Decl(typeGuardsNestedAssignments.ts, 16, 7))
foo1; // Foo | null
>foo1 : Symbol(foo1, Decl(typeGuardsNestedAssignments.ts, 16, 7))
foo2; // Foo
>foo2 : Symbol(foo2, Decl(typeGuardsNestedAssignments.ts, 17, 7))
}
}
function f3() {
>f3 : Symbol(f3, Decl(typeGuardsNestedAssignments.ts, 22, 1))
let obj: Object | null;
>obj : Symbol(obj, Decl(typeGuardsNestedAssignments.ts, 25, 7))
>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
if ((obj = getFooOrNull()) instanceof Foo) {
>obj : Symbol(obj, Decl(typeGuardsNestedAssignments.ts, 25, 7))
>getFooOrNull : Symbol(getFooOrNull, Decl(typeGuardsNestedAssignments.ts, 3, 1))
>Foo : Symbol(Foo, Decl(typeGuardsNestedAssignments.ts, 0, 0))
obj;
>obj : Symbol(obj, Decl(typeGuardsNestedAssignments.ts, 25, 7))
}
}
function f4() {
>f4 : Symbol(f4, Decl(typeGuardsNestedAssignments.ts, 29, 1))
let x: string | number | null;
>x : Symbol(x, Decl(typeGuardsNestedAssignments.ts, 32, 7))
if (typeof (x = getStringOrNumberOrNull()) === "number") {
>x : Symbol(x, Decl(typeGuardsNestedAssignments.ts, 32, 7))
>getStringOrNumberOrNull : Symbol(getStringOrNumberOrNull, Decl(typeGuardsNestedAssignments.ts, 5, 44))
x;
>x : Symbol(x, Decl(typeGuardsNestedAssignments.ts, 32, 7))
}
}
// Repro from #8851
const re = /./g
>re : Symbol(re, Decl(typeGuardsNestedAssignments.ts, 40, 5))
let match: RegExpExecArray | null
>match : Symbol(match, Decl(typeGuardsNestedAssignments.ts, 41, 3))
>RegExpExecArray : Symbol(RegExpExecArray, Decl(lib.d.ts, --, --))
while ((match = re.exec("xxx")) != null) {
>match : Symbol(match, Decl(typeGuardsNestedAssignments.ts, 41, 3))
>re.exec : Symbol(RegExp.exec, Decl(lib.d.ts, --, --))
>re : Symbol(re, Decl(typeGuardsNestedAssignments.ts, 40, 5))
>exec : Symbol(RegExp.exec, Decl(lib.d.ts, --, --))
const length = match[1].length + match[2].length
>length : Symbol(length, Decl(typeGuardsNestedAssignments.ts, 44, 9))
>match[1].length : Symbol(String.length, Decl(lib.d.ts, --, --))
>match : Symbol(match, Decl(typeGuardsNestedAssignments.ts, 41, 3))
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
>match[2].length : Symbol(String.length, Decl(lib.d.ts, --, --))
>match : Symbol(match, Decl(typeGuardsNestedAssignments.ts, 41, 3))
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
}
@@ -0,0 +1,155 @@
=== tests/cases/conformance/controlFlow/typeGuardsNestedAssignments.ts ===
class Foo {
>Foo : Foo
x: string;
>x : string
}
declare function getFooOrNull(): Foo | null;
>getFooOrNull : () => Foo | null
>Foo : Foo
>null : null
declare function getStringOrNumberOrNull(): string | number | null;
>getStringOrNumberOrNull : () => string | number | null
>null : null
function f1() {
>f1 : () => void
let foo: Foo | null;
>foo : Foo | null
>Foo : Foo
>null : null
if ((foo = getFooOrNull()) !== null) {
>(foo = getFooOrNull()) !== null : boolean
>(foo = getFooOrNull()) : Foo | null
>foo = getFooOrNull() : Foo | null
>foo : Foo | null
>getFooOrNull() : Foo | null
>getFooOrNull : () => Foo | null
>null : null
foo; // Foo
>foo : Foo
}
}
function f2() {
>f2 : () => void
let foo1: Foo | null;
>foo1 : Foo | null
>Foo : Foo
>null : null
let foo2: Foo | null;
>foo2 : Foo | null
>Foo : Foo
>null : null
if ((foo1 = getFooOrNull(), foo2 = foo1) !== null) {
>(foo1 = getFooOrNull(), foo2 = foo1) !== null : boolean
>(foo1 = getFooOrNull(), foo2 = foo1) : Foo | null
>foo1 = getFooOrNull(), foo2 = foo1 : Foo | null
>foo1 = getFooOrNull() : Foo | null
>foo1 : Foo | null
>getFooOrNull() : Foo | null
>getFooOrNull : () => Foo | null
>foo2 = foo1 : Foo | null
>foo2 : Foo | null
>foo1 : Foo | null
>null : null
foo1; // Foo | null
>foo1 : Foo | null
foo2; // Foo
>foo2 : Foo
}
}
function f3() {
>f3 : () => void
let obj: Object | null;
>obj : Object | null
>Object : Object
>null : null
if ((obj = getFooOrNull()) instanceof Foo) {
>(obj = getFooOrNull()) instanceof Foo : boolean
>(obj = getFooOrNull()) : Foo | null
>obj = getFooOrNull() : Foo | null
>obj : Object | null
>getFooOrNull() : Foo | null
>getFooOrNull : () => Foo | null
>Foo : typeof Foo
obj;
>obj : Foo
}
}
function f4() {
>f4 : () => void
let x: string | number | null;
>x : string | number | null
>null : null
if (typeof (x = getStringOrNumberOrNull()) === "number") {
>typeof (x = getStringOrNumberOrNull()) === "number" : boolean
>typeof (x = getStringOrNumberOrNull()) : string
>(x = getStringOrNumberOrNull()) : string | number | null
>x = getStringOrNumberOrNull() : string | number | null
>x : string | number | null
>getStringOrNumberOrNull() : string | number | null
>getStringOrNumberOrNull : () => string | number | null
>"number" : string
x;
>x : number
}
}
// Repro from #8851
const re = /./g
>re : RegExp
>/./g : RegExp
let match: RegExpExecArray | null
>match : RegExpExecArray | null
>RegExpExecArray : RegExpExecArray
>null : null
while ((match = re.exec("xxx")) != null) {
>(match = re.exec("xxx")) != null : boolean
>(match = re.exec("xxx")) : RegExpExecArray | null
>match = re.exec("xxx") : RegExpExecArray | null
>match : RegExpExecArray | null
>re.exec("xxx") : RegExpExecArray | null
>re.exec : (string: string) => RegExpExecArray | null
>re : RegExp
>exec : (string: string) => RegExpExecArray | null
>"xxx" : string
>null : null
const length = match[1].length + match[2].length
>length : number
>match[1].length + match[2].length : number
>match[1].length : number
>match[1] : string
>match : RegExpExecArray
>1 : number
>length : number
>match[2].length : number
>match[2] : string
>match : RegExpExecArray
>2 : number
>length : number
}
@@ -1,14 +0,0 @@
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOf.ts(7,20): error TS2339: Property 'global' does not exist on type 'never'.
==== tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOf.ts (1 errors) ====
interface I { global: string; }
var result: I;
var result2: I;
if (!(result instanceof RegExp)) {
result = result2;
} else if (!result.global) {
~~~~~~
!!! error TS2339: Property 'global' does not exist on type 'never'.
}
@@ -0,0 +1,26 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOf.ts ===
interface I { global: string; }
>I : Symbol(I, Decl(typeGuardsWithInstanceOf.ts, 0, 0))
>global : Symbol(I.global, Decl(typeGuardsWithInstanceOf.ts, 0, 13))
var result: I;
>result : Symbol(result, Decl(typeGuardsWithInstanceOf.ts, 1, 3))
>I : Symbol(I, Decl(typeGuardsWithInstanceOf.ts, 0, 0))
var result2: I;
>result2 : Symbol(result2, Decl(typeGuardsWithInstanceOf.ts, 2, 3))
>I : Symbol(I, Decl(typeGuardsWithInstanceOf.ts, 0, 0))
if (!(result instanceof RegExp)) {
>result : Symbol(result, Decl(typeGuardsWithInstanceOf.ts, 1, 3))
>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
result = result2;
>result : Symbol(result, Decl(typeGuardsWithInstanceOf.ts, 1, 3))
>result2 : Symbol(result2, Decl(typeGuardsWithInstanceOf.ts, 2, 3))
} else if (!result.global) {
>result.global : Symbol(global, Decl(typeGuardsWithInstanceOf.ts, 0, 13), Decl(lib.d.ts, --, --))
>result : Symbol(result, Decl(typeGuardsWithInstanceOf.ts, 1, 3))
>global : Symbol(global, Decl(typeGuardsWithInstanceOf.ts, 0, 13), Decl(lib.d.ts, --, --))
}
@@ -0,0 +1,31 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOf.ts ===
interface I { global: string; }
>I : I
>global : string
var result: I;
>result : I
>I : I
var result2: I;
>result2 : I
>I : I
if (!(result instanceof RegExp)) {
>!(result instanceof RegExp) : boolean
>(result instanceof RegExp) : boolean
>result instanceof RegExp : boolean
>result : I
>RegExp : RegExpConstructor
result = result2;
>result = result2 : I
>result : I
>result2 : I
} else if (!result.global) {
>!result.global : boolean
>result.global : string & boolean
>result : I & RegExp
>global : string & boolean
}
@@ -8,7 +8,7 @@ export interface A {
x: () => typeof $
>x : Symbol(A.x, Decl(app.ts, 2, 20))
>$ : Symbol($, Decl(app.ts, 1, 8))
>$ : Symbol($, Decl(index.d.ts, 0, 11))
}
=== /ref.d.ts ===
@@ -8,7 +8,7 @@ export interface A {
x: typeof $;
>x : Symbol(A.x, Decl(app.ts, 2, 20))
>$ : Symbol($, Decl(app.ts, 1, 8))
>$ : Symbol($, Decl(index.d.ts, 0, 11))
}
=== /ref.d.ts ===
@@ -0,0 +1,10 @@
// @target: ES6
async function fAsync() {
// Without explicit type annotation, this is just an array.
return [1, true];
}
async function fAsyncExplicit(): Promise<[number, boolean]> {
// This is contextually typed as a tuple.
return [1, true];
}
@@ -0,0 +1,5 @@
// @target: es5
async function foo() { return 42; } // ERROR: Async functions are only available in ES6+
let bar = async function () { return 42; } // OK, but should be an error
let baz = async () => 42; // OK, but should be an error
@@ -0,0 +1,30 @@
// @Filename: declarations.d.ts
declare module "foo*baz" {
export function foo(s: string): void;
}
// Augmentations still work
declare module "foo*baz" {
export const baz: string;
}
// Longest prefix wins
declare module "foos*" {
export const foos: string;
}
declare module "*!text" {
const x: string;
export default x;
}
// @Filename: user.ts
///<reference path="declarations.d.ts" />
import {foo, baz} from "foobarbaz";
foo(baz);
import {foos} from "foosball";
foo(foos);
// Works with relative file name
import fileText from "./file!text";
foo(fileText);
@@ -0,0 +1 @@
declare module "too*many*asterisks" { }
@@ -0,0 +1,47 @@
// @strictNullChecks: true
class Foo {
x: string;
}
declare function getFooOrNull(): Foo | null;
declare function getStringOrNumberOrNull(): string | number | null;
function f1() {
let foo: Foo | null;
if ((foo = getFooOrNull()) !== null) {
foo; // Foo
}
}
function f2() {
let foo1: Foo | null;
let foo2: Foo | null;
if ((foo1 = getFooOrNull(), foo2 = foo1) !== null) {
foo1; // Foo | null
foo2; // Foo
}
}
function f3() {
let obj: Object | null;
if ((obj = getFooOrNull()) instanceof Foo) {
obj;
}
}
function f4() {
let x: string | number | null;
if (typeof (x = getStringOrNumberOrNull()) === "number") {
x;
}
}
// Repro from #8851
const re = /./g
let match: RegExpExecArray | null
while ((match = re.exec("xxx")) != null) {
const length = match[1].length + match[2].length
}
@@ -0,0 +1,82 @@
// @strictNullChecks: true
const a = [0];
const s = "";
const x = 0;
const b = false;
const v: void = undefined;
const u = undefined;
const n = null;
const z = s || x || u;
const a1 = a && a;
const a2 = a && s;
const a3 = a && x;
const a4 = a && b;
const a5 = a && v;
const a6 = a && u;
const a7 = a && n;
const a8 = a && z;
const s1 = s && a;
const s2 = s && s;
const s3 = s && x;
const s4 = s && b;
const s5 = s && v;
const s6 = s && u;
const s7 = s && n;
const s8 = s && z;
const x1 = x && a;
const x2 = x && s;
const x3 = x && x;
const x4 = x && b;
const x5 = x && v;
const x6 = x && u;
const x7 = x && n;
const x8 = x && z;
const b1 = b && a;
const b2 = b && s;
const b3 = b && x;
const b4 = b && b;
const b5 = b && v;
const b6 = b && u;
const b7 = b && n;
const b8 = b && z;
const v1 = v && a;
const v2 = v && s;
const v3 = v && x;
const v4 = v && b;
const v5 = v && v;
const v6 = v && u;
const v7 = v && n;
const v8 = v && z;
const u1 = u && a;
const u2 = u && s;
const u3 = u && x;
const u4 = u && b;
const u5 = u && v;
const u6 = u && u;
const u7 = u && n;
const u8 = u && z;
const n1 = n && a;
const n2 = n && s;
const n3 = n && x;
const n4 = n && b;
const n5 = n && v;
const n6 = n && u;
const n7 = n && n;
const n8 = n && z;
const z1 = z && a;
const z2 = z && s;
const z3 = z && x;
const z4 = z && b;
const z5 = z && v;
const z6 = z && u;
const z7 = z && n;
const z8 = z && z;
@@ -0,0 +1,113 @@
// @strictNullChecks: true
interface X {
x: string;
}
interface Y {
y: string;
}
interface Z {
z: string;
}
declare function isX(obj: any): obj is X;
declare function isY(obj: any): obj is Y;
declare function isZ(obj: any): obj is Z;
function f1(obj: Object) {
if (isX(obj) || isY(obj) || isZ(obj)) {
obj;
}
if (isX(obj) && isY(obj) && isZ(obj)) {
obj;
}
}
// Repro from #8911
// two interfaces
interface A {
a: string;
}
interface B {
b: string;
}
// a type guard for B
function isB(toTest: any): toTest is B {
return toTest && toTest.b;
}
// a function that turns an A into an A & B
function union(a: A): A & B | null {
if (isB(a)) {
return a;
} else {
return null;
}
}
// Repro from #9016
declare function log(s: string): void;
// Supported beast features
interface Beast { wings?: boolean; legs?: number }
interface Legged { legs: number; }
interface Winged { wings: boolean; }
// Beast feature detection via user-defined type guards
function hasLegs(x: Beast): x is Legged { return x && typeof x.legs === 'number'; }
function hasWings(x: Beast): x is Winged { return x && !!x.wings; }
// Function to identify a given beast by detecting its features
function identifyBeast(beast: Beast) {
// All beasts with legs
if (hasLegs(beast)) {
// All winged beasts with legs
if (hasWings(beast)) {
if (beast.legs === 4) {
log(`pegasus - 4 legs, wings`);
}
else if (beast.legs === 2) {
log(`bird - 2 legs, wings`);
}
else {
log(`unknown - ${beast.legs} legs, wings`);
}
}
// All non-winged beasts with legs
else {
log(`manbearpig - ${beast.legs} legs, no wings`);
}
}
// All beasts without legs
else {
if (hasWings(beast)) {
log(`quetzalcoatl - no legs, wings`)
}
else {
log(`snake - no legs, no wings`)
}
}
}
function beastFoo(beast: Object) {
if (hasWings(beast) && hasLegs(beast)) {
beast; // Winged & Legged
}
else {
beast;
}
if (hasLegs(beast) && hasWings(beast)) {
beast; // Legged & Winged
}
}
@@ -0,0 +1,28 @@
// @traceResolution: true
// @Filename: /src/a.ts
export default 0;
// No extension: '.ts' added
// @Filename: /src/b.ts
import a from './a';
// Matching extension
// @Filename: /src/c.ts
import a from './a.ts';
// '.js' extension: stripped and replaced with '.ts'
// @Filename: /src/d.ts
import a from './a.js';
// @Filename: /src/jquery.d.ts
declare var x: number;
export default x;
// No extension: '.d.ts' added
// @Filename: /src/jquery_user_1.ts
import j from "./jquery";
// '.js' extension: stripped and replaced with '.d.ts'
// @Filename: /src/jquery_user_1.ts
import j from "./jquery.js"
@@ -0,0 +1,15 @@
/// <reference path='fourslash.ts'/>
////type Options = "Option 1" | "Option 2" | "Option 3";
////var x: Options = "/*1*/Option 3";
////
////function f(a: Options) { };
////f("/*2*/
goTo.marker('1');
verify.completionListContains("Option 1");
verify.memberListCount(3);
goTo.marker('2');
verify.completionListContains("Option 2");
verify.memberListCount(3);
@@ -0,0 +1,20 @@
/// <reference path='fourslash.ts'/>
////var o = {
//// foo() { },
//// bar: 0,
//// "some other name": 1
////};
////
////o["/*1*/bar"];
////o["/*2*/
goTo.marker('1');
verify.completionListContains("foo");
verify.completionListAllowsNewIdentifier();
verify.memberListCount(3);
goTo.marker('2');
verify.completionListContains("some other name");
verify.completionListAllowsNewIdentifier();
verify.memberListCount(3);
@@ -0,0 +1,20 @@
/// <reference path='fourslash.ts'/>
////declare function f(a: "A", b: number): void;
////declare function f(a: "B", b: number): void;
////declare function f(a: "C", b: number): void;
////declare function f(a: string, b: number): void;
////
////f("/*1*/C", 2);
////
////f("/*2*/
goTo.marker('1');
verify.completionListContains("A");
verify.completionListAllowsNewIdentifier();
verify.memberListCount(3);
goTo.marker('2');
verify.completionListContains("A");
verify.completionListAllowsNewIdentifier();
verify.memberListCount(3);
+3 -3
View File
@@ -52,13 +52,13 @@ declare module ts {
None = 0,
Block = 1,
Smart = 2,
}
}
interface OutputFile {
name: string;
writeByteOrderMark: boolean;
text: string;
}
}
}
declare namespace FourSlashInterface {
@@ -139,7 +139,7 @@ declare namespace FourSlashInterface {
isValidBraceCompletionAtPostion(openingBrace?: string): void;
}
class verify extends verifyNegatable {
assertHasRanges(ranges: FourSlash.Range[]): void;
assertHasRanges(ranges: Range[]): void;
caretAtMarker(markerName?: string): void;
indentationIs(numberOfSpaces: number): void;
indentationAtPositionIs(fileName: string, position: number, numberOfSpaces: number, indentStyle?: ts.IndentStyle): void;
+67
View File
@@ -0,0 +1,67 @@
///<reference path="fourslash.ts" />
// Testing that quickInfo gets information with a corresponding meaning: values to values, types to types.
// For quick info purposes, we don't resolve past aliases.
// However, when we have an alias for a type, the quickInfo for a value with the same should skip the alias, and vice versa.
// goToDefinition should work the same way.
// @Filename: foo.d.ts
////declare const /*foo_value_declaration*/foo: number;
////declare module "foo_module" {
//// interface I { x: number; y: number }
//// export = I;
////}
// @Filename: foo_user.ts
///////<reference path="foo.d.ts" />
/////*foo_type_declaration*/import foo = require("foo_module");
////const x = foo/*foo_value*/;
////const i: foo/*foo_type*/ = { x: 1, y: 2 };
verify.numberOfErrorsInCurrentFile(0);
verify.navigationItemsListCount(2, "foo", "exact");
verify.navigationItemsListContains("foo", "alias", "foo", "exact");
verify.navigationItemsListContains("foo", "const", "foo", "exact");
goTo.marker("foo_value");
verify.quickInfoIs("const foo: number");
goTo.definition();
verify.caretAtMarker("foo_value_declaration");
goTo.marker("foo_type");
verify.quickInfoIs("import foo = require(\"foo_module\")");
goTo.definition();
verify.caretAtMarker("foo_type_declaration");
// Above tested for global const and imported interface. Now test with global interface and imported const.
// @Filename: bar.d.ts
/////*bar_type_declaration*/declare interface bar { x: number; y: number }
////declare module "bar_module" {
//// const x: number;
//// export = x;
////}
// @Filename: bar_user.ts
///////<reference path="bar.d.ts" />
/////*bar_value_declaration*/import bar = require("bar_module");
////const x = bar/*bar_value*/;
////const i: bar/*bar_type*/ = { x: 1, y: 2 };
verify.numberOfErrorsInCurrentFile(0);
verify.navigationItemsListCount(2, "bar", "exact");
verify.navigationItemsListContains("bar", "alias", "bar", "exact");
verify.navigationItemsListContains("bar", "interface", "bar", "exact");
goTo.marker("bar_value");
verify.quickInfoIs("import bar = require(\"bar_module\")");
goTo.definition();
verify.caretAtMarker("bar_value_declaration");
goTo.marker("bar_type");
verify.quickInfoIs("interface bar");
goTo.definition();
verify.caretAtMarker("bar_type_declaration");
+1 -1
View File
@@ -1,4 +1,4 @@
import modErr = require("./foo/bar.js");
import modErr = require("./foo/bar.tx");
import modErr1 = require("baz");
import modErr2 = require("./baz");
+41 -13
View File
@@ -7,17 +7,21 @@ namespace ts {
options?: TranspileOptions;
expectedOutput?: string;
expectedDiagnosticCodes?: number[];
expectedDiagnosticTexts?: string[];
}
function checkDiagnostics(diagnostics: Diagnostic[], expectedDiagnosticCodes?: number[]) {
if (!expectedDiagnosticCodes) {
return;
function checkDiagnostics(diagnostics: Diagnostic[], expectedDiagnosticCodes: number[] = [], expectedDiagnosticTexts?: string[]) {
const n = expectedDiagnosticCodes.length;
if (expectedDiagnosticTexts) {
assert.equal(n, expectedDiagnosticTexts.length);
}
for (let i = 0; i < expectedDiagnosticCodes.length; i++) {
assert.equal(expectedDiagnosticCodes[i], diagnostics[i] && diagnostics[i].code, `Could not find expeced diagnostic.`);
}
assert.equal(diagnostics.length, expectedDiagnosticCodes.length, "Resuting diagnostics count does not match expected");
for (let i = 0; i < n; i++) {
assert.equal(expectedDiagnosticCodes[i], diagnostics[i] && diagnostics[i].code, `Could not find expected diagnostic.`);
if (expectedDiagnosticTexts) {
assert.equal(expectedDiagnosticTexts[i], diagnostics[i] && diagnostics[i].messageText);
}
};
assert.equal(diagnostics.length, n, "Resuting diagnostics count does not match expected");
}
function test(input: string, testSettings: TranspileTestSettings): void {
@@ -26,7 +30,7 @@ namespace ts {
if (!transpileOptions.compilerOptions) {
transpileOptions.compilerOptions = {};
}
if (transpileOptions.compilerOptions.newLine === undefined) { //
if (transpileOptions.compilerOptions.newLine === undefined) {
// use \r\n as default new line
transpileOptions.compilerOptions.newLine = ts.NewLineKind.CarriageReturnLineFeed;
}
@@ -36,7 +40,7 @@ namespace ts {
transpileOptions.reportDiagnostics = true;
const transpileModuleResult = transpileModule(input, transpileOptions);
checkDiagnostics(transpileModuleResult.diagnostics, testSettings.expectedDiagnosticCodes);
checkDiagnostics(transpileModuleResult.diagnostics, testSettings.expectedDiagnosticCodes, testSettings.expectedDiagnosticTexts);
if (testSettings.expectedOutput !== undefined) {
assert.equal(transpileModuleResult.outputText, testSettings.expectedOutput);
@@ -45,7 +49,7 @@ namespace ts {
if (canUseOldTranspile) {
const diagnostics: Diagnostic[] = [];
const transpileResult = transpile(input, transpileOptions.compilerOptions, transpileOptions.fileName, diagnostics, transpileOptions.moduleName);
checkDiagnostics(diagnostics, testSettings.expectedDiagnosticCodes);
checkDiagnostics(diagnostics, testSettings.expectedDiagnosticCodes, testSettings.expectedDiagnosticTexts);
if (testSettings.expectedOutput) {
assert.equal(transpileResult, testSettings.expectedOutput);
}
@@ -292,13 +296,37 @@ var x = 0;`,
const output = `"use strict";\nvar a = 10;\n`;
test(input, {
expectedOutput: output,
options: { compilerOptions: { newLine: NewLineKind.LineFeed, module: ModuleKind.CommonJS }, fileName: "input.js", reportDiagnostics: true },
expectedDiagnosticCodes: []
options: { compilerOptions: { newLine: NewLineKind.LineFeed, module: ModuleKind.CommonJS }, fileName: "input.js", reportDiagnostics: true }
});
});
it("Supports urls in file name", () => {
test("var x", { expectedOutput: `"use strict";\r\nvar x;\r\n`, options: { fileName: "http://somewhere/directory//directory2/file.ts" } });
});
describe("String values for enums", () => {
it("Accepts strings instead of enum values", () => {
test(`export const x = 0`, {
options: {
compilerOptions: {
module: <ModuleKind><any>"es6",
// Capitalization and spaces ignored
target: <ScriptTarget><any>" Es6 "
}
},
expectedOutput: "export const x = 0;\r\n"
});
});
it("Fails on bad value", () => {
for (const value in [123, {}, ""]) {
test(``, {
options: { compilerOptions: { module: <ModuleKind><any>value } },
expectedDiagnosticCodes: [6046],
expectedDiagnosticTexts: ["Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015'"]
});
}
});
});
});
}