Merge branch 'master' into remove-jake
This commit is contained in:
Коммит
b103857b23
|
@ -121,6 +121,7 @@ var languageServiceLibrarySources = [
|
|||
|
||||
var harnessCoreSources = [
|
||||
"harness.ts",
|
||||
"virtualFileSystem.ts",
|
||||
"sourceMapRecorder.ts",
|
||||
"harnessLanguageService.ts",
|
||||
"fourslash.ts",
|
||||
|
@ -155,7 +156,8 @@ var harnessSources = harnessCoreSources.concat([
|
|||
"commandLineParsing.ts",
|
||||
"convertCompilerOptionsFromJson.ts",
|
||||
"convertTypingOptionsFromJson.ts",
|
||||
"tsserverProjectSystem.ts"
|
||||
"tsserverProjectSystem.ts",
|
||||
"matchFiles.ts"
|
||||
].map(function (f) {
|
||||
return path.join(unittestsDirectory, f);
|
||||
})).concat([
|
||||
|
|
|
@ -578,12 +578,6 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function isNarrowableReference(expr: Expression): boolean {
|
||||
return expr.kind === SyntaxKind.Identifier ||
|
||||
expr.kind === SyntaxKind.ThisKeyword ||
|
||||
expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((<PropertyAccessExpression>expr).expression);
|
||||
}
|
||||
|
||||
function isNarrowingExpression(expr: Expression): boolean {
|
||||
switch (expr.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
|
@ -591,7 +585,7 @@ namespace ts {
|
|||
case SyntaxKind.PropertyAccessExpression:
|
||||
return isNarrowableReference(expr);
|
||||
case SyntaxKind.CallExpression:
|
||||
return true;
|
||||
return hasNarrowableArgument(<CallExpression>expr);
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
return isNarrowingExpression((<ParenthesizedExpression>expr).expression);
|
||||
case SyntaxKind.BinaryExpression:
|
||||
|
@ -602,6 +596,39 @@ namespace ts {
|
|||
return false;
|
||||
}
|
||||
|
||||
function isNarrowableReference(expr: Expression): boolean {
|
||||
return expr.kind === SyntaxKind.Identifier ||
|
||||
expr.kind === SyntaxKind.ThisKeyword ||
|
||||
expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((<PropertyAccessExpression>expr).expression);
|
||||
}
|
||||
|
||||
function hasNarrowableArgument(expr: CallExpression) {
|
||||
if (expr.arguments) {
|
||||
for (const argument of expr.arguments) {
|
||||
if (isNarrowableReference(argument)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (expr.expression.kind === SyntaxKind.PropertyAccessExpression &&
|
||||
isNarrowableReference((<PropertyAccessExpression>expr.expression).expression)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isNarrowingNullCheckOperands(expr1: Expression, expr2: Expression) {
|
||||
return (expr1.kind === SyntaxKind.NullKeyword || expr1.kind === SyntaxKind.Identifier && (<Identifier>expr1).text === "undefined") && isNarrowableOperand(expr2);
|
||||
}
|
||||
|
||||
function isNarrowingTypeofOperands(expr1: Expression, expr2: Expression) {
|
||||
return expr1.kind === SyntaxKind.TypeOfExpression && isNarrowableOperand((<TypeOfExpression>expr1).expression) && expr2.kind === SyntaxKind.StringLiteral;
|
||||
}
|
||||
|
||||
function isNarrowingDiscriminant(expr: Expression) {
|
||||
return expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((<PropertyAccessExpression>expr).expression);
|
||||
}
|
||||
|
||||
function isNarrowingBinaryExpression(expr: BinaryExpression) {
|
||||
switch (expr.operatorToken.kind) {
|
||||
case SyntaxKind.EqualsToken:
|
||||
|
@ -610,34 +637,35 @@ namespace ts {
|
|||
case SyntaxKind.ExclamationEqualsToken:
|
||||
case SyntaxKind.EqualsEqualsEqualsToken:
|
||||
case SyntaxKind.ExclamationEqualsEqualsToken:
|
||||
if ((isNarrowingExpression(expr.left) && (expr.right.kind === SyntaxKind.NullKeyword || expr.right.kind === SyntaxKind.Identifier)) ||
|
||||
(isNarrowingExpression(expr.right) && (expr.left.kind === SyntaxKind.NullKeyword || expr.left.kind === SyntaxKind.Identifier))) {
|
||||
return true;
|
||||
}
|
||||
if (isTypeOfNarrowingBinaryExpression(expr)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return isNarrowingNullCheckOperands(expr.right, expr.left) || isNarrowingNullCheckOperands(expr.left, expr.right) ||
|
||||
isNarrowingTypeofOperands(expr.right, expr.left) || isNarrowingTypeofOperands(expr.left, expr.right) ||
|
||||
isNarrowingDiscriminant(expr.left) || isNarrowingDiscriminant(expr.right);
|
||||
case SyntaxKind.InstanceOfKeyword:
|
||||
return isNarrowingExpression(expr.left);
|
||||
return isNarrowableOperand(expr.left);
|
||||
case SyntaxKind.CommaToken:
|
||||
return isNarrowingExpression(expr.right);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isTypeOfNarrowingBinaryExpression(expr: BinaryExpression) {
|
||||
let typeOf: Expression;
|
||||
if (expr.left.kind === SyntaxKind.StringLiteral) {
|
||||
typeOf = expr.right;
|
||||
function isNarrowableOperand(expr: Expression): boolean {
|
||||
switch (expr.kind) {
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
return isNarrowableOperand((<ParenthesizedExpression>expr).expression);
|
||||
case SyntaxKind.BinaryExpression:
|
||||
switch ((<BinaryExpression>expr).operatorToken.kind) {
|
||||
case SyntaxKind.EqualsToken:
|
||||
return isNarrowableOperand((<BinaryExpression>expr).left);
|
||||
case SyntaxKind.CommaToken:
|
||||
return isNarrowableOperand((<BinaryExpression>expr).right);
|
||||
}
|
||||
}
|
||||
else if (expr.right.kind === SyntaxKind.StringLiteral) {
|
||||
typeOf = expr.left;
|
||||
}
|
||||
else {
|
||||
typeOf = undefined;
|
||||
}
|
||||
return typeOf && typeOf.kind === SyntaxKind.TypeOfExpression && isNarrowingExpression((<TypeOfExpression>typeOf).expression);
|
||||
return isNarrowableReference(expr);
|
||||
}
|
||||
|
||||
function isNarrowingSwitchStatement(switchStatement: SwitchStatement) {
|
||||
const expr = switchStatement.expression;
|
||||
return expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((<PropertyAccessExpression>expr).expression);
|
||||
}
|
||||
|
||||
function createBranchLabel(): FlowLabel {
|
||||
|
@ -683,8 +711,22 @@ namespace ts {
|
|||
setFlowNodeReferenced(antecedent);
|
||||
return <FlowCondition>{
|
||||
flags,
|
||||
antecedent,
|
||||
expression,
|
||||
antecedent
|
||||
};
|
||||
}
|
||||
|
||||
function createFlowSwitchClause(antecedent: FlowNode, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): FlowNode {
|
||||
if (!isNarrowingSwitchStatement(switchStatement)) {
|
||||
return antecedent;
|
||||
}
|
||||
setFlowNodeReferenced(antecedent);
|
||||
return <FlowSwitchClause>{
|
||||
flags: FlowFlags.SwitchClause,
|
||||
switchStatement,
|
||||
clauseStart,
|
||||
clauseEnd,
|
||||
antecedent
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -913,9 +955,12 @@ namespace ts {
|
|||
preSwitchCaseFlow = currentFlow;
|
||||
bind(node.caseBlock);
|
||||
addAntecedent(postSwitchLabel, currentFlow);
|
||||
const hasNonEmptyDefault = forEach(node.caseBlock.clauses, c => c.kind === SyntaxKind.DefaultClause && c.statements.length);
|
||||
if (!hasNonEmptyDefault) {
|
||||
addAntecedent(postSwitchLabel, preSwitchCaseFlow);
|
||||
const hasDefault = forEach(node.caseBlock.clauses, c => c.kind === SyntaxKind.DefaultClause);
|
||||
// We mark a switch statement as possibly exhaustive if it has no default clause and if all
|
||||
// case clauses have unreachable end points (e.g. they all return).
|
||||
node.possiblyExhaustive = !hasDefault && !postSwitchLabel.antecedents;
|
||||
if (!hasDefault) {
|
||||
addAntecedent(postSwitchLabel, createFlowSwitchClause(preSwitchCaseFlow, node, 0, 0));
|
||||
}
|
||||
currentBreakTarget = saveBreakTarget;
|
||||
preSwitchCaseFlow = savePreSwitchCaseFlow;
|
||||
|
@ -924,25 +969,22 @@ namespace ts {
|
|||
|
||||
function bindCaseBlock(node: CaseBlock): void {
|
||||
const clauses = node.clauses;
|
||||
let fallthroughFlow = unreachableFlow;
|
||||
for (let i = 0; i < clauses.length; i++) {
|
||||
const clause = clauses[i];
|
||||
if (clause.statements.length) {
|
||||
if (currentFlow.flags & FlowFlags.Unreachable) {
|
||||
currentFlow = preSwitchCaseFlow;
|
||||
}
|
||||
else {
|
||||
const preCaseLabel = createBranchLabel();
|
||||
addAntecedent(preCaseLabel, preSwitchCaseFlow);
|
||||
addAntecedent(preCaseLabel, currentFlow);
|
||||
currentFlow = finishFlowLabel(preCaseLabel);
|
||||
}
|
||||
bind(clause);
|
||||
if (!(currentFlow.flags & FlowFlags.Unreachable) && i !== clauses.length - 1 && options.noFallthroughCasesInSwitch) {
|
||||
errorOnFirstToken(clause, Diagnostics.Fallthrough_case_in_switch);
|
||||
}
|
||||
const clauseStart = i;
|
||||
while (!clauses[i].statements.length && i + 1 < clauses.length) {
|
||||
bind(clauses[i]);
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
bind(clause);
|
||||
const preCaseLabel = createBranchLabel();
|
||||
addAntecedent(preCaseLabel, createFlowSwitchClause(preSwitchCaseFlow, <SwitchStatement>node.parent, clauseStart, i + 1));
|
||||
addAntecedent(preCaseLabel, fallthroughFlow);
|
||||
currentFlow = finishFlowLabel(preCaseLabel);
|
||||
const clause = clauses[i];
|
||||
bind(clause);
|
||||
fallthroughFlow = currentFlow;
|
||||
if (!(currentFlow.flags & FlowFlags.Unreachable) && i !== clauses.length - 1 && options.noFallthroughCasesInSwitch) {
|
||||
errorOnFirstToken(clause, Diagnostics.Fallthrough_case_in_switch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -562,7 +562,8 @@ namespace ts {
|
|||
const declarationFile = getSourceFileOfNode(declaration);
|
||||
const useFile = getSourceFileOfNode(usage);
|
||||
if (declarationFile !== useFile) {
|
||||
if (modulekind || (!compilerOptions.outFile && !compilerOptions.out)) {
|
||||
if ((modulekind && (declarationFile.externalModuleIndicator || useFile.externalModuleIndicator)) ||
|
||||
(!compilerOptions.outFile && !compilerOptions.out)) {
|
||||
// nodes are in different files and order cannot be determines
|
||||
return true;
|
||||
}
|
||||
|
@ -852,7 +853,8 @@ namespace ts {
|
|||
|
||||
if (!result) {
|
||||
if (nameNotFoundMessage) {
|
||||
if (!checkAndReportErrorForMissingPrefix(errorLocation, name, nameArg)) {
|
||||
if (!checkAndReportErrorForMissingPrefix(errorLocation, name, nameArg) &&
|
||||
!checkAndReportErrorForExtendingInterface(errorLocation)) {
|
||||
error(errorLocation, nameNotFoundMessage, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg));
|
||||
}
|
||||
}
|
||||
|
@ -936,6 +938,31 @@ namespace ts {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
function checkAndReportErrorForExtendingInterface(errorLocation: Node): boolean {
|
||||
let parentClassExpression = errorLocation;
|
||||
while (parentClassExpression) {
|
||||
const kind = parentClassExpression.kind;
|
||||
if (kind === SyntaxKind.Identifier || kind === SyntaxKind.PropertyAccessExpression) {
|
||||
parentClassExpression = parentClassExpression.parent;
|
||||
continue;
|
||||
}
|
||||
if (kind === SyntaxKind.ExpressionWithTypeArguments) {
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!parentClassExpression) {
|
||||
return false;
|
||||
}
|
||||
const expression = (<ExpressionWithTypeArguments>parentClassExpression).expression;
|
||||
if (resolveEntityName(expression, SymbolFlags.Interface, /*ignoreErrors*/ true)) {
|
||||
error(errorLocation, Diagnostics.Cannot_extend_an_interface_0_Did_you_mean_implements, getTextOfNode(expression));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function checkResolvedBlockScopedVariable(result: Symbol, errorLocation: Node): void {
|
||||
Debug.assert((result.flags & SymbolFlags.BlockScopedVariable) !== 0);
|
||||
// Block-scoped variables cannot be used before their definition
|
||||
|
@ -5185,7 +5212,6 @@ namespace ts {
|
|||
if (hasProperty(stringLiteralTypes, text)) {
|
||||
return stringLiteralTypes[text];
|
||||
}
|
||||
|
||||
const type = stringLiteralTypes[text] = <StringLiteralType>createType(TypeFlags.StringLiteral);
|
||||
type.text = text;
|
||||
return type;
|
||||
|
@ -5650,6 +5676,10 @@ namespace ts {
|
|||
return checkTypeComparableTo(source, target, /*errorNode*/ undefined);
|
||||
}
|
||||
|
||||
function areTypesComparable(type1: Type, type2: Type): boolean {
|
||||
return isTypeComparableTo(type1, type2) || isTypeComparableTo(type2, type1);
|
||||
}
|
||||
|
||||
function checkTypeSubtypeOf(source: Type, target: Type, errorNode: Node, headMessage?: DiagnosticMessage, containingMessageChain?: DiagnosticMessageChain): boolean {
|
||||
return checkTypeRelatedTo(source, target, subtypeRelation, errorNode, headMessage, containingMessageChain);
|
||||
}
|
||||
|
@ -6830,8 +6860,10 @@ namespace ts {
|
|||
return !!getPropertyOfType(type, "0");
|
||||
}
|
||||
|
||||
function isStringLiteralType(type: Type) {
|
||||
return type.flags & TypeFlags.StringLiteral;
|
||||
function isStringLiteralUnionType(type: Type): boolean {
|
||||
return type.flags & TypeFlags.StringLiteral ? true :
|
||||
type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, isStringLiteralUnionType) :
|
||||
false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7696,6 +7728,35 @@ namespace ts {
|
|||
return node;
|
||||
}
|
||||
|
||||
function getTypeOfSwitchClause(clause: CaseClause | DefaultClause) {
|
||||
if (clause.kind === SyntaxKind.CaseClause) {
|
||||
const expr = (<CaseClause>clause).expression;
|
||||
return expr.kind === SyntaxKind.StringLiteral ? getStringLiteralTypeForText((<StringLiteral>expr).text) : checkExpression(expr);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getSwitchClauseTypes(switchStatement: SwitchStatement): Type[] {
|
||||
const links = getNodeLinks(switchStatement);
|
||||
if (!links.switchTypes) {
|
||||
// If all case clauses specify expressions that have unit types, we return an array
|
||||
// of those unit types. Otherwise we return an empty array.
|
||||
const types = map(switchStatement.caseBlock.clauses, getTypeOfSwitchClause);
|
||||
links.switchTypes = forEach(types, t => !t || t.flags & TypeFlags.StringLiteral) ? types : emptyArray;
|
||||
}
|
||||
return links.switchTypes;
|
||||
}
|
||||
|
||||
function eachTypeContainedIn(source: Type, types: Type[]) {
|
||||
return source.flags & TypeFlags.Union ? !forEach((<UnionType>source).types, t => !contains(types, t)) : contains(types, source);
|
||||
}
|
||||
|
||||
function filterType(type: Type, f: (t: Type) => boolean): Type {
|
||||
return type.flags & TypeFlags.Union ?
|
||||
getUnionType(filter((<UnionType>type).types, f)) :
|
||||
f(type) ? type : neverType;
|
||||
}
|
||||
|
||||
function getFlowTypeOfReference(reference: Node, declaredType: Type, assumeInitialized: boolean, includeOuterFunctions: boolean) {
|
||||
let key: string;
|
||||
if (!reference.flowNode || assumeInitialized && !(declaredType.flags & TypeFlags.Narrowable)) {
|
||||
|
@ -7733,6 +7794,9 @@ namespace ts {
|
|||
else if (flow.flags & FlowFlags.Condition) {
|
||||
type = getTypeAtFlowCondition(<FlowCondition>flow);
|
||||
}
|
||||
else if (flow.flags & FlowFlags.SwitchClause) {
|
||||
type = getTypeAtSwitchClause(<FlowSwitchClause>flow);
|
||||
}
|
||||
else if (flow.flags & FlowFlags.Label) {
|
||||
if ((<FlowLabel>flow).antecedents.length === 1) {
|
||||
flow = (<FlowLabel>flow).antecedents[0];
|
||||
|
@ -7816,6 +7880,11 @@ namespace ts {
|
|||
return type;
|
||||
}
|
||||
|
||||
function getTypeAtSwitchClause(flow: FlowSwitchClause) {
|
||||
const type = getTypeAtFlowNode(flow.antecedent);
|
||||
return narrowTypeBySwitchOnDiscriminant(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd);
|
||||
}
|
||||
|
||||
function getTypeAtFlowBranchLabel(flow: FlowLabel) {
|
||||
const antecedentTypes: Type[] = [];
|
||||
for (const antecedent of flow.antecedents) {
|
||||
|
@ -7895,12 +7964,26 @@ namespace ts {
|
|||
case SyntaxKind.ExclamationEqualsToken:
|
||||
case SyntaxKind.EqualsEqualsEqualsToken:
|
||||
case SyntaxKind.ExclamationEqualsEqualsToken:
|
||||
if (isNullOrUndefinedLiteral(expr.left) || isNullOrUndefinedLiteral(expr.right)) {
|
||||
return narrowTypeByNullCheck(type, expr, assumeTrue);
|
||||
const left = expr.left;
|
||||
const operator = expr.operatorToken.kind;
|
||||
const right = expr.right;
|
||||
if (isNullOrUndefinedLiteral(right)) {
|
||||
return narrowTypeByNullCheck(type, left, operator, right, assumeTrue);
|
||||
}
|
||||
if (expr.left.kind === SyntaxKind.TypeOfExpression && expr.right.kind === SyntaxKind.StringLiteral ||
|
||||
expr.left.kind === SyntaxKind.StringLiteral && expr.right.kind === SyntaxKind.TypeOfExpression) {
|
||||
return narrowTypeByTypeof(type, expr, assumeTrue);
|
||||
if (isNullOrUndefinedLiteral(left)) {
|
||||
return narrowTypeByNullCheck(type, right, operator, left, assumeTrue);
|
||||
}
|
||||
if (left.kind === SyntaxKind.TypeOfExpression && right.kind === SyntaxKind.StringLiteral) {
|
||||
return narrowTypeByTypeof(type, <TypeOfExpression>left, operator, <LiteralExpression>right, assumeTrue);
|
||||
}
|
||||
if (right.kind === SyntaxKind.TypeOfExpression && left.kind === SyntaxKind.StringLiteral) {
|
||||
return narrowTypeByTypeof(type, <TypeOfExpression>right, operator, <LiteralExpression>left, assumeTrue);
|
||||
}
|
||||
if (left.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
return narrowTypeByDiscriminant(type, <PropertyAccessExpression>left, operator, right, assumeTrue);
|
||||
}
|
||||
if (right.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
return narrowTypeByDiscriminant(type, <PropertyAccessExpression>right, operator, left, assumeTrue);
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.InstanceOfKeyword:
|
||||
|
@ -7911,41 +7994,35 @@ namespace ts {
|
|||
return type;
|
||||
}
|
||||
|
||||
function narrowTypeByNullCheck(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
|
||||
// We have '==', '!=', '===', or '!==' operator with 'null' or 'undefined' on one side
|
||||
const operator = expr.operatorToken.kind;
|
||||
const nullLike = isNullOrUndefinedLiteral(expr.left) ? expr.left : expr.right;
|
||||
const narrowed = isNullOrUndefinedLiteral(expr.left) ? expr.right : expr.left;
|
||||
function narrowTypeByNullCheck(type: Type, target: Expression, operator: SyntaxKind, literal: Expression, assumeTrue: boolean): Type {
|
||||
// We have '==', '!=', '===', or '!==' operator with 'null' or 'undefined' as value
|
||||
if (operator === SyntaxKind.ExclamationEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) {
|
||||
assumeTrue = !assumeTrue;
|
||||
}
|
||||
if (!strictNullChecks || !isMatchingReference(reference, getReferenceFromExpression(narrowed))) {
|
||||
if (!strictNullChecks || !isMatchingReference(reference, getReferenceFromExpression(target))) {
|
||||
return type;
|
||||
}
|
||||
const doubleEquals = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken;
|
||||
const facts = doubleEquals ?
|
||||
assumeTrue ? TypeFacts.EQUndefinedOrNull : TypeFacts.NEUndefinedOrNull :
|
||||
nullLike.kind === SyntaxKind.NullKeyword ?
|
||||
literal.kind === SyntaxKind.NullKeyword ?
|
||||
assumeTrue ? TypeFacts.EQNull : TypeFacts.NENull :
|
||||
assumeTrue ? TypeFacts.EQUndefined : TypeFacts.NEUndefined;
|
||||
return getTypeWithFacts(type, facts);
|
||||
}
|
||||
|
||||
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 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, narrowed)) {
|
||||
function narrowTypeByTypeof(type: Type, typeOfExpr: TypeOfExpression, operator: SyntaxKind, literal: LiteralExpression, assumeTrue: boolean): Type {
|
||||
// We have '==', '!=', '====', or !==' operator with 'typeof xxx' and string literal operands
|
||||
const target = getReferenceFromExpression(typeOfExpr.expression);
|
||||
if (!isMatchingReference(reference, target)) {
|
||||
// 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, narrowed)) {
|
||||
if (containsMatchingReference(reference, target)) {
|
||||
return declaredType;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
if (expr.operatorToken.kind === SyntaxKind.ExclamationEqualsToken ||
|
||||
expr.operatorToken.kind === SyntaxKind.ExclamationEqualsEqualsToken) {
|
||||
if (operator === SyntaxKind.ExclamationEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) {
|
||||
assumeTrue = !assumeTrue;
|
||||
}
|
||||
if (assumeTrue && !(type.flags & TypeFlags.Union)) {
|
||||
|
@ -7963,6 +8040,58 @@ namespace ts {
|
|||
return getTypeWithFacts(type, facts);
|
||||
}
|
||||
|
||||
function narrowTypeByDiscriminant(type: Type, propAccess: PropertyAccessExpression, operator: SyntaxKind, value: Expression, assumeTrue: boolean): Type {
|
||||
// We have '==', '!=', '===', or '!==' operator with property access as target
|
||||
if (!isMatchingReference(reference, propAccess.expression)) {
|
||||
return type;
|
||||
}
|
||||
const propName = propAccess.name.text;
|
||||
const propType = getTypeOfPropertyOfType(type, propName);
|
||||
if (!propType || !isStringLiteralUnionType(propType)) {
|
||||
return type;
|
||||
}
|
||||
const discriminantType = value.kind === SyntaxKind.StringLiteral ? getStringLiteralTypeForText((<StringLiteral>value).text) : checkExpression(value);
|
||||
if (!isStringLiteralUnionType(discriminantType)) {
|
||||
return type;
|
||||
}
|
||||
if (operator === SyntaxKind.ExclamationEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) {
|
||||
assumeTrue = !assumeTrue;
|
||||
}
|
||||
if (assumeTrue) {
|
||||
return filterType(type, t => areTypesComparable(getTypeOfPropertyOfType(t, propName), discriminantType));
|
||||
}
|
||||
if (discriminantType.flags & TypeFlags.StringLiteral) {
|
||||
return filterType(type, t => getTypeOfPropertyOfType(t, propName) !== discriminantType);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
function narrowTypeBySwitchOnDiscriminant(type: Type, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number) {
|
||||
// We have switch statement with property access expression
|
||||
if (!isMatchingReference(reference, (<PropertyAccessExpression>switchStatement.expression).expression)) {
|
||||
return type;
|
||||
}
|
||||
const propName = (<PropertyAccessExpression>switchStatement.expression).name.text;
|
||||
const propType = getTypeOfPropertyOfType(type, propName);
|
||||
if (!propType || !isStringLiteralUnionType(propType)) {
|
||||
return type;
|
||||
}
|
||||
const switchTypes = getSwitchClauseTypes(switchStatement);
|
||||
if (!switchTypes.length) {
|
||||
return type;
|
||||
}
|
||||
const clauseTypes = switchTypes.slice(clauseStart, clauseEnd);
|
||||
const hasDefaultClause = clauseStart === clauseEnd || contains(clauseTypes, undefined);
|
||||
const caseTypes = hasDefaultClause ? filter(clauseTypes, t => !!t) : clauseTypes;
|
||||
const discriminantType = caseTypes.length ? getUnionType(caseTypes) : undefined;
|
||||
const caseType = discriminantType && filterType(type, t => isTypeComparableTo(discriminantType, getTypeOfPropertyOfType(t, propName)));
|
||||
if (!hasDefaultClause) {
|
||||
return caseType;
|
||||
}
|
||||
const defaultType = filterType(type, t => !eachTypeContainedIn(getTypeOfPropertyOfType(t, propName), switchTypes));
|
||||
return caseType ? getUnionType([caseType, defaultType]) : defaultType;
|
||||
}
|
||||
|
||||
function narrowTypeByInstanceof(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
|
||||
const left = getReferenceFromExpression(expr.left);
|
||||
if (!isMatchingReference(reference, left)) {
|
||||
|
@ -8933,10 +9062,6 @@ namespace ts {
|
|||
return applyToContextualType(type, t => getIndexTypeOfStructuredType(t, kind));
|
||||
}
|
||||
|
||||
function contextualTypeIsStringLiteralType(type: Type): boolean {
|
||||
return !!(type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, isStringLiteralType) : isStringLiteralType(type));
|
||||
}
|
||||
|
||||
// Return true if the given contextual type is a tuple-like type
|
||||
function contextualTypeIsTupleLikeType(type: Type): boolean {
|
||||
return !!(type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, isTupleLikeType) : isTupleLikeType(type));
|
||||
|
@ -10038,7 +10163,7 @@ namespace ts {
|
|||
}
|
||||
const prop = getPropertyOfType(apparentType, right.text);
|
||||
if (!prop) {
|
||||
if (right.text) {
|
||||
if (right.text && !checkAndReportErrorForExtendingInterface(node)) {
|
||||
error(right, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(right), typeToString(type.flags & TypeFlags.ThisType ? apparentType : type));
|
||||
}
|
||||
return unknownType;
|
||||
|
@ -11524,7 +11649,10 @@ namespace ts {
|
|||
|
||||
function checkAssertion(node: AssertionExpression) {
|
||||
const exprType = getRegularTypeOfObjectLiteral(checkExpression(node.expression));
|
||||
|
||||
checkSourceElement(node.type);
|
||||
const targetType = getTypeFromTypeNode(node.type);
|
||||
|
||||
if (produceDiagnostics && targetType !== unknownType) {
|
||||
const widenedType = getWidenedType(exprType);
|
||||
if (!isTypeComparableTo(targetType, widenedType)) {
|
||||
|
@ -11764,10 +11892,42 @@ namespace ts {
|
|||
return aggregatedTypes;
|
||||
}
|
||||
|
||||
function isExhaustiveSwitchStatement(node: SwitchStatement): boolean {
|
||||
const expr = node.expression;
|
||||
if (!node.possiblyExhaustive || expr.kind !== SyntaxKind.PropertyAccessExpression) {
|
||||
return false;
|
||||
}
|
||||
const type = checkExpression((<PropertyAccessExpression>expr).expression);
|
||||
if (!(type.flags & TypeFlags.Union)) {
|
||||
return false;
|
||||
}
|
||||
const propName = (<PropertyAccessExpression>expr).name.text;
|
||||
const propType = getTypeOfPropertyOfType(type, propName);
|
||||
if (!propType || !isStringLiteralUnionType(propType)) {
|
||||
return false;
|
||||
}
|
||||
const switchTypes = getSwitchClauseTypes(node);
|
||||
if (!switchTypes.length) {
|
||||
return false;
|
||||
}
|
||||
return eachTypeContainedIn(propType, switchTypes);
|
||||
}
|
||||
|
||||
function functionHasImplicitReturn(func: FunctionLikeDeclaration) {
|
||||
if (!(func.flags & NodeFlags.HasImplicitReturn)) {
|
||||
return false;
|
||||
}
|
||||
const lastStatement = lastOrUndefined((<Block>func.body).statements);
|
||||
if (lastStatement && lastStatement.kind === SyntaxKind.SwitchStatement && isExhaustiveSwitchStatement(<SwitchStatement>lastStatement)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkAndAggregateReturnExpressionTypes(func: FunctionLikeDeclaration, contextualMapper: TypeMapper): Type[] {
|
||||
const isAsync = isAsyncFunctionLike(func);
|
||||
const aggregatedTypes: Type[] = [];
|
||||
let hasReturnWithNoExpression = !!(func.flags & NodeFlags.HasImplicitReturn);
|
||||
let hasReturnWithNoExpression = functionHasImplicitReturn(func);
|
||||
let hasReturnOfTypeNever = false;
|
||||
forEachReturnStatement(<Block>func.body, returnStatement => {
|
||||
const expr = returnStatement.expression;
|
||||
|
@ -11824,7 +11984,7 @@ namespace ts {
|
|||
|
||||
// If all we have is a function signature, or an arrow function with an expression body, then there is nothing to check.
|
||||
// also if HasImplicitReturn flag is not set this means that all codepaths in function body end with return or throw
|
||||
if (nodeIsMissing(func.body) || func.body.kind !== SyntaxKind.Block || !(func.flags & NodeFlags.HasImplicitReturn)) {
|
||||
if (nodeIsMissing(func.body) || func.body.kind !== SyntaxKind.Block || !functionHasImplicitReturn(func)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -12602,7 +12762,7 @@ namespace ts {
|
|||
|
||||
function checkStringLiteralExpression(node: StringLiteral): Type {
|
||||
const contextualType = getContextualType(node);
|
||||
if (contextualType && contextualTypeIsStringLiteralType(contextualType)) {
|
||||
if (contextualType && isStringLiteralUnionType(contextualType)) {
|
||||
return getStringLiteralTypeForText(node.text);
|
||||
}
|
||||
|
||||
|
@ -13559,9 +13719,6 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
// when checking exported function declarations across modules check only duplicate implementations
|
||||
// names and consistency of modifiers are verified when we check local symbol
|
||||
const isExportSymbolInsideModule = symbol.parent && symbol.parent.flags & SymbolFlags.Module;
|
||||
let duplicateFunctionDeclaration = false;
|
||||
let multipleConstructorImplementation = false;
|
||||
for (const current of declarations) {
|
||||
|
@ -13594,7 +13751,7 @@ namespace ts {
|
|||
duplicateFunctionDeclaration = true;
|
||||
}
|
||||
}
|
||||
else if (!isExportSymbolInsideModule && previousDeclaration && previousDeclaration.parent === node.parent && previousDeclaration.end !== node.pos) {
|
||||
else if (previousDeclaration && previousDeclaration.parent === node.parent && previousDeclaration.end !== node.pos) {
|
||||
reportImplementationExpectedError(previousDeclaration);
|
||||
}
|
||||
|
||||
|
@ -13628,7 +13785,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
// Abstract methods can't have an implementation -- in particular, they don't need one.
|
||||
if (!isExportSymbolInsideModule && lastSeenNonAmbientDeclaration && !lastSeenNonAmbientDeclaration.body &&
|
||||
if (lastSeenNonAmbientDeclaration && !lastSeenNonAmbientDeclaration.body &&
|
||||
!(lastSeenNonAmbientDeclaration.flags & NodeFlags.Abstract) && !lastSeenNonAmbientDeclaration.questionToken) {
|
||||
reportImplementationExpectedError(lastSeenNonAmbientDeclaration);
|
||||
}
|
||||
|
|
|
@ -412,6 +412,10 @@ namespace ts {
|
|||
},
|
||||
description: Diagnostics.Specify_library_files_to_be_included_in_the_compilation_Colon
|
||||
},
|
||||
{
|
||||
name: "disableProjectSizeLimit",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "strictNullChecks",
|
||||
type: "boolean",
|
||||
|
@ -682,7 +686,7 @@ namespace ts {
|
|||
|
||||
// Skip over any minified JavaScript files (ending in ".min.js")
|
||||
// Skip over dotted files and folders as well
|
||||
const IgnoreFileNamePattern = /(\.min\.js$)|([\\/]\.[\w.])/;
|
||||
const ignoreFileNamePattern = /(\.min\.js$)|([\\/]\.[\w.])/;
|
||||
/**
|
||||
* Parse the contents of a config file (tsconfig.json).
|
||||
* @param json The contents of the config file to parse
|
||||
|
@ -698,78 +702,66 @@ namespace ts {
|
|||
|
||||
options.configFilePath = configFileName;
|
||||
|
||||
const fileNames = getFileNames(errors);
|
||||
const { fileNames, wildcardDirectories } = getFileNames(errors);
|
||||
|
||||
return {
|
||||
options,
|
||||
fileNames,
|
||||
typingOptions,
|
||||
raw: json,
|
||||
errors
|
||||
errors,
|
||||
wildcardDirectories
|
||||
};
|
||||
|
||||
function getFileNames(errors: Diagnostic[]): string[] {
|
||||
let fileNames: string[] = [];
|
||||
function getFileNames(errors: Diagnostic[]): ExpandResult {
|
||||
let fileNames: string[];
|
||||
if (hasProperty(json, "files")) {
|
||||
if (isArray(json["files"])) {
|
||||
fileNames = map(<string[]>json["files"], s => combinePaths(basePath, s));
|
||||
fileNames = <string[]>json["files"];
|
||||
}
|
||||
else {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "files", "Array"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
const filesSeen: Map<boolean> = {};
|
||||
|
||||
let exclude: string[] = [];
|
||||
if (isArray(json["exclude"])) {
|
||||
exclude = json["exclude"];
|
||||
let includeSpecs: string[];
|
||||
if (hasProperty(json, "include")) {
|
||||
if (isArray(json["include"])) {
|
||||
includeSpecs = <string[]>json["include"];
|
||||
}
|
||||
else {
|
||||
// by default exclude node_modules, and any specificied output directory
|
||||
exclude = ["node_modules", "bower_components", "jspm_packages"];
|
||||
}
|
||||
const outDir = json["compilerOptions"] && json["compilerOptions"]["outDir"];
|
||||
if (outDir) {
|
||||
exclude.push(outDir);
|
||||
}
|
||||
exclude = map(exclude, e => getNormalizedAbsolutePath(e, basePath));
|
||||
|
||||
const supportedExtensions = getSupportedExtensions(options);
|
||||
Debug.assert(indexOf(supportedExtensions, ".ts") < indexOf(supportedExtensions, ".d.ts"), "Changed priority of extensions to pick");
|
||||
|
||||
// Get files of supported extensions in their order of resolution
|
||||
for (const extension of supportedExtensions) {
|
||||
const filesInDirWithExtension = host.readDirectory(basePath, extension, exclude);
|
||||
for (const fileName of filesInDirWithExtension) {
|
||||
// .ts extension would read the .d.ts extension files too but since .d.ts is lower priority extension,
|
||||
// lets pick them when its turn comes up
|
||||
if (extension === ".ts" && fileExtensionIs(fileName, ".d.ts")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IgnoreFileNamePattern.test(fileName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this is one of the output extension (which would be .d.ts and .js if we are allowing compilation of js files)
|
||||
// do not include this file if we included .ts or .tsx file with same base name as it could be output of the earlier compilation
|
||||
if (extension === ".d.ts" || (options.allowJs && contains(supportedJavascriptExtensions, extension))) {
|
||||
const baseName = fileName.substr(0, fileName.length - extension.length);
|
||||
if (hasProperty(filesSeen, baseName + ".ts") || hasProperty(filesSeen, baseName + ".tsx")) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
filesSeen[fileName] = true;
|
||||
fileNames.push(fileName);
|
||||
}
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "include", "Array"));
|
||||
}
|
||||
}
|
||||
if (hasProperty(json, "excludes") && !hasProperty(json, "exclude")) {
|
||||
|
||||
let excludeSpecs: string[];
|
||||
if (hasProperty(json, "exclude")) {
|
||||
if (isArray(json["exclude"])) {
|
||||
excludeSpecs = <string[]>json["exclude"];
|
||||
}
|
||||
else {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "exclude", "Array"));
|
||||
}
|
||||
}
|
||||
else if (hasProperty(json, "excludes")) {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Unknown_option_excludes_Did_you_mean_exclude));
|
||||
}
|
||||
return fileNames;
|
||||
else {
|
||||
// By default, exclude common package folders
|
||||
excludeSpecs = ["node_modules", "bower_components", "jspm_packages"];
|
||||
}
|
||||
|
||||
// Always exclude the output directory unless explicitly included
|
||||
const outDir = json["compilerOptions"] && json["compilerOptions"]["outDir"];
|
||||
if (outDir) {
|
||||
excludeSpecs.push(outDir);
|
||||
}
|
||||
|
||||
if (fileNames === undefined && includeSpecs === undefined) {
|
||||
includeSpecs = ["**/*"];
|
||||
}
|
||||
|
||||
return matchFileNames(fileNames, includeSpecs, excludeSpecs, basePath, options, host, errors);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -865,4 +857,296 @@ namespace ts {
|
|||
function trimString(s: string) {
|
||||
return typeof s.trim === "function" ? s.trim() : s.replace(/^[\s]+|[\s]+$/g, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for a path that ends in a recursive directory wildcard.
|
||||
* Matches **, \**, **\, and \**\, but not a**b.
|
||||
*
|
||||
* NOTE: used \ in place of / above to avoid issues with multiline comments.
|
||||
*
|
||||
* Breakdown:
|
||||
* (^|\/) # matches either the beginning of the string or a directory separator.
|
||||
* \*\* # matches the recursive directory wildcard "**".
|
||||
* \/?$ # matches an optional trailing directory separator at the end of the string.
|
||||
*/
|
||||
const invalidTrailingRecursionPattern = /(^|\/)\*\*\/?$/;
|
||||
|
||||
/**
|
||||
* Tests for a path with multiple recursive directory wildcards.
|
||||
* Matches **\** and **\a\**, but not **\a**b.
|
||||
*
|
||||
* NOTE: used \ in place of / above to avoid issues with multiline comments.
|
||||
*
|
||||
* Breakdown:
|
||||
* (^|\/) # matches either the beginning of the string or a directory separator.
|
||||
* \*\*\/ # matches a recursive directory wildcard "**" followed by a directory separator.
|
||||
* (.*\/)? # optionally matches any number of characters followed by a directory separator.
|
||||
* \*\* # matches a recursive directory wildcard "**"
|
||||
* ($|\/) # matches either the end of the string or a directory separator.
|
||||
*/
|
||||
const invalidMultipleRecursionPatterns = /(^|\/)\*\*\/(.*\/)?\*\*($|\/)/;
|
||||
|
||||
/**
|
||||
* Tests for a path containing a wildcard character in a directory component of the path.
|
||||
* Matches \*\, \?\, and \a*b\, but not \a\ or \a\*.
|
||||
*
|
||||
* NOTE: used \ in place of / above to avoid issues with multiline comments.
|
||||
*
|
||||
* Breakdown:
|
||||
* \/ # matches a directory separator.
|
||||
* [^/]*? # matches any number of characters excluding directory separators (non-greedy).
|
||||
* [*?] # matches either a wildcard character (* or ?)
|
||||
* [^/]* # matches any number of characters excluding directory separators (greedy).
|
||||
* \/ # matches a directory separator.
|
||||
*/
|
||||
const watchRecursivePattern = /\/[^/]*?[*?][^/]*\//;
|
||||
|
||||
/**
|
||||
* Matches the portion of a wildcard path that does not contain wildcards.
|
||||
* Matches \a of \a\*, or \a\b\c of \a\b\c\?\d.
|
||||
*
|
||||
* NOTE: used \ in place of / above to avoid issues with multiline comments.
|
||||
*
|
||||
* Breakdown:
|
||||
* ^ # matches the beginning of the string
|
||||
* [^*?]* # matches any number of non-wildcard characters
|
||||
* (?=\/[^/]*[*?]) # lookahead that matches a directory separator followed by
|
||||
* # a path component that contains at least one wildcard character (* or ?).
|
||||
*/
|
||||
const wildcardDirectoryPattern = /^[^*?]*(?=\/[^/]*[*?])/;
|
||||
|
||||
/**
|
||||
* Expands an array of file specifications.
|
||||
*
|
||||
* @param fileNames The literal file names to include.
|
||||
* @param include The wildcard file specifications to include.
|
||||
* @param exclude The wildcard file specifications to exclude.
|
||||
* @param basePath The base path for any relative file specifications.
|
||||
* @param options Compiler options.
|
||||
* @param host The host used to resolve files and directories.
|
||||
* @param errors An array for diagnostic reporting.
|
||||
*/
|
||||
function matchFileNames(fileNames: string[], include: string[], exclude: string[], basePath: string, options: CompilerOptions, host: ParseConfigHost, errors: Diagnostic[]): ExpandResult {
|
||||
basePath = normalizePath(basePath);
|
||||
|
||||
// The exclude spec list is converted into a regular expression, which allows us to quickly
|
||||
// test whether a file or directory should be excluded before recursively traversing the
|
||||
// file system.
|
||||
const keyMapper = host.useCaseSensitiveFileNames ? caseSensitiveKeyMapper : caseInsensitiveKeyMapper;
|
||||
|
||||
// Literal file names (provided via the "files" array in tsconfig.json) are stored in a
|
||||
// file map with a possibly case insensitive key. We use this map later when when including
|
||||
// wildcard paths.
|
||||
const literalFileMap: Map<string> = {};
|
||||
|
||||
// Wildcard paths (provided via the "includes" array in tsconfig.json) are stored in a
|
||||
// file map with a possibly case insensitive key. We use this map to store paths matched
|
||||
// via wildcard, and to handle extension priority.
|
||||
const wildcardFileMap: Map<string> = {};
|
||||
|
||||
if (include) {
|
||||
include = validateSpecs(include, errors, /*allowTrailingRecursion*/ false);
|
||||
}
|
||||
|
||||
if (exclude) {
|
||||
exclude = validateSpecs(exclude, errors, /*allowTrailingRecursion*/ true);
|
||||
}
|
||||
|
||||
// Wildcard directories (provided as part of a wildcard path) are stored in a
|
||||
// file map that marks whether it was a regular wildcard match (with a `*` or `?` token),
|
||||
// or a recursive directory. This information is used by filesystem watchers to monitor for
|
||||
// new entries in these paths.
|
||||
const wildcardDirectories: Map<WatchDirectoryFlags> = getWildcardDirectories(include, exclude, basePath, host.useCaseSensitiveFileNames);
|
||||
|
||||
// Rather than requery this for each file and filespec, we query the supported extensions
|
||||
// once and store it on the expansion context.
|
||||
const supportedExtensions = getSupportedExtensions(options);
|
||||
|
||||
// Literal files are always included verbatim. An "include" or "exclude" specification cannot
|
||||
// remove a literal file.
|
||||
if (fileNames) {
|
||||
for (const fileName of fileNames) {
|
||||
const file = combinePaths(basePath, fileName);
|
||||
literalFileMap[keyMapper(file)] = file;
|
||||
}
|
||||
}
|
||||
|
||||
if (include && include.length > 0) {
|
||||
for (const file of host.readDirectory(basePath, supportedExtensions, exclude, include)) {
|
||||
// If we have already included a literal or wildcard path with a
|
||||
// higher priority extension, we should skip this file.
|
||||
//
|
||||
// This handles cases where we may encounter both <file>.ts and
|
||||
// <file>.d.ts (or <file>.js if "allowJs" is enabled) in the same
|
||||
// directory when they are compilation outputs.
|
||||
if (hasFileWithHigherPriorityExtension(file, literalFileMap, wildcardFileMap, supportedExtensions, keyMapper)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ignoreFileNamePattern.test(file)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We may have included a wildcard path with a lower priority
|
||||
// extension due to the user-defined order of entries in the
|
||||
// "include" array. If there is a lower priority extension in the
|
||||
// same directory, we should remove it.
|
||||
removeWildcardFilesWithLowerPriorityExtension(file, wildcardFileMap, supportedExtensions, keyMapper);
|
||||
|
||||
const key = keyMapper(file);
|
||||
if (!hasProperty(literalFileMap, key) && !hasProperty(wildcardFileMap, key)) {
|
||||
wildcardFileMap[key] = file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const literalFiles = reduceProperties(literalFileMap, addFileToOutput, []);
|
||||
const wildcardFiles = reduceProperties(wildcardFileMap, addFileToOutput, []);
|
||||
wildcardFiles.sort(host.useCaseSensitiveFileNames ? compareStrings : compareStringsCaseInsensitive);
|
||||
return {
|
||||
fileNames: literalFiles.concat(wildcardFiles),
|
||||
wildcardDirectories
|
||||
};
|
||||
}
|
||||
|
||||
function validateSpecs(specs: string[], errors: Diagnostic[], allowTrailingRecursion: boolean) {
|
||||
const validSpecs: string[] = [];
|
||||
for (const spec of specs) {
|
||||
if (!allowTrailingRecursion && invalidTrailingRecursionPattern.test(spec)) {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec));
|
||||
}
|
||||
else if (invalidMultipleRecursionPatterns.test(spec)) {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, spec));
|
||||
}
|
||||
else {
|
||||
validSpecs.push(spec);
|
||||
}
|
||||
}
|
||||
|
||||
return validSpecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets directories in a set of include patterns that should be watched for changes.
|
||||
*/
|
||||
function getWildcardDirectories(include: string[], exclude: string[], path: string, useCaseSensitiveFileNames: boolean) {
|
||||
// We watch a directory recursively if it contains a wildcard anywhere in a directory segment
|
||||
// of the pattern:
|
||||
//
|
||||
// /a/b/**/d - Watch /a/b recursively to catch changes to any d in any subfolder recursively
|
||||
// /a/b/*/d - Watch /a/b recursively to catch any d in any immediate subfolder, even if a new subfolder is added
|
||||
//
|
||||
// We watch a directory without recursion if it contains a wildcard in the file segment of
|
||||
// the pattern:
|
||||
//
|
||||
// /a/b/* - Watch /a/b directly to catch any new file
|
||||
// /a/b/a?z - Watch /a/b directly to catch any new file matching a?z
|
||||
const rawExcludeRegex = getRegularExpressionForWildcard(exclude, path, "exclude");
|
||||
const excludeRegex = rawExcludeRegex && new RegExp(rawExcludeRegex, useCaseSensitiveFileNames ? "" : "i");
|
||||
const wildcardDirectories: Map<WatchDirectoryFlags> = {};
|
||||
if (include !== undefined) {
|
||||
const recursiveKeys: string[] = [];
|
||||
for (const file of include) {
|
||||
const name = combinePaths(path, file);
|
||||
if (excludeRegex && excludeRegex.test(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const match = wildcardDirectoryPattern.exec(name);
|
||||
if (match) {
|
||||
const key = useCaseSensitiveFileNames ? match[0] : match[0].toLowerCase();
|
||||
const flags = watchRecursivePattern.test(name) ? WatchDirectoryFlags.Recursive : WatchDirectoryFlags.None;
|
||||
const existingFlags = getProperty(wildcardDirectories, key);
|
||||
if (existingFlags === undefined || existingFlags < flags) {
|
||||
wildcardDirectories[key] = flags;
|
||||
if (flags === WatchDirectoryFlags.Recursive) {
|
||||
recursiveKeys.push(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove any subpaths under an existing recursively watched directory.
|
||||
for (const key in wildcardDirectories) {
|
||||
if (hasProperty(wildcardDirectories, key)) {
|
||||
for (const recursiveKey of recursiveKeys) {
|
||||
if (key !== recursiveKey && containsPath(recursiveKey, key, path, !useCaseSensitiveFileNames)) {
|
||||
delete wildcardDirectories[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return wildcardDirectories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a literal or wildcard file has already been included that has a higher
|
||||
* extension priority.
|
||||
*
|
||||
* @param file The path to the file.
|
||||
* @param extensionPriority The priority of the extension.
|
||||
* @param context The expansion context.
|
||||
*/
|
||||
function hasFileWithHigherPriorityExtension(file: string, literalFiles: Map<string>, wildcardFiles: Map<string>, extensions: string[], keyMapper: (value: string) => string) {
|
||||
const extensionPriority = getExtensionPriority(file, extensions);
|
||||
const adjustedExtensionPriority = adjustExtensionPriority(extensionPriority);
|
||||
for (let i = ExtensionPriority.Highest; i < adjustedExtensionPriority; i++) {
|
||||
const higherPriorityExtension = extensions[i];
|
||||
const higherPriorityPath = keyMapper(changeExtension(file, higherPriorityExtension));
|
||||
if (hasProperty(literalFiles, higherPriorityPath) || hasProperty(wildcardFiles, higherPriorityPath)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes files included via wildcard expansion with a lower extension priority that have
|
||||
* already been included.
|
||||
*
|
||||
* @param file The path to the file.
|
||||
* @param extensionPriority The priority of the extension.
|
||||
* @param context The expansion context.
|
||||
*/
|
||||
function removeWildcardFilesWithLowerPriorityExtension(file: string, wildcardFiles: Map<string>, extensions: string[], keyMapper: (value: string) => string) {
|
||||
const extensionPriority = getExtensionPriority(file, extensions);
|
||||
const nextExtensionPriority = getNextLowestExtensionPriority(extensionPriority);
|
||||
for (let i = nextExtensionPriority; i < extensions.length; i++) {
|
||||
const lowerPriorityExtension = extensions[i];
|
||||
const lowerPriorityPath = keyMapper(changeExtension(file, lowerPriorityExtension));
|
||||
delete wildcardFiles[lowerPriorityPath];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a file to an array of files.
|
||||
*
|
||||
* @param output The output array.
|
||||
* @param file The file path.
|
||||
*/
|
||||
function addFileToOutput(output: string[], file: string) {
|
||||
output.push(file);
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a case sensitive key.
|
||||
*
|
||||
* @param key The original key.
|
||||
*/
|
||||
function caseSensitiveKeyMapper(key: string) {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a case insensitive key.
|
||||
*
|
||||
* @param key The original key.
|
||||
*/
|
||||
function caseInsensitiveKeyMapper(key: string) {
|
||||
return key.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace ts {
|
|||
contains,
|
||||
remove,
|
||||
forEachValue: forEachValueInMap,
|
||||
clear
|
||||
clear,
|
||||
};
|
||||
|
||||
function forEachValueInMap(f: (key: Path, value: T) => void) {
|
||||
|
@ -113,6 +113,15 @@ namespace ts {
|
|||
return -1;
|
||||
}
|
||||
|
||||
export function indexOfAnyCharCode(text: string, charCodes: number[], start?: number): number {
|
||||
for (let i = start || 0, len = text.length; i < len; i++) {
|
||||
if (contains(charCodes, text.charCodeAt(i))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
export function countWhere<T>(array: T[], predicate: (x: T) => boolean): number {
|
||||
let count = 0;
|
||||
if (array) {
|
||||
|
@ -138,6 +147,17 @@ namespace ts {
|
|||
return result;
|
||||
}
|
||||
|
||||
export function filterMutate<T>(array: T[], f: (x: T) => boolean): void {
|
||||
let outIndex = 0;
|
||||
for (const item of array) {
|
||||
if (f(item)) {
|
||||
array[outIndex] = item;
|
||||
outIndex++;
|
||||
}
|
||||
}
|
||||
array.length = outIndex;
|
||||
}
|
||||
|
||||
export function map<T, U>(array: T[], f: (x: T) => U): U[] {
|
||||
let result: U[];
|
||||
if (array) {
|
||||
|
@ -523,6 +543,28 @@ namespace ts {
|
|||
return a < b ? Comparison.LessThan : Comparison.GreaterThan;
|
||||
}
|
||||
|
||||
export function compareStrings(a: string, b: string, ignoreCase?: boolean): Comparison {
|
||||
if (a === b) return Comparison.EqualTo;
|
||||
if (a === undefined) return Comparison.LessThan;
|
||||
if (b === undefined) return Comparison.GreaterThan;
|
||||
if (ignoreCase) {
|
||||
if (String.prototype.localeCompare) {
|
||||
const result = a.localeCompare(b, /*locales*/ undefined, { usage: "sort", sensitivity: "accent" });
|
||||
return result < 0 ? Comparison.LessThan : result > 0 ? Comparison.GreaterThan : Comparison.EqualTo;
|
||||
}
|
||||
|
||||
a = a.toUpperCase();
|
||||
b = b.toUpperCase();
|
||||
if (a === b) return Comparison.EqualTo;
|
||||
}
|
||||
|
||||
return a < b ? Comparison.LessThan : Comparison.GreaterThan;
|
||||
}
|
||||
|
||||
export function compareStringsCaseInsensitive(a: string, b: string) {
|
||||
return compareStrings(a, b, /*ignoreCase*/ true);
|
||||
}
|
||||
|
||||
function getDiagnosticFileName(diagnostic: Diagnostic): string {
|
||||
return diagnostic.file ? diagnostic.file.fileName : undefined;
|
||||
}
|
||||
|
@ -792,12 +834,275 @@ namespace ts {
|
|||
return path1 + directorySeparator + path2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a trailing directory separator from a path.
|
||||
* @param path The path.
|
||||
*/
|
||||
export function removeTrailingDirectorySeparator(path: string) {
|
||||
if (path.charAt(path.length - 1) === directorySeparator) {
|
||||
return path.substr(0, path.length - 1);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a trailing directory separator to a path, if it does not already have one.
|
||||
* @param path The path.
|
||||
*/
|
||||
export function ensureTrailingDirectorySeparator(path: string) {
|
||||
if (path.charAt(path.length - 1) !== directorySeparator) {
|
||||
return path + directorySeparator;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
export function comparePaths(a: string, b: string, currentDirectory: string, ignoreCase?: boolean) {
|
||||
if (a === b) return Comparison.EqualTo;
|
||||
if (a === undefined) return Comparison.LessThan;
|
||||
if (b === undefined) return Comparison.GreaterThan;
|
||||
a = removeTrailingDirectorySeparator(a);
|
||||
b = removeTrailingDirectorySeparator(b);
|
||||
const aComponents = getNormalizedPathComponents(a, currentDirectory);
|
||||
const bComponents = getNormalizedPathComponents(b, currentDirectory);
|
||||
const sharedLength = Math.min(aComponents.length, bComponents.length);
|
||||
for (let i = 0; i < sharedLength; i++) {
|
||||
const result = compareStrings(aComponents[i], bComponents[i], ignoreCase);
|
||||
if (result !== Comparison.EqualTo) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return compareValues(aComponents.length, bComponents.length);
|
||||
}
|
||||
|
||||
export function containsPath(parent: string, child: string, currentDirectory: string, ignoreCase?: boolean) {
|
||||
if (parent === undefined || child === undefined) return false;
|
||||
if (parent === child) return true;
|
||||
parent = removeTrailingDirectorySeparator(parent);
|
||||
child = removeTrailingDirectorySeparator(child);
|
||||
if (parent === child) return true;
|
||||
const parentComponents = getNormalizedPathComponents(parent, currentDirectory);
|
||||
const childComponents = getNormalizedPathComponents(child, currentDirectory);
|
||||
if (childComponents.length < parentComponents.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < parentComponents.length; i++) {
|
||||
const result = compareStrings(parentComponents[i], childComponents[i], ignoreCase);
|
||||
if (result !== Comparison.EqualTo) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function fileExtensionIs(path: string, extension: string): boolean {
|
||||
const pathLen = path.length;
|
||||
const extLen = extension.length;
|
||||
return pathLen > extLen && path.substr(pathLen - extLen, extLen) === extension;
|
||||
}
|
||||
|
||||
export function fileExtensionIsAny(path: string, extensions: string[]): boolean {
|
||||
for (const extension of extensions) {
|
||||
if (fileExtensionIs(path, extension)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Reserved characters, forces escaping of any non-word (or digit), non-whitespace character.
|
||||
// It may be inefficient (we could just match (/[-[\]{}()*+?.,\\^$|#\s]/g), but this is future
|
||||
// proof.
|
||||
const reservedCharacterPattern = /[^\w\s\/]/g;
|
||||
const wildcardCharCodes = [CharacterCodes.asterisk, CharacterCodes.question];
|
||||
|
||||
export function getRegularExpressionForWildcard(specs: string[], basePath: string, usage: "files" | "directories" | "exclude") {
|
||||
if (specs === undefined || specs.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let pattern = "";
|
||||
let hasWrittenSubpattern = false;
|
||||
spec: for (const spec of specs) {
|
||||
if (!spec) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let subpattern = "";
|
||||
let hasRecursiveDirectoryWildcard = false;
|
||||
let hasWrittenComponent = false;
|
||||
const components = getNormalizedPathComponents(spec, basePath);
|
||||
if (usage !== "exclude" && components[components.length - 1] === "**") {
|
||||
continue spec;
|
||||
}
|
||||
|
||||
// getNormalizedPathComponents includes the separator for the root component.
|
||||
// We need to remove to create our regex correctly.
|
||||
components[0] = removeTrailingDirectorySeparator(components[0]);
|
||||
|
||||
let optionalCount = 0;
|
||||
for (const component of components) {
|
||||
if (component === "**") {
|
||||
if (hasRecursiveDirectoryWildcard) {
|
||||
continue spec;
|
||||
}
|
||||
|
||||
subpattern += "(/.+?)?";
|
||||
hasRecursiveDirectoryWildcard = true;
|
||||
hasWrittenComponent = true;
|
||||
}
|
||||
else {
|
||||
if (usage === "directories") {
|
||||
subpattern += "(";
|
||||
optionalCount++;
|
||||
}
|
||||
|
||||
if (hasWrittenComponent) {
|
||||
subpattern += directorySeparator;
|
||||
}
|
||||
|
||||
subpattern += component.replace(reservedCharacterPattern, replaceWildcardCharacter);
|
||||
hasWrittenComponent = true;
|
||||
}
|
||||
}
|
||||
|
||||
while (optionalCount > 0) {
|
||||
subpattern += ")?";
|
||||
optionalCount--;
|
||||
}
|
||||
|
||||
if (hasWrittenSubpattern) {
|
||||
pattern += "|";
|
||||
}
|
||||
|
||||
pattern += "(" + subpattern + ")";
|
||||
hasWrittenSubpattern = true;
|
||||
}
|
||||
|
||||
if (!pattern) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return "^(" + pattern + (usage === "exclude" ? ")($|/)" : ")$");
|
||||
}
|
||||
|
||||
function replaceWildcardCharacter(match: string) {
|
||||
return match === "*" ? "[^/]*" : match === "?" ? "[^/]" : "\\" + match;
|
||||
}
|
||||
|
||||
export interface FileSystemEntries {
|
||||
files: string[];
|
||||
directories: string[];
|
||||
}
|
||||
|
||||
interface FileMatcherPatterns {
|
||||
includeFilePattern: string;
|
||||
includeDirectoryPattern: string;
|
||||
excludePattern: string;
|
||||
basePaths: string[];
|
||||
}
|
||||
|
||||
export function getFileMatcherPatterns(path: string, extensions: string[], excludes: string[], includes: string[], useCaseSensitiveFileNames: boolean, currentDirectory: string): FileMatcherPatterns {
|
||||
path = normalizePath(path);
|
||||
currentDirectory = normalizePath(currentDirectory);
|
||||
const absolutePath = combinePaths(currentDirectory, path);
|
||||
|
||||
return {
|
||||
includeFilePattern: getRegularExpressionForWildcard(includes, absolutePath, "files"),
|
||||
includeDirectoryPattern: getRegularExpressionForWildcard(includes, absolutePath, "directories"),
|
||||
excludePattern: getRegularExpressionForWildcard(excludes, absolutePath, "exclude"),
|
||||
basePaths: getBasePaths(path, includes, useCaseSensitiveFileNames)
|
||||
};
|
||||
}
|
||||
|
||||
export function matchFiles(path: string, extensions: string[], excludes: string[], includes: string[], useCaseSensitiveFileNames: boolean, currentDirectory: string, getFileSystemEntries: (path: string) => FileSystemEntries): string[] {
|
||||
path = normalizePath(path);
|
||||
currentDirectory = normalizePath(currentDirectory);
|
||||
|
||||
const patterns = getFileMatcherPatterns(path, extensions, excludes, includes, useCaseSensitiveFileNames, currentDirectory);
|
||||
|
||||
const regexFlag = useCaseSensitiveFileNames ? "" : "i";
|
||||
const includeFileRegex = patterns.includeFilePattern && new RegExp(patterns.includeFilePattern, regexFlag);
|
||||
const includeDirectoryRegex = patterns.includeDirectoryPattern && new RegExp(patterns.includeDirectoryPattern, regexFlag);
|
||||
const excludeRegex = patterns.excludePattern && new RegExp(patterns.excludePattern, regexFlag);
|
||||
|
||||
const result: string[] = [];
|
||||
for (const basePath of patterns.basePaths) {
|
||||
visitDirectory(basePath, combinePaths(currentDirectory, basePath));
|
||||
}
|
||||
return result;
|
||||
|
||||
function visitDirectory(path: string, absolutePath: string) {
|
||||
const { files, directories } = getFileSystemEntries(path);
|
||||
|
||||
for (const current of files) {
|
||||
const name = combinePaths(path, current);
|
||||
const absoluteName = combinePaths(absolutePath, current);
|
||||
if ((!extensions || fileExtensionIsAny(name, extensions)) &&
|
||||
(!includeFileRegex || includeFileRegex.test(absoluteName)) &&
|
||||
(!excludeRegex || !excludeRegex.test(absoluteName))) {
|
||||
result.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
for (const current of directories) {
|
||||
const name = combinePaths(path, current);
|
||||
const absoluteName = combinePaths(absolutePath, current);
|
||||
if ((!includeDirectoryRegex || includeDirectoryRegex.test(absoluteName)) &&
|
||||
(!excludeRegex || !excludeRegex.test(absoluteName))) {
|
||||
visitDirectory(name, absoluteName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the unique non-wildcard base paths amongst the provided include patterns.
|
||||
*/
|
||||
function getBasePaths(path: string, includes: string[], useCaseSensitiveFileNames: boolean) {
|
||||
// Storage for our results in the form of literal paths (e.g. the paths as written by the user).
|
||||
const basePaths: string[] = [path];
|
||||
if (includes) {
|
||||
// Storage for literal base paths amongst the include patterns.
|
||||
const includeBasePaths: string[] = [];
|
||||
for (const include of includes) {
|
||||
if (isRootedDiskPath(include)) {
|
||||
const wildcardOffset = indexOfAnyCharCode(include, wildcardCharCodes);
|
||||
const includeBasePath = wildcardOffset < 0
|
||||
? removeTrailingDirectorySeparator(getDirectoryPath(include))
|
||||
: include.substring(0, include.lastIndexOf(directorySeparator, wildcardOffset));
|
||||
|
||||
// Append the literal and canonical candidate base paths.
|
||||
includeBasePaths.push(includeBasePath);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the offsets array using either the literal or canonical path representations.
|
||||
includeBasePaths.sort(useCaseSensitiveFileNames ? compareStrings : compareStringsCaseInsensitive);
|
||||
|
||||
// Iterate over each include base path and include unique base paths that are not a
|
||||
// subpath of an existing base path
|
||||
include: for (let i = 0; i < includeBasePaths.length; i++) {
|
||||
const includeBasePath = includeBasePaths[i];
|
||||
for (let j = 0; j < basePaths.length; j++) {
|
||||
if (containsPath(basePaths[j], includeBasePath, path, !useCaseSensitiveFileNames)) {
|
||||
continue include;
|
||||
}
|
||||
}
|
||||
|
||||
basePaths.push(includeBasePath);
|
||||
}
|
||||
}
|
||||
|
||||
return basePaths;
|
||||
}
|
||||
|
||||
export function ensureScriptKind(fileName: string, scriptKind?: ScriptKind): ScriptKind {
|
||||
// Using scriptKind as a condition handles both:
|
||||
// - 'scriptKind' is unspecified and thus it is `undefined`
|
||||
|
@ -846,6 +1151,59 @@ namespace ts {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension boundaries by priority. Lower numbers indicate higher priorities, and are
|
||||
* aligned to the offset of the highest priority extension in the
|
||||
* allSupportedExtensions array.
|
||||
*/
|
||||
export const enum ExtensionPriority {
|
||||
TypeScriptFiles = 0,
|
||||
DeclarationAndJavaScriptFiles = 2,
|
||||
Limit = 5,
|
||||
|
||||
Highest = TypeScriptFiles,
|
||||
Lowest = DeclarationAndJavaScriptFiles,
|
||||
}
|
||||
|
||||
export function getExtensionPriority(path: string, supportedExtensions: string[]): ExtensionPriority {
|
||||
for (let i = supportedExtensions.length - 1; i >= 0; i--) {
|
||||
if (fileExtensionIs(path, supportedExtensions[i])) {
|
||||
return adjustExtensionPriority(<ExtensionPriority>i);
|
||||
}
|
||||
}
|
||||
|
||||
// If its not in the list of supported extensions, this is likely a
|
||||
// TypeScript file with a non-ts extension
|
||||
return ExtensionPriority.Highest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts an extension priority to be the highest priority within the same range.
|
||||
*/
|
||||
export function adjustExtensionPriority(extensionPriority: ExtensionPriority): ExtensionPriority {
|
||||
if (extensionPriority < ExtensionPriority.DeclarationAndJavaScriptFiles) {
|
||||
return ExtensionPriority.TypeScriptFiles;
|
||||
}
|
||||
else if (extensionPriority < ExtensionPriority.Limit) {
|
||||
return ExtensionPriority.DeclarationAndJavaScriptFiles;
|
||||
}
|
||||
else {
|
||||
return ExtensionPriority.Limit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next lowest extension priority for a given priority.
|
||||
*/
|
||||
export function getNextLowestExtensionPriority(extensionPriority: ExtensionPriority): ExtensionPriority {
|
||||
if (extensionPriority < ExtensionPriority.DeclarationAndJavaScriptFiles) {
|
||||
return ExtensionPriority.DeclarationAndJavaScriptFiles;
|
||||
}
|
||||
else {
|
||||
return ExtensionPriority.Limit;
|
||||
}
|
||||
}
|
||||
|
||||
const extensionsToRemove = [".d.ts", ".ts", ".js", ".tsx", ".jsx"];
|
||||
export function removeFileExtension(path: string): string {
|
||||
for (const ext of extensionsToRemove) {
|
||||
|
@ -865,6 +1223,10 @@ namespace ts {
|
|||
return ext === ".jsx" || ext === ".tsx";
|
||||
}
|
||||
|
||||
export function changeExtension<T extends string | Path>(path: T, newExtension: string): T {
|
||||
return <T>(removeFileExtension(path) + newExtension);
|
||||
}
|
||||
|
||||
export interface ObjectAllocator {
|
||||
getNodeConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => Node;
|
||||
getSourceFileConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => SourceFile;
|
||||
|
|
|
@ -1935,6 +1935,10 @@
|
|||
"category": "Error",
|
||||
"code": 2688
|
||||
},
|
||||
"Cannot extend an interface '{0}'. Did you mean 'implements'?": {
|
||||
"category": "Error",
|
||||
"code": 2689
|
||||
},
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
"code": 4000
|
||||
|
@ -2228,6 +2232,14 @@
|
|||
"category": "Error",
|
||||
"code": 5009
|
||||
},
|
||||
"File specification cannot end in a recursive directory wildcard ('**'): '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 5010
|
||||
},
|
||||
"File specification cannot contain multiple recursive directory wildcards ('**'): '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 5011
|
||||
},
|
||||
"Cannot read file '{0}': {1}": {
|
||||
"category": "Error",
|
||||
"code": 5012
|
||||
|
@ -2921,10 +2933,6 @@
|
|||
"category": "Error",
|
||||
"code": 8012
|
||||
},
|
||||
"'property declarations' can only be used in a .ts file.": {
|
||||
"category": "Error",
|
||||
"code": 8014
|
||||
},
|
||||
"'enum declarations' can only be used in a .ts file.": {
|
||||
"category": "Error",
|
||||
"code": 8015
|
||||
|
|
|
@ -2076,7 +2076,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||
function createPropertyAccessExpression(expression: Expression, name: Identifier): PropertyAccessExpression {
|
||||
const result = <PropertyAccessExpression>createSynthesizedNode(SyntaxKind.PropertyAccessExpression);
|
||||
result.expression = parenthesizeForAccess(expression);
|
||||
result.dotToken = createSynthesizedNode(SyntaxKind.DotToken);
|
||||
result.name = name;
|
||||
return result;
|
||||
}
|
||||
|
@ -2223,11 +2222,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||
// Returns 'true' if the code was actually indented, false otherwise.
|
||||
// If the code is not indented, an optional valueToWriteWhenNotIndenting will be
|
||||
// emitted instead.
|
||||
function indentIfOnDifferentLines(parent: Node, node1: Node, node2: Node, valueToWriteWhenNotIndenting?: string): boolean {
|
||||
function indentIfOnDifferentLines(parent: Node, node1: TextRange, node2: TextRange, valueToWriteWhenNotIndenting?: string): boolean {
|
||||
const realNodesAreOnDifferentLines = !nodeIsSynthesized(parent) && !nodeEndIsOnSameLineAsNodeStart(node1, node2);
|
||||
|
||||
// Always use a newline for synthesized code if the synthesizer desires it.
|
||||
const synthesizedNodeIsOnDifferentLine = synthesizedNodeStartsOnNewLine(node2);
|
||||
const synthesizedNodeIsOnDifferentLine = synthesizedNodeStartsOnNewLine(node2 as Node);
|
||||
|
||||
if (realNodesAreOnDifferentLines || synthesizedNodeIsOnDifferentLine) {
|
||||
increaseIndent();
|
||||
|
@ -2257,7 +2256,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||
}
|
||||
|
||||
emit(node.expression);
|
||||
const indentedBeforeDot = indentIfOnDifferentLines(node, node.expression, node.dotToken);
|
||||
const dotRangeStart = nodeIsSynthesized(node.expression) ? -1 : node.expression.end;
|
||||
const dotRangeEnd = nodeIsSynthesized(node.expression) ? -1 : skipTrivia(currentText, node.expression.end) + 1;
|
||||
const dotToken = <TextRange>{ pos: dotRangeStart, end: dotRangeEnd };
|
||||
const indentedBeforeDot = indentIfOnDifferentLines(node, node.expression, dotToken);
|
||||
|
||||
// 1 .toString is a valid property access, emit a space after the literal
|
||||
// Also emit a space if expression is a integer const enum value - it will appear in generated code as numeric literal
|
||||
|
@ -2283,7 +2285,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||
write(".");
|
||||
}
|
||||
|
||||
const indentedAfterDot = indentIfOnDifferentLines(node, node.dotToken, node.name);
|
||||
const indentedAfterDot = indentIfOnDifferentLines(node, dotToken, node.name);
|
||||
emit(node.name);
|
||||
decreaseIndentIf(indentedBeforeDot, indentedAfterDot);
|
||||
}
|
||||
|
@ -2780,7 +2782,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||
const identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefineTempVariablesInPlace*/ false, /*shouldEmitCommaBeforeAssignment*/ false);
|
||||
synthesizedLHS.expression = identifier;
|
||||
|
||||
(<PropertyAccessExpression>synthesizedLHS).dotToken = leftHandSideExpression.dotToken;
|
||||
(<PropertyAccessExpression>synthesizedLHS).name = leftHandSideExpression.name;
|
||||
write(", ");
|
||||
}
|
||||
|
@ -3758,7 +3759,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||
getLineOfLocalPositionFromLineMap(currentLineMap, node2.end);
|
||||
}
|
||||
|
||||
function nodeEndIsOnSameLineAsNodeStart(node1: Node, node2: Node) {
|
||||
function nodeEndIsOnSameLineAsNodeStart(node1: TextRange, node2: TextRange) {
|
||||
return getLineOfLocalPositionFromLineMap(currentLineMap, node1.end) ===
|
||||
getLineOfLocalPositionFromLineMap(currentLineMap, skipTrivia(currentText, node2.pos));
|
||||
}
|
||||
|
|
|
@ -137,7 +137,6 @@ namespace ts {
|
|||
return visitNodes(cbNodes, (<ObjectLiteralExpression>node).properties);
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
return visitNode(cbNode, (<PropertyAccessExpression>node).expression) ||
|
||||
visitNode(cbNode, (<PropertyAccessExpression>node).dotToken) ||
|
||||
visitNode(cbNode, (<PropertyAccessExpression>node).name);
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
return visitNode(cbNode, (<ElementAccessExpression>node).expression) ||
|
||||
|
@ -3571,7 +3570,7 @@ namespace ts {
|
|||
// If it wasn't then just try to parse out a '.' and report an error.
|
||||
const node = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
|
||||
node.expression = expression;
|
||||
node.dotToken = parseExpectedToken(SyntaxKind.DotToken, /*reportAtCurrentPosition*/ false, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access);
|
||||
parseExpectedToken(SyntaxKind.DotToken, /*reportAtCurrentPosition*/ false, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access);
|
||||
node.name = parseRightSideOfDot(/*allowIdentifierNames*/ true);
|
||||
return finishNode(node);
|
||||
}
|
||||
|
@ -3807,7 +3806,6 @@ namespace ts {
|
|||
if (dotToken) {
|
||||
const propertyAccess = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
|
||||
propertyAccess.expression = expression;
|
||||
propertyAccess.dotToken = dotToken;
|
||||
propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true);
|
||||
expression = finishNode(propertyAccess);
|
||||
continue;
|
||||
|
|
|
@ -180,7 +180,7 @@ namespace ts {
|
|||
|
||||
function getEffectiveTypeRoots(options: CompilerOptions, host: ModuleResolutionHost) {
|
||||
return options.typeRoots ||
|
||||
defaultTypeRoots.map(d => combinePaths(options.configFilePath ? getDirectoryPath(options.configFilePath) : host.getCurrentDirectory(), d));
|
||||
map(defaultTypeRoots, d => combinePaths(options.configFilePath ? getDirectoryPath(options.configFilePath) : host.getCurrentDirectory(), d));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1601,8 +1601,19 @@ namespace ts {
|
|||
}
|
||||
break;
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.property_declarations_can_only_be_used_in_a_ts_file));
|
||||
return true;
|
||||
const propertyDeclaration = <PropertyDeclaration>node;
|
||||
if (propertyDeclaration.modifiers) {
|
||||
for (const modifier of propertyDeclaration.modifiers) {
|
||||
if (modifier.kind !== SyntaxKind.StaticKeyword) {
|
||||
diagnostics.push(createDiagnosticForNode(modifier, Diagnostics._0_can_only_be_used_in_a_ts_file, tokenToString(modifier.kind)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (checkTypeAnnotation((<PropertyDeclaration>node).type)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.enum_declarations_can_only_be_used_in_a_ts_file));
|
||||
return true;
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace ts {
|
|||
useCaseSensitiveFileNames: boolean;
|
||||
write(s: string): void;
|
||||
readFile(path: string, encoding?: string): string;
|
||||
getFileSize?(path: string): number;
|
||||
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
|
||||
watchFile?(path: string, callback: FileWatcherCallback): FileWatcher;
|
||||
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
|
@ -25,7 +26,7 @@ namespace ts {
|
|||
getExecutingFilePath(): string;
|
||||
getCurrentDirectory(): string;
|
||||
getDirectories(path: string): string[];
|
||||
readDirectory(path: string, extension?: string, exclude?: string[]): string[];
|
||||
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[]): string[];
|
||||
getModifiedTime?(path: string): Date;
|
||||
createHash?(data: string): string;
|
||||
getMemoryUsage?(): number;
|
||||
|
@ -73,17 +74,18 @@ namespace ts {
|
|||
readFile(path: string): string;
|
||||
writeFile(path: string, contents: string): void;
|
||||
getDirectories(path: string): string[];
|
||||
readDirectory(path: string, extension?: string, exclude?: string[]): string[];
|
||||
readDirectory(path: string, extensions?: string[], basePaths?: string[], excludeEx?: string, includeFileEx?: string, includeDirEx?: string): string[];
|
||||
watchFile?(path: string, callback: FileWatcherCallback): FileWatcher;
|
||||
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
realpath(path: string): string;
|
||||
};
|
||||
|
||||
export var sys: System = (function () {
|
||||
export var sys: System = (function() {
|
||||
|
||||
function getWScriptSystem(): System {
|
||||
|
||||
const fso = new ActiveXObject("Scripting.FileSystemObject");
|
||||
const shell = new ActiveXObject("WScript.Shell");
|
||||
|
||||
const fileStream = new ActiveXObject("ADODB.Stream");
|
||||
fileStream.Type = 2 /*text*/;
|
||||
|
@ -151,10 +153,6 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function getCanonicalPath(path: string): string {
|
||||
return path.toLowerCase();
|
||||
}
|
||||
|
||||
function getNames(collection: any): string[] {
|
||||
const result: string[] = [];
|
||||
for (let e = new Enumerator(collection); !e.atEnd(); e.moveNext()) {
|
||||
|
@ -168,28 +166,20 @@ namespace ts {
|
|||
return getNames(folder.subfolders);
|
||||
}
|
||||
|
||||
function readDirectory(path: string, extension?: string, exclude?: string[]): string[] {
|
||||
const result: string[] = [];
|
||||
exclude = map(exclude, s => getCanonicalPath(combinePaths(path, s)));
|
||||
visitDirectory(path);
|
||||
return result;
|
||||
function visitDirectory(path: string) {
|
||||
function getAccessibleFileSystemEntries(path: string): FileSystemEntries {
|
||||
try {
|
||||
const folder = fso.GetFolder(path || ".");
|
||||
const files = getNames(folder.files);
|
||||
for (const current of files) {
|
||||
const name = combinePaths(path, current);
|
||||
if ((!extension || fileExtensionIs(name, extension)) && !contains(exclude, getCanonicalPath(name))) {
|
||||
result.push(name);
|
||||
}
|
||||
}
|
||||
const subfolders = getNames(folder.subfolders);
|
||||
for (const current of subfolders) {
|
||||
const name = combinePaths(path, current);
|
||||
if (!contains(exclude, getCanonicalPath(name))) {
|
||||
visitDirectory(name);
|
||||
}
|
||||
}
|
||||
const directories = getNames(folder.subfolders);
|
||||
return { files, directories };
|
||||
}
|
||||
catch (e) {
|
||||
return { files: [], directories: [] };
|
||||
}
|
||||
}
|
||||
|
||||
function readDirectory(path: string, extensions?: string[], excludes?: string[], includes?: string[]): string[] {
|
||||
return matchFiles(path, extensions, excludes, includes, /*useCaseSensitiveFileNames*/ false, shell.CurrentDirectory, getAccessibleFileSystemEntries);
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -219,7 +209,7 @@ namespace ts {
|
|||
return WScript.ScriptFullName;
|
||||
},
|
||||
getCurrentDirectory() {
|
||||
return new ActiveXObject("WScript.Shell").CurrentDirectory;
|
||||
return shell.CurrentDirectory;
|
||||
},
|
||||
getDirectories,
|
||||
readDirectory,
|
||||
|
@ -380,8 +370,43 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function getCanonicalPath(path: string): string {
|
||||
return useCaseSensitiveFileNames ? path : path.toLowerCase();
|
||||
function getAccessibleFileSystemEntries(path: string): FileSystemEntries {
|
||||
try {
|
||||
const entries = _fs.readdirSync(path || ".").sort();
|
||||
const files: string[] = [];
|
||||
const directories: string[] = [];
|
||||
for (const entry of entries) {
|
||||
// This is necessary because on some file system node fails to exclude
|
||||
// "." and "..". See https://github.com/nodejs/node/issues/4002
|
||||
if (entry === "." || entry === "..") {
|
||||
continue;
|
||||
}
|
||||
const name = combinePaths(path, entry);
|
||||
|
||||
let stat: any;
|
||||
try {
|
||||
stat = _fs.statSync(name);
|
||||
}
|
||||
catch (e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (stat.isFile()) {
|
||||
files.push(entry);
|
||||
}
|
||||
else if (stat.isDirectory()) {
|
||||
directories.push(entry);
|
||||
}
|
||||
}
|
||||
return { files, directories };
|
||||
}
|
||||
catch (e) {
|
||||
return { files: [], directories: [] };
|
||||
}
|
||||
}
|
||||
|
||||
function readDirectory(path: string, extensions?: string[], excludes?: string[], includes?: string[]): string[] {
|
||||
return matchFiles(path, extensions, excludes, includes, useCaseSensitiveFileNames, process.cwd(), getAccessibleFileSystemEntries);
|
||||
}
|
||||
|
||||
const enum FileSystemEntryKind {
|
||||
|
@ -414,39 +439,6 @@ namespace ts {
|
|||
return filter<string>(_fs.readdirSync(path), p => fileSystemEntryExists(combinePaths(path, p), FileSystemEntryKind.Directory));
|
||||
}
|
||||
|
||||
function readDirectory(path: string, extension?: string, exclude?: string[]): string[] {
|
||||
const result: string[] = [];
|
||||
exclude = map(exclude, s => getCanonicalPath(combinePaths(path, s)));
|
||||
visitDirectory(path);
|
||||
return result;
|
||||
function visitDirectory(path: string) {
|
||||
const files = _fs.readdirSync(path || ".").sort();
|
||||
const directories: string[] = [];
|
||||
for (const current of files) {
|
||||
// This is necessary because on some file system node fails to exclude
|
||||
// "." and "..". See https://github.com/nodejs/node/issues/4002
|
||||
if (current === "." || current === "..") {
|
||||
continue;
|
||||
}
|
||||
const name = combinePaths(path, current);
|
||||
if (!contains(exclude, getCanonicalPath(name))) {
|
||||
const stat = _fs.statSync(name);
|
||||
if (stat.isFile()) {
|
||||
if (!extension || fileExtensionIs(name, extension)) {
|
||||
result.push(name);
|
||||
}
|
||||
}
|
||||
else if (stat.isDirectory()) {
|
||||
directories.push(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const current of directories) {
|
||||
visitDirectory(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
args: process.argv.slice(2),
|
||||
newLine: _os.EOL,
|
||||
|
@ -503,7 +495,7 @@ namespace ts {
|
|||
}
|
||||
);
|
||||
},
|
||||
resolvePath: function (path: string): string {
|
||||
resolvePath: function(path: string): string {
|
||||
return _path.resolve(path);
|
||||
},
|
||||
fileExists,
|
||||
|
@ -540,6 +532,16 @@ namespace ts {
|
|||
}
|
||||
return process.memoryUsage().heapUsed;
|
||||
},
|
||||
getFileSize(path) {
|
||||
try {
|
||||
const stat = _fs.statSync(path);
|
||||
if (stat.isFile()) {
|
||||
return stat.size;
|
||||
}
|
||||
}
|
||||
catch (e) { }
|
||||
return 0;
|
||||
},
|
||||
exit(exitCode?: number): void {
|
||||
process.exit(exitCode);
|
||||
},
|
||||
|
@ -575,7 +577,10 @@ namespace ts {
|
|||
getExecutingFilePath: () => ChakraHost.executingFile,
|
||||
getCurrentDirectory: () => ChakraHost.currentDirectory,
|
||||
getDirectories: ChakraHost.getDirectories,
|
||||
readDirectory: ChakraHost.readDirectory,
|
||||
readDirectory: (path: string, extensions?: string[], excludes?: string[], includes?: string[]) => {
|
||||
const pattern = getFileMatcherPatterns(path, extensions, excludes, includes, !!ChakraHost.useCaseSensitiveFileNames, ChakraHost.currentDirectory);
|
||||
return ChakraHost.readDirectory(path, extensions, pattern.basePaths, pattern.excludePattern, pattern.includeFilePattern, pattern.includeDirectoryPattern);
|
||||
},
|
||||
exit: ChakraHost.quit,
|
||||
realpath
|
||||
};
|
||||
|
|
|
@ -980,7 +980,6 @@ namespace ts {
|
|||
// @kind(SyntaxKind.PropertyAccessExpression)
|
||||
export interface PropertyAccessExpression extends MemberExpression, Declaration {
|
||||
expression: LeftHandSideExpression;
|
||||
dotToken: Node;
|
||||
name: Identifier;
|
||||
}
|
||||
|
||||
|
@ -1188,6 +1187,7 @@ namespace ts {
|
|||
export interface SwitchStatement extends Statement {
|
||||
expression: Expression;
|
||||
caseBlock: CaseBlock;
|
||||
possiblyExhaustive?: boolean;
|
||||
}
|
||||
|
||||
// @kind(SyntaxKind.CaseBlock)
|
||||
|
@ -1554,8 +1554,9 @@ namespace ts {
|
|||
Assignment = 1 << 4, // Assignment
|
||||
TrueCondition = 1 << 5, // Condition known to be true
|
||||
FalseCondition = 1 << 6, // Condition known to be false
|
||||
Referenced = 1 << 7, // Referenced as antecedent once
|
||||
Shared = 1 << 8, // Referenced as antecedent more than once
|
||||
SwitchClause = 1 << 7, // Switch statement clause
|
||||
Referenced = 1 << 8, // Referenced as antecedent once
|
||||
Shared = 1 << 9, // Referenced as antecedent more than once
|
||||
Label = BranchLabel | LoopLabel,
|
||||
Condition = TrueCondition | FalseCondition
|
||||
}
|
||||
|
@ -1591,6 +1592,13 @@ namespace ts {
|
|||
antecedent: FlowNode;
|
||||
}
|
||||
|
||||
export interface FlowSwitchClause extends FlowNode {
|
||||
switchStatement: SwitchStatement;
|
||||
clauseStart: number; // Start index of case/default clause range
|
||||
clauseEnd: number; // End index of case/default clause range
|
||||
antecedent: FlowNode;
|
||||
}
|
||||
|
||||
export interface AmdDependency {
|
||||
path: string;
|
||||
name: string;
|
||||
|
@ -1669,7 +1677,15 @@ namespace ts {
|
|||
}
|
||||
|
||||
export interface ParseConfigHost {
|
||||
readDirectory(rootDir: string, extension: string, exclude: string[]): string[];
|
||||
useCaseSensitiveFileNames: boolean;
|
||||
|
||||
readDirectory(rootDir: string, extensions: string[], excludes: string[], includes: string[]): string[];
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether the specified path exists and is a file.
|
||||
* @param path The path to test.
|
||||
*/
|
||||
fileExists(path: string): boolean;
|
||||
}
|
||||
|
||||
export interface WriteFileCallback {
|
||||
|
@ -2185,6 +2201,7 @@ namespace ts {
|
|||
resolvedJsxType?: Type; // resolved element attributes type of a JSX openinglike element
|
||||
hasSuperCall?: boolean; // recorded result when we try to find super-call. We only try to find one if this flag is undefined, indicating that we haven't made an attempt.
|
||||
superCall?: ExpressionStatement; // Cached first super-call found in the constructor. Used in checking whether super is called before this-accessing
|
||||
switchTypes?: Type[]; // Cached array of switch case expression types
|
||||
}
|
||||
|
||||
export const enum TypeFlags {
|
||||
|
@ -2224,7 +2241,8 @@ namespace ts {
|
|||
|
||||
/* @internal */
|
||||
Nullable = Undefined | Null,
|
||||
Falsy = String | Number | Boolean | Void | Undefined | Null,
|
||||
/* @internal */
|
||||
Falsy = Void | Undefined | Null, // TODO: Add false, 0, and ""
|
||||
/* @internal */
|
||||
Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null | Never,
|
||||
/* @internal */
|
||||
|
@ -2561,6 +2579,7 @@ namespace ts {
|
|||
/* @internal */ suppressOutputPathCheck?: boolean;
|
||||
target?: ScriptTarget;
|
||||
traceResolution?: boolean;
|
||||
disableSizeLimit?: boolean;
|
||||
types?: string[];
|
||||
/** Paths used to used to compute primary types search locations */
|
||||
typeRoots?: string[];
|
||||
|
@ -2649,6 +2668,17 @@ namespace ts {
|
|||
fileNames: string[];
|
||||
raw?: any;
|
||||
errors: Diagnostic[];
|
||||
wildcardDirectories?: Map<WatchDirectoryFlags>;
|
||||
}
|
||||
|
||||
export const enum WatchDirectoryFlags {
|
||||
None = 0,
|
||||
Recursive = 1 << 0,
|
||||
}
|
||||
|
||||
export interface ExpandResult {
|
||||
fileNames: string[];
|
||||
wildcardDirectories: Map<WatchDirectoryFlags>;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
|
|
@ -2330,7 +2330,9 @@ namespace ts {
|
|||
|
||||
export function getSourceFilePathInNewDir(sourceFile: SourceFile, host: EmitHost, newDirPath: string) {
|
||||
let sourceFilePath = getNormalizedAbsolutePath(sourceFile.fileName, host.getCurrentDirectory());
|
||||
sourceFilePath = sourceFilePath.replace(host.getCommonSourceDirectory(), "");
|
||||
const commonSourceDirectory = host.getCommonSourceDirectory();
|
||||
const isSourceFileInCommonSourceDirectory = host.getCanonicalFileName(sourceFilePath).indexOf(host.getCanonicalFileName(commonSourceDirectory)) === 0;
|
||||
sourceFilePath = isSourceFileInCommonSourceDirectory ? sourceFilePath.substring(commonSourceDirectory.length) : sourceFilePath;
|
||||
return combinePaths(newDirPath, sourceFilePath);
|
||||
}
|
||||
|
||||
|
@ -2714,6 +2716,10 @@ namespace ts {
|
|||
return forEach(supportedJavascriptExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
}
|
||||
|
||||
export function hasTypeScriptFileExtension(fileName: string) {
|
||||
return forEach(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace each instance of non-ascii characters by one, two, three, or four escape sequences
|
||||
* representing the UTF-8 encoding of the character, and return the expanded char code list.
|
||||
|
|
|
@ -167,8 +167,13 @@ declare module chai {
|
|||
module assert {
|
||||
function equal(actual: any, expected: any, message?: string): void;
|
||||
function notEqual(actual: any, expected: any, message?: string): void;
|
||||
function deepEqual<T>(actual: T, expected: T, message?: string): void;
|
||||
function notDeepEqual<T>(actual: T, expected: T, message?: string): void;
|
||||
function lengthOf(object: any[], length: number, message?: string): void;
|
||||
function isTrue(value: any, message?: string): void;
|
||||
function isFalse(value: any, message?: string): void;
|
||||
function isOk(actual: any, message?: string): void;
|
||||
function isUndefined(value: any, message?: string): void;
|
||||
function isDefined(value: any, message?: string): void;
|
||||
}
|
||||
}
|
|
@ -730,30 +730,6 @@ namespace FourSlash {
|
|||
}
|
||||
}
|
||||
|
||||
public verifyReferencesAtPositionListContains(fileName: string, start: number, end: number, isWriteAccess?: boolean, isDefinition?: boolean) {
|
||||
const references = this.getReferencesAtCaret();
|
||||
|
||||
if (!references || references.length === 0) {
|
||||
this.raiseError("verifyReferencesAtPositionListContains failed - found 0 references, expected at least one.");
|
||||
}
|
||||
|
||||
for (let i = 0; i < references.length; i++) {
|
||||
const reference = references[i];
|
||||
if (reference && reference.fileName === fileName && reference.textSpan.start === start && ts.textSpanEnd(reference.textSpan) === end) {
|
||||
if (typeof isWriteAccess !== "undefined" && reference.isWriteAccess !== isWriteAccess) {
|
||||
this.raiseError(`verifyReferencesAtPositionListContains failed - item isWriteAccess value does not match, actual: ${reference.isWriteAccess}, expected: ${isWriteAccess}.`);
|
||||
}
|
||||
if (typeof isDefinition !== "undefined" && reference.isDefinition !== isDefinition) {
|
||||
this.raiseError(`verifyReferencesAtPositionListContains failed - item isDefinition value does not match, actual: ${reference.isDefinition}, expected: ${isDefinition}.`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const missingItem = { fileName, start, end, isWriteAccess, isDefinition };
|
||||
this.raiseError(`verifyReferencesAtPositionListContains failed - could not find the item: ${stringify(missingItem)} in the returned list: (${stringify(references)})`);
|
||||
}
|
||||
|
||||
public verifyReferencesCountIs(count: number, localFilesOnly = true) {
|
||||
const references = this.getReferencesAtCaret();
|
||||
let referencesCount = 0;
|
||||
|
@ -777,6 +753,73 @@ namespace FourSlash {
|
|||
}
|
||||
}
|
||||
|
||||
public verifyReferencesAre(expectedReferences: Range[]) {
|
||||
const actualReferences = this.getReferencesAtCaret() || [];
|
||||
|
||||
if (actualReferences.length > expectedReferences.length) {
|
||||
// Find the unaccounted-for reference.
|
||||
for (const actual of actualReferences) {
|
||||
if (!ts.forEach(expectedReferences, r => r.start === actual.textSpan.start)) {
|
||||
this.raiseError(`A reference ${actual} is unaccounted for.`);
|
||||
}
|
||||
}
|
||||
// Probably will never reach here.
|
||||
this.raiseError(`There are ${actualReferences.length} references but only ${expectedReferences.length} were expected.`);
|
||||
}
|
||||
|
||||
for (const reference of expectedReferences) {
|
||||
const {fileName, start, end} = reference;
|
||||
if (reference.marker) {
|
||||
const {isWriteAccess, isDefinition} = reference.marker.data;
|
||||
this.verifyReferencesWorker(actualReferences, fileName, start, end, isWriteAccess, isDefinition);
|
||||
}
|
||||
else {
|
||||
this.verifyReferencesWorker(actualReferences, fileName, start, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public verifyReferencesOf({fileName, start}: Range, references: Range[]) {
|
||||
this.openFile(fileName);
|
||||
this.goToPosition(start);
|
||||
this.verifyReferencesAre(references);
|
||||
}
|
||||
|
||||
public verifyRangesReferenceEachOther(ranges?: Range[]) {
|
||||
ranges = ranges || this.getRanges();
|
||||
assert(ranges.length);
|
||||
for (const range of ranges) {
|
||||
this.verifyReferencesOf(range, ranges);
|
||||
}
|
||||
}
|
||||
|
||||
public verifyReferencesAtPositionListContains(fileName: string, start: number, end: number, isWriteAccess?: boolean, isDefinition?: boolean) {
|
||||
const references = this.getReferencesAtCaret();
|
||||
if (!references || references.length === 0) {
|
||||
this.raiseError("verifyReferencesAtPositionListContains failed - found 0 references, expected at least one.");
|
||||
}
|
||||
this.verifyReferencesWorker(references, fileName, start, end, isWriteAccess, isDefinition);
|
||||
}
|
||||
|
||||
private verifyReferencesWorker(references: ts.ReferenceEntry[], fileName: string, start: number, end: number, isWriteAccess?: boolean, isDefinition?: boolean) {
|
||||
for (let i = 0; i < references.length; i++) {
|
||||
const reference = references[i];
|
||||
if (reference && reference.fileName === fileName && reference.textSpan.start === start && ts.textSpanEnd(reference.textSpan) === end) {
|
||||
if (typeof isWriteAccess !== "undefined" && reference.isWriteAccess !== isWriteAccess) {
|
||||
this.raiseError(`verifyReferencesAtPositionListContains failed - item isWriteAccess value does not match, actual: ${reference.isWriteAccess}, expected: ${isWriteAccess}.`);
|
||||
}
|
||||
if (typeof isDefinition !== "undefined" && reference.isDefinition !== isDefinition) {
|
||||
this.raiseError(`verifyReferencesAtPositionListContains failed - item isDefinition value does not match, actual: ${reference.isDefinition}, expected: ${isDefinition}.`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const missingItem = { fileName, start, end, isWriteAccess, isDefinition };
|
||||
this.raiseError(`verifyReferencesAtPositionListContains failed - could not find the item: ${stringify(missingItem)} in the returned list: (${stringify(references)})`);
|
||||
|
||||
}
|
||||
|
||||
private getMemberListAtCaret() {
|
||||
return this.languageService.getCompletionsAtPosition(this.activeFile.fileName, this.currentCaretPosition);
|
||||
}
|
||||
|
@ -2836,14 +2879,6 @@ namespace FourSlashInterface {
|
|||
this.state.verifyMemberListIsEmpty(this.negative);
|
||||
}
|
||||
|
||||
public referencesCountIs(count: number) {
|
||||
this.state.verifyReferencesCountIs(count, /*localFilesOnly*/ false);
|
||||
}
|
||||
|
||||
public referencesAtPositionContains(range: FourSlash.Range, isWriteAccess?: boolean, isDefinition?: boolean) {
|
||||
this.state.verifyReferencesAtPositionListContains(range.fileName, range.start, range.end, isWriteAccess, isDefinition);
|
||||
}
|
||||
|
||||
public signatureHelpPresent() {
|
||||
this.state.verifySignatureHelpPresent(!this.negative);
|
||||
}
|
||||
|
@ -2935,6 +2970,22 @@ namespace FourSlashInterface {
|
|||
this.state.verifyGetEmitOutputContentsForCurrentFile(expected);
|
||||
}
|
||||
|
||||
public referencesCountIs(count: number) {
|
||||
this.state.verifyReferencesCountIs(count, /*localFilesOnly*/ false);
|
||||
}
|
||||
|
||||
public referencesAre(ranges: FourSlash.Range[]) {
|
||||
this.state.verifyReferencesAre(ranges);
|
||||
}
|
||||
|
||||
public referencesOf(start: FourSlash.Range, references: FourSlash.Range[]) {
|
||||
this.state.verifyReferencesOf(start, references);
|
||||
}
|
||||
|
||||
public rangesReferenceEachOther(ranges?: FourSlash.Range[]) {
|
||||
this.state.verifyRangesReferenceEachOther(ranges);
|
||||
}
|
||||
|
||||
public currentParameterHelpArgumentNameIs(name: string) {
|
||||
this.state.verifyCurrentParameterHelpName(name);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
/// <reference path="external\chai.d.ts"/>
|
||||
/// <reference path="sourceMapRecorder.ts"/>
|
||||
/// <reference path="runnerbase.ts"/>
|
||||
/// <reference path="virtualFileSystem.ts" />
|
||||
|
||||
// Block scoped definitions work poorly for global variables, temporarily enable var
|
||||
/* tslint:disable:no-var-keyword */
|
||||
|
@ -443,7 +444,7 @@ namespace Harness {
|
|||
args(): string[];
|
||||
getExecutingFilePath(): string;
|
||||
exit(exitCode?: number): void;
|
||||
readDirectory(path: string, extension?: string, exclude?: string[]): string[];
|
||||
readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[]): string[];
|
||||
}
|
||||
export var IO: IO;
|
||||
|
||||
|
@ -482,7 +483,7 @@ namespace Harness {
|
|||
export const directoryExists: typeof IO.directoryExists = fso.FolderExists;
|
||||
export const fileExists: typeof IO.fileExists = fso.FileExists;
|
||||
export const log: typeof IO.log = global.WScript && global.WScript.StdOut.WriteLine;
|
||||
export const readDirectory: typeof IO.readDirectory = (path, extension, exclude) => ts.sys.readDirectory(path, extension, exclude);
|
||||
export const readDirectory: typeof IO.readDirectory = (path, extension, exclude, include) => ts.sys.readDirectory(path, extension, exclude, include);
|
||||
|
||||
export function createDirectory(path: string) {
|
||||
if (directoryExists(path)) {
|
||||
|
@ -552,7 +553,7 @@ namespace Harness {
|
|||
export const fileExists: typeof IO.fileExists = fs.existsSync;
|
||||
export const log: typeof IO.log = s => console.log(s);
|
||||
|
||||
export const readDirectory: typeof IO.readDirectory = (path, extension, exclude) => ts.sys.readDirectory(path, extension, exclude);
|
||||
export const readDirectory: typeof IO.readDirectory = (path, extension, exclude, include) => ts.sys.readDirectory(path, extension, exclude, include);
|
||||
|
||||
export function createDirectory(path: string) {
|
||||
if (!directoryExists(path)) {
|
||||
|
@ -740,8 +741,22 @@ namespace Harness {
|
|||
Http.writeToServerSync(serverRoot + path, "WRITE", contents);
|
||||
}
|
||||
|
||||
export function readDirectory(path: string, extension?: string, exclude?: string[]) {
|
||||
return listFiles(path).filter(f => !extension || ts.fileExtensionIs(f, extension));
|
||||
export function readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[]) {
|
||||
const fs = new Utils.VirtualFileSystem(path, useCaseSensitiveFileNames());
|
||||
for (const file in listFiles(path)) {
|
||||
fs.addFile(file);
|
||||
}
|
||||
return ts.matchFiles(path, extension, exclude, include, useCaseSensitiveFileNames(), getCurrentDirectory(), path => {
|
||||
const entry = fs.traversePath(path);
|
||||
if (entry && entry.isDirectory()) {
|
||||
const directory = <Utils.VirtualDirectory>entry;
|
||||
return {
|
||||
files: ts.map(directory.getFiles(), f => f.name),
|
||||
directories: ts.map(directory.getDirectories(), d => d.name)
|
||||
};
|
||||
}
|
||||
return { files: [], directories: [] };
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1051,7 +1066,7 @@ namespace Harness {
|
|||
options.target = options.target || ts.ScriptTarget.ES3;
|
||||
options.newLine = options.newLine || ts.NewLineKind.CarriageReturnLineFeed;
|
||||
options.noErrorTruncation = true;
|
||||
options.skipDefaultLibCheck = true;
|
||||
options.skipDefaultLibCheck = typeof options.skipDefaultLibCheck === "undefined" ? true : options.skipDefaultLibCheck;
|
||||
|
||||
if (typeof currentDirectory === "undefined") {
|
||||
currentDirectory = Harness.IO.getCurrentDirectory();
|
||||
|
@ -1531,7 +1546,9 @@ namespace Harness {
|
|||
|
||||
// unit tests always list files explicitly
|
||||
const parseConfigHost: ts.ParseConfigHost = {
|
||||
readDirectory: (name) => []
|
||||
useCaseSensitiveFileNames: false,
|
||||
readDirectory: (name) => [],
|
||||
fileExists: (name) => true
|
||||
};
|
||||
|
||||
// check if project has tsconfig.json in the list of files
|
||||
|
|
|
@ -288,6 +288,12 @@ namespace Harness.LanguageService {
|
|||
readDirectory(rootDir: string, extension: string): string {
|
||||
throw new Error("NYI");
|
||||
}
|
||||
readDirectoryNames(path: string): string {
|
||||
throw new Error("Not implemented.");
|
||||
}
|
||||
readFileNames(path: string): string {
|
||||
throw new Error("Not implemented.");
|
||||
}
|
||||
fileExists(fileName: string) { return this.getScriptInfo(fileName) !== undefined; }
|
||||
readFile(fileName: string) {
|
||||
const snapshot = this.nativeHost.getScriptSnapshot(fileName);
|
||||
|
@ -611,7 +617,7 @@ namespace Harness.LanguageService {
|
|||
return [];
|
||||
}
|
||||
|
||||
readDirectory(path: string, extension?: string): string[] {
|
||||
readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[]): string[] {
|
||||
throw new Error("Not implemented Yet.");
|
||||
}
|
||||
|
||||
|
@ -695,4 +701,3 @@ namespace Harness.LanguageService {
|
|||
getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { throw new Error("getPreProcessedFileInfo is not available using the server interface."); }
|
||||
}
|
||||
}
|
||||
|
|
@ -61,8 +61,9 @@ interface IOLog {
|
|||
}[];
|
||||
directoriesRead: {
|
||||
path: string,
|
||||
extension: string,
|
||||
extension: string[],
|
||||
exclude: string[],
|
||||
include: string[],
|
||||
result: string[]
|
||||
}[];
|
||||
}
|
||||
|
@ -217,9 +218,9 @@ namespace Playback {
|
|||
memoize(path => findResultByPath(wrapper, replayLog.filesRead, path).contents));
|
||||
|
||||
wrapper.readDirectory = recordReplay(wrapper.readDirectory, underlying)(
|
||||
(path, extension, exclude) => {
|
||||
const result = (<ts.System>underlying).readDirectory(path, extension, exclude);
|
||||
const logEntry = { path, extension, exclude, result };
|
||||
(path, extension, exclude, include) => {
|
||||
const result = (<ts.System>underlying).readDirectory(path, extension, exclude, include);
|
||||
const logEntry = { path, extension, exclude, include, result };
|
||||
recordLog.directoriesRead.push(logEntry);
|
||||
return result;
|
||||
},
|
||||
|
|
|
@ -218,7 +218,12 @@ class ProjectRunner extends RunnerBase {
|
|||
}
|
||||
|
||||
const configObject = result.config;
|
||||
const configParseResult = ts.parseJsonConfigFileContent(configObject, { readDirectory }, ts.getDirectoryPath(configFileName), compilerOptions);
|
||||
const configParseHost: ts.ParseConfigHost = {
|
||||
useCaseSensitiveFileNames: Harness.IO.useCaseSensitiveFileNames(),
|
||||
fileExists,
|
||||
readDirectory,
|
||||
};
|
||||
const configParseResult = ts.parseJsonConfigFileContent(configObject, configParseHost, ts.getDirectoryPath(configFileName), compilerOptions);
|
||||
if (configParseResult.errors.length > 0) {
|
||||
return {
|
||||
moduleKind,
|
||||
|
@ -276,8 +281,8 @@ class ProjectRunner extends RunnerBase {
|
|||
: ts.normalizeSlashes(testCase.projectRoot) + "/" + ts.normalizeSlashes(fileName);
|
||||
}
|
||||
|
||||
function readDirectory(rootDir: string, extension: string, exclude: string[]): string[] {
|
||||
const harnessReadDirectoryResult = Harness.IO.readDirectory(getFileNameInTheProjectTest(rootDir), extension, exclude);
|
||||
function readDirectory(rootDir: string, extension: string[], exclude: string[], include: string[]): string[] {
|
||||
const harnessReadDirectoryResult = Harness.IO.readDirectory(getFileNameInTheProjectTest(rootDir), extension, exclude, include);
|
||||
const result: string[] = [];
|
||||
for (let i = 0; i < harnessReadDirectoryResult.length; i++) {
|
||||
result[i] = ts.getRelativePathToDirectoryOrUrl(testCase.projectRoot, harnessReadDirectoryResult[i],
|
||||
|
|
|
@ -75,7 +75,12 @@ namespace RWC {
|
|||
if (tsconfigFile) {
|
||||
const tsconfigFileContents = getHarnessCompilerInputUnit(tsconfigFile.path);
|
||||
const parsedTsconfigFileContents = ts.parseConfigFileTextToJson(tsconfigFile.path, tsconfigFileContents.content);
|
||||
const configParseResult = ts.parseJsonConfigFileContent(parsedTsconfigFileContents.config, Harness.IO, ts.getDirectoryPath(tsconfigFile.path));
|
||||
const configParseHost: ts.ParseConfigHost = {
|
||||
useCaseSensitiveFileNames: Harness.IO.useCaseSensitiveFileNames(),
|
||||
fileExists: Harness.IO.fileExists,
|
||||
readDirectory: Harness.IO.readDirectory,
|
||||
};
|
||||
const configParseResult = ts.parseJsonConfigFileContent(parsedTsconfigFileContents.config, configParseHost, ts.getDirectoryPath(tsconfigFile.path));
|
||||
fileNames = configParseResult.fileNames;
|
||||
opts.options = ts.extend(opts.options, configParseResult.options);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
/// <reference path="harness.ts" />
|
||||
/// <reference path="..\compiler\commandLineParser.ts"/>
|
||||
namespace Utils {
|
||||
export class VirtualFileSystemEntry {
|
||||
fileSystem: VirtualFileSystem;
|
||||
name: string;
|
||||
|
||||
constructor(fileSystem: VirtualFileSystem, name: string) {
|
||||
this.fileSystem = fileSystem;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
isDirectory() { return false; }
|
||||
isFile() { return false; }
|
||||
isFileSystem() { return false; }
|
||||
}
|
||||
|
||||
export class VirtualFile extends VirtualFileSystemEntry {
|
||||
content: string;
|
||||
isFile() { return true; }
|
||||
}
|
||||
|
||||
export abstract class VirtualFileSystemContainer extends VirtualFileSystemEntry {
|
||||
abstract getFileSystemEntries(): VirtualFileSystemEntry[];
|
||||
|
||||
getFileSystemEntry(name: string): VirtualFileSystemEntry {
|
||||
for (const entry of this.getFileSystemEntries()) {
|
||||
if (this.fileSystem.sameName(entry.name, name)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getDirectories(): VirtualDirectory[] {
|
||||
return <VirtualDirectory[]>ts.filter(this.getFileSystemEntries(), entry => entry.isDirectory());
|
||||
}
|
||||
|
||||
getFiles(): VirtualFile[] {
|
||||
return <VirtualFile[]>ts.filter(this.getFileSystemEntries(), entry => entry.isFile());
|
||||
}
|
||||
|
||||
getDirectory(name: string): VirtualDirectory {
|
||||
const entry = this.getFileSystemEntry(name);
|
||||
return entry.isDirectory() ? <VirtualDirectory>entry : undefined;
|
||||
}
|
||||
|
||||
getFile(name: string): VirtualFile {
|
||||
const entry = this.getFileSystemEntry(name);
|
||||
return entry.isFile() ? <VirtualFile>entry : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export class VirtualDirectory extends VirtualFileSystemContainer {
|
||||
private entries: VirtualFileSystemEntry[] = [];
|
||||
|
||||
isDirectory() { return true; }
|
||||
|
||||
getFileSystemEntries() { return this.entries.slice(); }
|
||||
|
||||
addDirectory(name: string): VirtualDirectory {
|
||||
const entry = this.getFileSystemEntry(name);
|
||||
if (entry === undefined) {
|
||||
const directory = new VirtualDirectory(this.fileSystem, name);
|
||||
this.entries.push(directory);
|
||||
return directory;
|
||||
}
|
||||
else if (entry.isDirectory()) {
|
||||
return <VirtualDirectory>entry;
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
addFile(name: string, content?: string): VirtualFile {
|
||||
const entry = this.getFileSystemEntry(name);
|
||||
if (entry === undefined) {
|
||||
const file = new VirtualFile(this.fileSystem, name);
|
||||
file.content = content;
|
||||
this.entries.push(file);
|
||||
return file;
|
||||
}
|
||||
else if (entry.isFile()) {
|
||||
const file = <VirtualFile>entry;
|
||||
file.content = content;
|
||||
return file;
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class VirtualFileSystem extends VirtualFileSystemContainer {
|
||||
private root: VirtualDirectory;
|
||||
|
||||
currentDirectory: string;
|
||||
useCaseSensitiveFileNames: boolean;
|
||||
|
||||
constructor(currentDirectory: string, useCaseSensitiveFileNames: boolean) {
|
||||
super(undefined, "");
|
||||
this.fileSystem = this;
|
||||
this.root = new VirtualDirectory(this, "");
|
||||
this.currentDirectory = currentDirectory;
|
||||
this.useCaseSensitiveFileNames = useCaseSensitiveFileNames;
|
||||
}
|
||||
|
||||
isFileSystem() { return true; }
|
||||
|
||||
getFileSystemEntries() { return this.root.getFileSystemEntries(); }
|
||||
|
||||
addDirectory(path: string) {
|
||||
const components = ts.getNormalizedPathComponents(path, this.currentDirectory);
|
||||
let directory: VirtualDirectory = this.root;
|
||||
for (const component of components) {
|
||||
directory = directory.addDirectory(component);
|
||||
if (directory === undefined) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return directory;
|
||||
}
|
||||
|
||||
addFile(path: string, content?: string) {
|
||||
const absolutePath = ts.getNormalizedAbsolutePath(path, this.currentDirectory);
|
||||
const fileName = ts.getBaseFileName(path);
|
||||
const directoryPath = ts.getDirectoryPath(absolutePath);
|
||||
const directory = this.addDirectory(directoryPath);
|
||||
return directory ? directory.addFile(fileName, content) : undefined;
|
||||
}
|
||||
|
||||
fileExists(path: string) {
|
||||
const entry = this.traversePath(path);
|
||||
return entry !== undefined && entry.isFile();
|
||||
}
|
||||
|
||||
sameName(a: string, b: string) {
|
||||
return this.useCaseSensitiveFileNames ? a === b : a.toLowerCase() === b.toLowerCase();
|
||||
}
|
||||
|
||||
traversePath(path: string) {
|
||||
let directory: VirtualDirectory = this.root;
|
||||
for (const component of ts.getNormalizedPathComponents(path, this.currentDirectory)) {
|
||||
const entry = directory.getFileSystemEntry(component);
|
||||
if (entry === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
else if (entry.isDirectory()) {
|
||||
directory = <VirtualDirectory>entry;
|
||||
}
|
||||
else {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
return directory;
|
||||
}
|
||||
}
|
||||
|
||||
export class MockParseConfigHost extends VirtualFileSystem implements ts.ParseConfigHost {
|
||||
constructor(currentDirectory: string, ignoreCase: boolean, files: string[]) {
|
||||
super(currentDirectory, ignoreCase);
|
||||
for (const file of files) {
|
||||
this.addFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
readDirectory(path: string, extensions: string[], excludes: string[], includes: string[]) {
|
||||
return ts.matchFiles(path, extensions, excludes, includes, this.useCaseSensitiveFileNames, this.currentDirectory, (path: string) => this.getAccessibleFileSystemEntries(path));
|
||||
}
|
||||
|
||||
getAccessibleFileSystemEntries(path: string) {
|
||||
const entry = this.traversePath(path);
|
||||
if (entry && entry.isDirectory()) {
|
||||
const directory = <VirtualDirectory>entry;
|
||||
return {
|
||||
files: ts.map(directory.getFiles(), f => f.name),
|
||||
directories: ts.map(directory.getDirectories(), d => d.name)
|
||||
};
|
||||
}
|
||||
return { files: [], directories: [] };
|
||||
}
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -3,6 +3,10 @@
|
|||
/// IE Worker APIs
|
||||
/////////////////////////////
|
||||
|
||||
interface Algorithm {
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface EventInit {
|
||||
bubbles?: boolean;
|
||||
cancelable?: boolean;
|
||||
|
@ -18,6 +22,10 @@ interface IDBObjectStoreParameters {
|
|||
keyPath?: IDBKeyPath;
|
||||
}
|
||||
|
||||
interface KeyAlgorithm {
|
||||
name?: string;
|
||||
}
|
||||
|
||||
interface EventListener {
|
||||
(evt: Event): void;
|
||||
}
|
||||
|
@ -107,6 +115,18 @@ declare var Coordinates: {
|
|||
new(): Coordinates;
|
||||
}
|
||||
|
||||
interface CryptoKey {
|
||||
readonly algorithm: KeyAlgorithm;
|
||||
readonly extractable: boolean;
|
||||
readonly type: string;
|
||||
readonly usages: string[];
|
||||
}
|
||||
|
||||
declare var CryptoKey: {
|
||||
prototype: CryptoKey;
|
||||
new(): CryptoKey;
|
||||
}
|
||||
|
||||
interface DOMError {
|
||||
readonly name: string;
|
||||
toString(): string;
|
||||
|
@ -323,7 +343,7 @@ interface IDBDatabase extends EventTarget {
|
|||
readonly name: string;
|
||||
readonly objectStoreNames: DOMStringList;
|
||||
onabort: (ev: Event) => any;
|
||||
onerror: (ev: Event) => any;
|
||||
onerror: (ev: ErrorEvent) => any;
|
||||
version: number;
|
||||
onversionchange: (ev: IDBVersionChangeEvent) => any;
|
||||
close(): void;
|
||||
|
@ -426,7 +446,7 @@ declare var IDBOpenDBRequest: {
|
|||
|
||||
interface IDBRequest extends EventTarget {
|
||||
readonly error: DOMError;
|
||||
onerror: (ev: Event) => any;
|
||||
onerror: (ev: ErrorEvent) => any;
|
||||
onsuccess: (ev: Event) => any;
|
||||
readonly readyState: string;
|
||||
readonly result: any;
|
||||
|
@ -448,7 +468,7 @@ interface IDBTransaction extends EventTarget {
|
|||
readonly mode: string;
|
||||
onabort: (ev: Event) => any;
|
||||
oncomplete: (ev: Event) => any;
|
||||
onerror: (ev: Event) => any;
|
||||
onerror: (ev: ErrorEvent) => any;
|
||||
abort(): void;
|
||||
objectStore(name: string): IDBObjectStore;
|
||||
readonly READ_ONLY: string;
|
||||
|
@ -516,7 +536,7 @@ declare var MSApp: MSApp;
|
|||
interface MSAppAsyncOperation extends EventTarget {
|
||||
readonly error: DOMError;
|
||||
oncomplete: (ev: Event) => any;
|
||||
onerror: (ev: Event) => any;
|
||||
onerror: (ev: ErrorEvent) => any;
|
||||
readonly readyState: number;
|
||||
readonly result: any;
|
||||
start(): void;
|
||||
|
@ -665,7 +685,7 @@ interface WebSocket extends EventTarget {
|
|||
readonly bufferedAmount: number;
|
||||
readonly extensions: string;
|
||||
onclose: (ev: CloseEvent) => any;
|
||||
onerror: (ev: Event) => any;
|
||||
onerror: (ev: ErrorEvent) => any;
|
||||
onmessage: (ev: MessageEvent) => any;
|
||||
onopen: (ev: Event) => any;
|
||||
readonly protocol: string;
|
||||
|
@ -708,7 +728,6 @@ declare var Worker: {
|
|||
}
|
||||
|
||||
interface XMLHttpRequest extends EventTarget, XMLHttpRequestEventTarget {
|
||||
msCaching: string;
|
||||
onreadystatechange: (ev: ProgressEvent) => any;
|
||||
readonly readyState: number;
|
||||
readonly response: any;
|
||||
|
@ -720,6 +739,7 @@ interface XMLHttpRequest extends EventTarget, XMLHttpRequestEventTarget {
|
|||
timeout: number;
|
||||
readonly upload: XMLHttpRequestUpload;
|
||||
withCredentials: boolean;
|
||||
msCaching?: string;
|
||||
abort(): void;
|
||||
getAllResponseHeaders(): string;
|
||||
getResponseHeader(header: string): string | null;
|
||||
|
@ -766,14 +786,14 @@ declare var XMLHttpRequestUpload: {
|
|||
}
|
||||
|
||||
interface AbstractWorker {
|
||||
onerror: (ev: Event) => any;
|
||||
onerror: (ev: ErrorEvent) => any;
|
||||
addEventListener(type: "error", listener: (ev: ErrorEvent) => any, useCapture?: boolean): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
|
||||
}
|
||||
|
||||
interface MSBaseReader {
|
||||
onabort: (ev: Event) => any;
|
||||
onerror: (ev: Event) => any;
|
||||
onerror: (ev: ErrorEvent) => any;
|
||||
onload: (ev: Event) => any;
|
||||
onloadend: (ev: ProgressEvent) => any;
|
||||
onloadstart: (ev: Event) => any;
|
||||
|
@ -819,7 +839,7 @@ interface WindowConsole {
|
|||
|
||||
interface XMLHttpRequestEventTarget {
|
||||
onabort: (ev: Event) => any;
|
||||
onerror: (ev: Event) => any;
|
||||
onerror: (ev: ErrorEvent) => any;
|
||||
onload: (ev: Event) => any;
|
||||
onloadend: (ev: ProgressEvent) => any;
|
||||
onloadstart: (ev: Event) => any;
|
||||
|
@ -849,7 +869,7 @@ declare var FileReaderSync: {
|
|||
|
||||
interface WorkerGlobalScope extends EventTarget, WorkerUtils, DedicatedWorkerGlobalScope, WindowConsole {
|
||||
readonly location: WorkerLocation;
|
||||
onerror: (ev: Event) => any;
|
||||
onerror: (ev: ErrorEvent) => any;
|
||||
readonly self: WorkerGlobalScope;
|
||||
close(): void;
|
||||
msWriteProfilerMark(profilerMarkName: string): void;
|
||||
|
@ -905,8 +925,11 @@ interface WorkerUtils extends Object, WindowBase64 {
|
|||
clearInterval(handle: number): void;
|
||||
clearTimeout(handle: number): void;
|
||||
importScripts(...urls: string[]): void;
|
||||
setImmediate(handler: (...args: any[]) => void): number;
|
||||
setImmediate(handler: any, ...args: any[]): number;
|
||||
setInterval(handler: (...args: any[]) => void, timeout: number): number;
|
||||
setInterval(handler: any, timeout?: any, ...args: any[]): number;
|
||||
setTimeout(handler: (...args: any[]) => void, timeout: number): number;
|
||||
setTimeout(handler: any, timeout?: any, ...args: any[]): number;
|
||||
}
|
||||
|
||||
|
@ -942,6 +965,177 @@ interface ProgressEventInit extends EventInit {
|
|||
interface IDBArrayKey extends Array<IDBValidKey> {
|
||||
}
|
||||
|
||||
interface RsaKeyGenParams extends Algorithm {
|
||||
modulusLength: number;
|
||||
publicExponent: Uint8Array;
|
||||
}
|
||||
|
||||
interface RsaHashedKeyGenParams extends RsaKeyGenParams {
|
||||
hash: AlgorithmIdentifier;
|
||||
}
|
||||
|
||||
interface RsaKeyAlgorithm extends KeyAlgorithm {
|
||||
modulusLength: number;
|
||||
publicExponent: Uint8Array;
|
||||
}
|
||||
|
||||
interface RsaHashedKeyAlgorithm extends RsaKeyAlgorithm {
|
||||
hash: AlgorithmIdentifier;
|
||||
}
|
||||
|
||||
interface RsaHashedImportParams {
|
||||
hash: AlgorithmIdentifier;
|
||||
}
|
||||
|
||||
interface RsaPssParams {
|
||||
saltLength: number;
|
||||
}
|
||||
|
||||
interface RsaOaepParams extends Algorithm {
|
||||
label?: BufferSource;
|
||||
}
|
||||
|
||||
interface EcdsaParams extends Algorithm {
|
||||
hash: AlgorithmIdentifier;
|
||||
}
|
||||
|
||||
interface EcKeyGenParams extends Algorithm {
|
||||
typedCurve: string;
|
||||
}
|
||||
|
||||
interface EcKeyAlgorithm extends KeyAlgorithm {
|
||||
typedCurve: string;
|
||||
}
|
||||
|
||||
interface EcKeyImportParams {
|
||||
namedCurve: string;
|
||||
}
|
||||
|
||||
interface EcdhKeyDeriveParams extends Algorithm {
|
||||
public: CryptoKey;
|
||||
}
|
||||
|
||||
interface AesCtrParams extends Algorithm {
|
||||
counter: BufferSource;
|
||||
length: number;
|
||||
}
|
||||
|
||||
interface AesKeyAlgorithm extends KeyAlgorithm {
|
||||
length: number;
|
||||
}
|
||||
|
||||
interface AesKeyGenParams extends Algorithm {
|
||||
length: number;
|
||||
}
|
||||
|
||||
interface AesDerivedKeyParams extends Algorithm {
|
||||
length: number;
|
||||
}
|
||||
|
||||
interface AesCbcParams extends Algorithm {
|
||||
iv: BufferSource;
|
||||
}
|
||||
|
||||
interface AesCmacParams extends Algorithm {
|
||||
length: number;
|
||||
}
|
||||
|
||||
interface AesGcmParams extends Algorithm {
|
||||
iv: BufferSource;
|
||||
additionalData?: BufferSource;
|
||||
tagLength?: number;
|
||||
}
|
||||
|
||||
interface AesCfbParams extends Algorithm {
|
||||
iv: BufferSource;
|
||||
}
|
||||
|
||||
interface HmacImportParams extends Algorithm {
|
||||
hash?: AlgorithmIdentifier;
|
||||
length?: number;
|
||||
}
|
||||
|
||||
interface HmacKeyAlgorithm extends KeyAlgorithm {
|
||||
hash: AlgorithmIdentifier;
|
||||
length: number;
|
||||
}
|
||||
|
||||
interface HmacKeyGenParams extends Algorithm {
|
||||
hash: AlgorithmIdentifier;
|
||||
length?: number;
|
||||
}
|
||||
|
||||
interface DhKeyGenParams extends Algorithm {
|
||||
prime: Uint8Array;
|
||||
generator: Uint8Array;
|
||||
}
|
||||
|
||||
interface DhKeyAlgorithm extends KeyAlgorithm {
|
||||
prime: Uint8Array;
|
||||
generator: Uint8Array;
|
||||
}
|
||||
|
||||
interface DhKeyDeriveParams extends Algorithm {
|
||||
public: CryptoKey;
|
||||
}
|
||||
|
||||
interface DhImportKeyParams extends Algorithm {
|
||||
prime: Uint8Array;
|
||||
generator: Uint8Array;
|
||||
}
|
||||
|
||||
interface ConcatParams extends Algorithm {
|
||||
hash?: AlgorithmIdentifier;
|
||||
algorithmId: Uint8Array;
|
||||
partyUInfo: Uint8Array;
|
||||
partyVInfo: Uint8Array;
|
||||
publicInfo?: Uint8Array;
|
||||
privateInfo?: Uint8Array;
|
||||
}
|
||||
|
||||
interface HkdfCtrParams extends Algorithm {
|
||||
hash: AlgorithmIdentifier;
|
||||
label: BufferSource;
|
||||
context: BufferSource;
|
||||
}
|
||||
|
||||
interface Pbkdf2Params extends Algorithm {
|
||||
salt: BufferSource;
|
||||
iterations: number;
|
||||
hash: AlgorithmIdentifier;
|
||||
}
|
||||
|
||||
interface RsaOtherPrimesInfo {
|
||||
r: string;
|
||||
d: string;
|
||||
t: string;
|
||||
}
|
||||
|
||||
interface JsonWebKey {
|
||||
kty: string;
|
||||
use?: string;
|
||||
key_ops?: string[];
|
||||
alg?: string;
|
||||
kid?: string;
|
||||
x5u?: string;
|
||||
x5c?: string;
|
||||
x5t?: string;
|
||||
ext?: boolean;
|
||||
crv?: string;
|
||||
x?: string;
|
||||
y?: string;
|
||||
d?: string;
|
||||
n?: string;
|
||||
e?: string;
|
||||
p?: string;
|
||||
q?: string;
|
||||
dp?: string;
|
||||
dq?: string;
|
||||
qi?: string;
|
||||
oth?: RsaOtherPrimesInfo[];
|
||||
k?: string;
|
||||
}
|
||||
|
||||
declare type EventListenerOrEventListenerObject = EventListener | EventListenerObject;
|
||||
|
||||
interface ErrorEventHandler {
|
||||
|
@ -975,7 +1169,7 @@ interface FunctionStringCallback {
|
|||
(data: string): void;
|
||||
}
|
||||
declare var location: WorkerLocation;
|
||||
declare var onerror: (ev: Event) => any;
|
||||
declare var onerror: (ev: ErrorEvent) => any;
|
||||
declare var self: WorkerGlobalScope;
|
||||
declare function close(): void;
|
||||
declare function msWriteProfilerMark(profilerMarkName: string): void;
|
||||
|
@ -990,8 +1184,11 @@ declare function clearImmediate(handle: number): void;
|
|||
declare function clearInterval(handle: number): void;
|
||||
declare function clearTimeout(handle: number): void;
|
||||
declare function importScripts(...urls: string[]): void;
|
||||
declare function setImmediate(handler: (...args: any[]) => void): number;
|
||||
declare function setImmediate(handler: any, ...args: any[]): number;
|
||||
declare function setInterval(handler: (...args: any[]) => void, timeout: number): number;
|
||||
declare function setInterval(handler: any, timeout?: any, ...args: any[]): number;
|
||||
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): number;
|
||||
declare function setTimeout(handler: any, timeout?: any, ...args: any[]): number;
|
||||
declare function atob(encodedString: string): string;
|
||||
declare function btoa(rawString: string): string;
|
||||
|
@ -1001,5 +1198,7 @@ declare var console: Console;
|
|||
declare function addEventListener(type: "error", listener: (ev: ErrorEvent) => any, useCapture?: boolean): void;
|
||||
declare function addEventListener(type: "message", listener: (ev: MessageEvent) => any, useCapture?: boolean): void;
|
||||
declare function addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
|
||||
type AlgorithmIdentifier = string | Algorithm;
|
||||
type IDBKeyPath = string;
|
||||
type IDBValidKey = number | string | Date | IDBArrayKey;
|
||||
type IDBValidKey = number | string | Date | IDBArrayKey;
|
||||
type BufferSource = ArrayBuffer | ArrayBufferView;
|
|
@ -45,8 +45,9 @@ namespace ts.server {
|
|||
return lineMap;
|
||||
}
|
||||
|
||||
private lineOffsetToPosition(fileName: string, lineOffset: protocol.Location): number {
|
||||
return ts.computePositionOfLineAndCharacter(this.getLineMap(fileName), lineOffset.line - 1, lineOffset.offset - 1);
|
||||
private lineOffsetToPosition(fileName: string, lineOffset: protocol.Location, lineMap?: number[]): number {
|
||||
lineMap = lineMap || this.getLineMap(fileName);
|
||||
return ts.computePositionOfLineAndCharacter(lineMap, lineOffset.line - 1, lineOffset.offset - 1);
|
||||
}
|
||||
|
||||
private positionToOneBasedLineOffset(fileName: string, position: number): protocol.Location {
|
||||
|
@ -449,7 +450,7 @@ namespace ts.server {
|
|||
return this.lastRenameEntry.locations;
|
||||
}
|
||||
|
||||
decodeNavigationBarItems(items: protocol.NavigationBarItem[], fileName: string): NavigationBarItem[] {
|
||||
decodeNavigationBarItems(items: protocol.NavigationBarItem[], fileName: string, lineMap: number[]): NavigationBarItem[] {
|
||||
if (!items) {
|
||||
return [];
|
||||
}
|
||||
|
@ -458,8 +459,11 @@ namespace ts.server {
|
|||
text: item.text,
|
||||
kind: item.kind,
|
||||
kindModifiers: item.kindModifiers || "",
|
||||
spans: item.spans.map(span => createTextSpanFromBounds(this.lineOffsetToPosition(fileName, span.start), this.lineOffsetToPosition(fileName, span.end))),
|
||||
childItems: this.decodeNavigationBarItems(item.childItems, fileName),
|
||||
spans: item.spans.map(span =>
|
||||
createTextSpanFromBounds(
|
||||
this.lineOffsetToPosition(fileName, span.start, lineMap),
|
||||
this.lineOffsetToPosition(fileName, span.end, lineMap))),
|
||||
childItems: this.decodeNavigationBarItems(item.childItems, fileName, lineMap),
|
||||
indent: item.indent,
|
||||
bolded: false,
|
||||
grayed: false
|
||||
|
@ -474,7 +478,8 @@ namespace ts.server {
|
|||
const request = this.processRequest<protocol.NavBarRequest>(CommandNames.NavBar, args);
|
||||
const response = this.processResponse<protocol.NavBarResponse>(request);
|
||||
|
||||
return this.decodeNavigationBarItems(response.body, fileName);
|
||||
const lineMap = this.getLineMap(fileName);
|
||||
return this.decodeNavigationBarItems(response.body, fileName, lineMap);
|
||||
}
|
||||
|
||||
getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): TextSpan {
|
||||
|
|
|
@ -27,6 +27,8 @@ namespace ts.server {
|
|||
});
|
||||
}
|
||||
|
||||
export const maxProgramSizeForNonTsFiles = 20 * 1024 * 1024;
|
||||
|
||||
export class ScriptInfo {
|
||||
svc: ScriptVersionCache;
|
||||
children: ScriptInfo[] = []; // files referenced by this file
|
||||
|
@ -357,18 +359,23 @@ namespace ts.server {
|
|||
* @param line 1-based index
|
||||
* @param offset 1-based index
|
||||
*/
|
||||
positionToLineOffset(filename: string, position: number): ILineInfo {
|
||||
positionToLineOffset(filename: string, position: number, lineIndex?: LineIndex): ILineInfo {
|
||||
lineIndex = lineIndex || this.getLineIndex(filename);
|
||||
const lineOffset = lineIndex.charOffsetToLineNumberAndPos(position);
|
||||
return { line: lineOffset.line, offset: lineOffset.offset + 1 };
|
||||
}
|
||||
|
||||
getLineIndex(filename: string): LineIndex {
|
||||
const path = toPath(filename, this.host.getCurrentDirectory(), this.getCanonicalFileName);
|
||||
const script: ScriptInfo = this.filenameToScript.get(path);
|
||||
const index = script.snap().index;
|
||||
const lineOffset = index.charOffsetToLineNumberAndPos(position);
|
||||
return { line: lineOffset.line, offset: lineOffset.offset + 1 };
|
||||
return script.snap().index;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ProjectOptions {
|
||||
// these fields can be present in the project file
|
||||
files?: string[];
|
||||
wildcardDirectories?: ts.Map<ts.WatchDirectoryFlags>;
|
||||
compilerOptions?: ts.CompilerOptions;
|
||||
}
|
||||
|
||||
|
@ -377,6 +384,7 @@ namespace ts.server {
|
|||
projectFilename: string;
|
||||
projectFileWatcher: FileWatcher;
|
||||
directoryWatcher: FileWatcher;
|
||||
directoriesWatchedForWildcards: Map<FileWatcher>;
|
||||
// Used to keep track of what directories are watched for this project
|
||||
directoriesWatchedForTsconfig: string[] = [];
|
||||
program: ts.Program;
|
||||
|
@ -385,12 +393,29 @@ namespace ts.server {
|
|||
/** Used for configured projects which may have multiple open roots */
|
||||
openRefCount = 0;
|
||||
|
||||
constructor(public projectService: ProjectService, public projectOptions?: ProjectOptions) {
|
||||
constructor(
|
||||
public projectService: ProjectService,
|
||||
public projectOptions?: ProjectOptions,
|
||||
public languageServiceDiabled = false) {
|
||||
if (projectOptions && projectOptions.files) {
|
||||
// If files are listed explicitly, allow all extensions
|
||||
projectOptions.compilerOptions.allowNonTsExtensions = true;
|
||||
}
|
||||
this.compilerService = new CompilerService(this, projectOptions && projectOptions.compilerOptions);
|
||||
if (!languageServiceDiabled) {
|
||||
this.compilerService = new CompilerService(this, projectOptions && projectOptions.compilerOptions);
|
||||
}
|
||||
}
|
||||
|
||||
enableLanguageService() {
|
||||
// if the language service was disabled, we should re-initiate the compiler service
|
||||
if (this.languageServiceDiabled) {
|
||||
this.compilerService = new CompilerService(this, this.projectOptions && this.projectOptions.compilerOptions);
|
||||
}
|
||||
this.languageServiceDiabled = false;
|
||||
}
|
||||
|
||||
disableLanguageService() {
|
||||
this.languageServiceDiabled = true;
|
||||
}
|
||||
|
||||
addOpenRef() {
|
||||
|
@ -407,19 +432,45 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
getRootFiles() {
|
||||
if (this.languageServiceDiabled) {
|
||||
// When the languageService was disabled, only return file list if it is a configured project
|
||||
return this.projectOptions ? this.projectOptions.files : undefined;
|
||||
}
|
||||
|
||||
return this.compilerService.host.roots.map(info => info.fileName);
|
||||
}
|
||||
|
||||
getFileNames() {
|
||||
if (this.languageServiceDiabled) {
|
||||
if (!this.projectOptions) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const fileNames: string[] = [];
|
||||
if (this.projectOptions && this.projectOptions.compilerOptions) {
|
||||
fileNames.push(getDefaultLibFilePath(this.projectOptions.compilerOptions));
|
||||
}
|
||||
ts.addRange(fileNames, this.projectOptions.files);
|
||||
return fileNames;
|
||||
}
|
||||
|
||||
const sourceFiles = this.program.getSourceFiles();
|
||||
return sourceFiles.map(sourceFile => sourceFile.fileName);
|
||||
}
|
||||
|
||||
getSourceFile(info: ScriptInfo) {
|
||||
if (this.languageServiceDiabled) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.filenameToSourceFile[info.fileName];
|
||||
}
|
||||
|
||||
getSourceFileFromName(filename: string, requireOpen?: boolean) {
|
||||
if (this.languageServiceDiabled) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const info = this.projectService.getScriptInfo(filename);
|
||||
if (info) {
|
||||
if ((!requireOpen) || info.isOpen) {
|
||||
|
@ -429,15 +480,27 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
isRoot(info: ScriptInfo) {
|
||||
if (this.languageServiceDiabled) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.compilerService.host.roots.some(root => root === info);
|
||||
}
|
||||
|
||||
removeReferencedFile(info: ScriptInfo) {
|
||||
if (this.languageServiceDiabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.compilerService.host.removeReferencedFile(info);
|
||||
this.updateGraph();
|
||||
}
|
||||
|
||||
updateFileMap() {
|
||||
if (this.languageServiceDiabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.filenameToSourceFile = {};
|
||||
const sourceFiles = this.program.getSourceFiles();
|
||||
for (let i = 0, len = sourceFiles.length; i < len; i++) {
|
||||
|
@ -447,11 +510,19 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
finishGraph() {
|
||||
if (this.languageServiceDiabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateGraph();
|
||||
this.compilerService.languageService.getNavigateToItems(".*");
|
||||
}
|
||||
|
||||
updateGraph() {
|
||||
if (this.languageServiceDiabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.program = this.compilerService.languageService.getProgram();
|
||||
this.updateFileMap();
|
||||
}
|
||||
|
@ -462,15 +533,32 @@ namespace ts.server {
|
|||
|
||||
// add a root file to project
|
||||
addRoot(info: ScriptInfo) {
|
||||
if (this.languageServiceDiabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.compilerService.host.addRoot(info);
|
||||
}
|
||||
|
||||
// remove a root file from project
|
||||
removeRoot(info: ScriptInfo) {
|
||||
if (this.languageServiceDiabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.compilerService.host.removeRoot(info);
|
||||
}
|
||||
|
||||
filesToString() {
|
||||
if (this.languageServiceDiabled) {
|
||||
if (this.projectOptions) {
|
||||
let strBuilder = "";
|
||||
ts.forEach(this.projectOptions.files,
|
||||
file => { strBuilder += file + "\n"; });
|
||||
return strBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
let strBuilder = "";
|
||||
ts.forEachValue(this.filenameToSourceFile,
|
||||
sourceFile => { strBuilder += sourceFile.fileName + "\n"; });
|
||||
|
@ -481,7 +569,9 @@ namespace ts.server {
|
|||
this.projectOptions = projectOptions;
|
||||
if (projectOptions.compilerOptions) {
|
||||
projectOptions.compilerOptions.allowNonTsExtensions = true;
|
||||
this.compilerService.setCompilerOptions(projectOptions.compilerOptions);
|
||||
if (!this.languageServiceDiabled) {
|
||||
this.compilerService.setCompilerOptions(projectOptions.compilerOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -764,6 +854,8 @@ namespace ts.server {
|
|||
if (project.isConfiguredProject()) {
|
||||
project.projectFileWatcher.close();
|
||||
project.directoryWatcher.close();
|
||||
forEachValue(project.directoriesWatchedForWildcards, watcher => { watcher.close(); });
|
||||
delete project.directoriesWatchedForWildcards;
|
||||
this.configuredProjects = copyListRemovingItem(project, this.configuredProjects);
|
||||
}
|
||||
else {
|
||||
|
@ -807,6 +899,7 @@ namespace ts.server {
|
|||
else {
|
||||
this.findReferencingProjects(info);
|
||||
if (info.defaultProject) {
|
||||
info.defaultProject.addOpenRef();
|
||||
this.openFilesReferenced.push(info);
|
||||
}
|
||||
else {
|
||||
|
@ -1255,12 +1348,30 @@ namespace ts.server {
|
|||
else {
|
||||
const projectOptions: ProjectOptions = {
|
||||
files: parsedCommandLine.fileNames,
|
||||
compilerOptions: parsedCommandLine.options
|
||||
wildcardDirectories: parsedCommandLine.wildcardDirectories,
|
||||
compilerOptions: parsedCommandLine.options,
|
||||
};
|
||||
return { succeeded: true, projectOptions };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private exceedTotalNonTsFileSizeLimit(fileNames: string[]) {
|
||||
let totalNonTsFileSize = 0;
|
||||
if (!this.host.getFileSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const fileName of fileNames) {
|
||||
if (hasTypeScriptFileExtension(fileName)) {
|
||||
continue;
|
||||
}
|
||||
totalNonTsFileSize += this.host.getFileSize(fileName);
|
||||
if (totalNonTsFileSize > maxProgramSizeForNonTsFiles) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
openConfigFile(configFilename: string, clientFileName?: string): { success: boolean, project?: Project, errors?: Diagnostic[] } {
|
||||
|
@ -1269,6 +1380,19 @@ namespace ts.server {
|
|||
return { success: false, errors };
|
||||
}
|
||||
else {
|
||||
if (!projectOptions.compilerOptions.disableSizeLimit && projectOptions.compilerOptions.allowJs) {
|
||||
if (this.exceedTotalNonTsFileSizeLimit(projectOptions.files)) {
|
||||
const project = this.createProject(configFilename, projectOptions, /*languageServiceDisabled*/ true);
|
||||
|
||||
// for configured projects with languageService disabled, we only watch its config file,
|
||||
// do not care about the directory changes in the folder.
|
||||
project.projectFileWatcher = this.host.watchFile(
|
||||
toPath(configFilename, configFilename, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)),
|
||||
_ => this.watchedProjectConfigFileChanged(project));
|
||||
return { success: true, project };
|
||||
}
|
||||
}
|
||||
|
||||
const project = this.createProject(configFilename, projectOptions);
|
||||
let errors: Diagnostic[];
|
||||
for (const rootFilename of projectOptions.files) {
|
||||
|
@ -1282,17 +1406,35 @@ namespace ts.server {
|
|||
}
|
||||
project.finishGraph();
|
||||
project.projectFileWatcher = this.host.watchFile(configFilename, _ => this.watchedProjectConfigFileChanged(project));
|
||||
this.log("Add recursive watcher for: " + ts.getDirectoryPath(configFilename));
|
||||
|
||||
const configDirectoryPath = ts.getDirectoryPath(configFilename);
|
||||
|
||||
this.log("Add recursive watcher for: " + configDirectoryPath);
|
||||
project.directoryWatcher = this.host.watchDirectory(
|
||||
ts.getDirectoryPath(configFilename),
|
||||
configDirectoryPath,
|
||||
path => this.directoryWatchedForSourceFilesChanged(project, path),
|
||||
/*recursive*/ true
|
||||
);
|
||||
|
||||
project.directoriesWatchedForWildcards = reduceProperties(projectOptions.wildcardDirectories, (watchers, flag, directory) => {
|
||||
if (comparePaths(configDirectoryPath, directory, ".", !this.host.useCaseSensitiveFileNames) !== Comparison.EqualTo) {
|
||||
const recursive = (flag & WatchDirectoryFlags.Recursive) !== 0;
|
||||
this.log(`Add ${ recursive ? "recursive " : ""}watcher for: ${directory}`);
|
||||
watchers[directory] = this.host.watchDirectory(
|
||||
directory,
|
||||
path => this.directoryWatchedForSourceFilesChanged(project, path),
|
||||
recursive
|
||||
);
|
||||
}
|
||||
|
||||
return watchers;
|
||||
}, <Map<FileWatcher>>{});
|
||||
|
||||
return { success: true, project: project, errors };
|
||||
}
|
||||
}
|
||||
|
||||
updateConfiguredProject(project: Project) {
|
||||
updateConfiguredProject(project: Project): Diagnostic[] {
|
||||
if (!this.host.fileExists(project.projectFilename)) {
|
||||
this.log("Config file deleted");
|
||||
this.removeProject(project);
|
||||
|
@ -1303,7 +1445,43 @@ namespace ts.server {
|
|||
return errors;
|
||||
}
|
||||
else {
|
||||
const oldFileNames = project.compilerService.host.roots.map(info => info.fileName);
|
||||
if (projectOptions.compilerOptions && !projectOptions.compilerOptions.disableSizeLimit && this.exceedTotalNonTsFileSizeLimit(projectOptions.files)) {
|
||||
project.setProjectOptions(projectOptions);
|
||||
if (project.languageServiceDiabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
project.disableLanguageService();
|
||||
if (project.directoryWatcher) {
|
||||
project.directoryWatcher.close();
|
||||
project.directoryWatcher = undefined;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (project.languageServiceDiabled) {
|
||||
project.setProjectOptions(projectOptions);
|
||||
project.enableLanguageService();
|
||||
project.directoryWatcher = this.host.watchDirectory(
|
||||
ts.getDirectoryPath(project.projectFilename),
|
||||
path => this.directoryWatchedForSourceFilesChanged(project, path),
|
||||
/*recursive*/ true
|
||||
);
|
||||
|
||||
for (const rootFilename of projectOptions.files) {
|
||||
if (this.host.fileExists(rootFilename)) {
|
||||
const info = this.openFile(rootFilename, /*openedByClient*/ false);
|
||||
project.addRoot(info);
|
||||
}
|
||||
}
|
||||
project.finishGraph();
|
||||
return;
|
||||
}
|
||||
|
||||
// if the project is too large, the root files might not have been all loaded if the total
|
||||
// program size reached the upper limit. In that case project.projectOptions.files should
|
||||
// be more precise. However this would only happen for configured project.
|
||||
const oldFileNames = project.projectOptions ? project.projectOptions.files : project.compilerService.host.roots.map(info => info.fileName);
|
||||
const newFileNames = ts.filter(projectOptions.files, f => this.host.fileExists(f));
|
||||
const fileNamesToRemove = oldFileNames.filter(f => newFileNames.indexOf(f) < 0);
|
||||
const fileNamesToAdd = newFileNames.filter(f => oldFileNames.indexOf(f) < 0);
|
||||
|
@ -1346,8 +1524,8 @@ namespace ts.server {
|
|||
}
|
||||
}
|
||||
|
||||
createProject(projectFilename: string, projectOptions?: ProjectOptions) {
|
||||
const project = new Project(this, projectOptions);
|
||||
createProject(projectFilename: string, projectOptions?: ProjectOptions, languageServiceDisabled?: boolean) {
|
||||
const project = new Project(this, projectOptions, languageServiceDisabled);
|
||||
project.projectFilename = projectFilename;
|
||||
return project;
|
||||
}
|
||||
|
|
|
@ -123,6 +123,10 @@ declare namespace ts.server.protocol {
|
|||
* The list of normalized file name in the project, including 'lib.d.ts'
|
||||
*/
|
||||
fileNames?: string[];
|
||||
/**
|
||||
* Indicates if the project has a active language service instance
|
||||
*/
|
||||
languageServiceDisabled?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -313,7 +313,7 @@ namespace ts.server {
|
|||
private getDefinition(line: number, offset: number, fileName: string): protocol.FileSpan[] {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
|
@ -335,7 +335,7 @@ namespace ts.server {
|
|||
private getTypeDefinition(line: number, offset: number, fileName: string): protocol.FileSpan[] {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
|
@ -358,7 +358,7 @@ namespace ts.server {
|
|||
fileName = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(fileName);
|
||||
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
|
@ -388,7 +388,7 @@ namespace ts.server {
|
|||
fileName = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(fileName);
|
||||
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
|
@ -423,15 +423,18 @@ namespace ts.server {
|
|||
private getProjectInfo(fileName: string, needFileNameList: boolean): protocol.ProjectInfo {
|
||||
fileName = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(fileName);
|
||||
if (!project) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
const projectInfo: protocol.ProjectInfo = {
|
||||
configFileName: project.projectFilename
|
||||
configFileName: project.projectFilename,
|
||||
languageServiceDisabled: project.languageServiceDiabled
|
||||
};
|
||||
|
||||
if (needFileNameList) {
|
||||
projectInfo.fileNames = project.getFileNames();
|
||||
}
|
||||
|
||||
return projectInfo;
|
||||
}
|
||||
|
||||
|
@ -439,11 +442,12 @@ namespace ts.server {
|
|||
const file = ts.normalizePath(fileName);
|
||||
const info = this.projectService.getScriptInfo(file);
|
||||
const projects = this.projectService.findReferencingProjects(info);
|
||||
if (!projects.length) {
|
||||
const projectsWithLanguageServiceEnabeld = ts.filter(projects, p => !p.languageServiceDiabled);
|
||||
if (projectsWithLanguageServiceEnabeld.length === 0) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
const defaultProject = projects[0];
|
||||
const defaultProject = projectsWithLanguageServiceEnabeld[0];
|
||||
// The rename info should be the same for every project
|
||||
const defaultProjectCompilerService = defaultProject.compilerService;
|
||||
const position = defaultProjectCompilerService.host.lineOffsetToPosition(file, line, offset);
|
||||
|
@ -460,7 +464,7 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
const fileSpans = combineProjectOutput(
|
||||
projects,
|
||||
projectsWithLanguageServiceEnabeld,
|
||||
(project: Project) => {
|
||||
const compilerService = project.compilerService;
|
||||
const renameLocations = compilerService.languageService.findRenameLocations(file, position, findInStrings, findInComments);
|
||||
|
@ -521,11 +525,12 @@ namespace ts.server {
|
|||
const file = ts.normalizePath(fileName);
|
||||
const info = this.projectService.getScriptInfo(file);
|
||||
const projects = this.projectService.findReferencingProjects(info);
|
||||
if (!projects.length) {
|
||||
const projectsWithLanguageServiceEnabeld = ts.filter(projects, p => !p.languageServiceDiabled);
|
||||
if (projectsWithLanguageServiceEnabeld.length === 0) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
const defaultProject = projects[0];
|
||||
const defaultProject = projectsWithLanguageServiceEnabeld[0];
|
||||
const position = defaultProject.compilerService.host.lineOffsetToPosition(file, line, offset);
|
||||
const nameInfo = defaultProject.compilerService.languageService.getQuickInfoAtPosition(file, position);
|
||||
if (!nameInfo) {
|
||||
|
@ -537,7 +542,7 @@ namespace ts.server {
|
|||
const nameColStart = defaultProject.compilerService.host.positionToLineOffset(file, nameSpan.start).offset;
|
||||
const nameText = defaultProject.compilerService.host.getScriptSnapshot(file).getText(nameSpan.start, ts.textSpanEnd(nameSpan));
|
||||
const refs = combineProjectOutput<protocol.ReferencesResponseItem>(
|
||||
projects,
|
||||
projectsWithLanguageServiceEnabeld,
|
||||
(project: Project) => {
|
||||
const compilerService = project.compilerService;
|
||||
const references = compilerService.languageService.getReferencesAtPosition(file, position);
|
||||
|
@ -596,7 +601,7 @@ namespace ts.server {
|
|||
private getQuickInfo(line: number, offset: number, fileName: string): protocol.QuickInfoResponseBody {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
|
@ -622,7 +627,7 @@ namespace ts.server {
|
|||
private getFormattingEditsForRange(line: number, offset: number, endLine: number, endOffset: number, fileName: string): protocol.CodeEdit[] {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
|
@ -650,7 +655,7 @@ namespace ts.server {
|
|||
const file = ts.normalizePath(fileName);
|
||||
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
|
@ -728,7 +733,7 @@ namespace ts.server {
|
|||
}
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
|
@ -752,7 +757,7 @@ namespace ts.server {
|
|||
entryNames: string[], fileName: string): protocol.CompletionEntryDetails[] {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
|
@ -771,7 +776,7 @@ namespace ts.server {
|
|||
private getSignatureHelpItems(line: number, offset: number, fileName: string): protocol.SignatureHelpItems {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
|
@ -801,7 +806,7 @@ namespace ts.server {
|
|||
const checkList = fileNames.reduce((accum: PendingErrorCheck[], fileName: string) => {
|
||||
fileName = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(fileName);
|
||||
if (project) {
|
||||
if (project && !project.languageServiceDiabled) {
|
||||
accum.push({ fileName, project });
|
||||
}
|
||||
return accum;
|
||||
|
@ -815,7 +820,7 @@ namespace ts.server {
|
|||
private change(line: number, offset: number, endLine: number, endOffset: number, insertString: string, fileName: string) {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (project) {
|
||||
if (project && !project.languageServiceDiabled) {
|
||||
const compilerService = project.compilerService;
|
||||
const start = compilerService.host.lineOffsetToPosition(file, line, offset);
|
||||
const end = compilerService.host.lineOffsetToPosition(file, endLine, endOffset);
|
||||
|
@ -831,7 +836,7 @@ namespace ts.server {
|
|||
const file = ts.normalizePath(fileName);
|
||||
const tmpfile = ts.normalizePath(tempFileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (project) {
|
||||
if (project && !project.languageServiceDiabled) {
|
||||
this.changeSeq++;
|
||||
// make sure no changes happen before this one is finished
|
||||
project.compilerService.host.reloadScript(file, tmpfile, () => {
|
||||
|
@ -845,7 +850,7 @@ namespace ts.server {
|
|||
const tmpfile = ts.normalizePath(tempFileName);
|
||||
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (project) {
|
||||
if (project && !project.languageServiceDiabled) {
|
||||
project.compilerService.host.saveTo(file, tmpfile);
|
||||
}
|
||||
}
|
||||
|
@ -858,7 +863,7 @@ namespace ts.server {
|
|||
this.projectService.closeClientFile(file);
|
||||
}
|
||||
|
||||
private decorateNavigationBarItem(project: Project, fileName: string, items: ts.NavigationBarItem[]): protocol.NavigationBarItem[] {
|
||||
private decorateNavigationBarItem(project: Project, fileName: string, items: ts.NavigationBarItem[], lineIndex: LineIndex): protocol.NavigationBarItem[] {
|
||||
if (!items) {
|
||||
return undefined;
|
||||
}
|
||||
|
@ -870,10 +875,10 @@ namespace ts.server {
|
|||
kind: item.kind,
|
||||
kindModifiers: item.kindModifiers,
|
||||
spans: item.spans.map(span => ({
|
||||
start: compilerService.host.positionToLineOffset(fileName, span.start),
|
||||
end: compilerService.host.positionToLineOffset(fileName, ts.textSpanEnd(span))
|
||||
start: compilerService.host.positionToLineOffset(fileName, span.start, lineIndex),
|
||||
end: compilerService.host.positionToLineOffset(fileName, ts.textSpanEnd(span), lineIndex)
|
||||
})),
|
||||
childItems: this.decorateNavigationBarItem(project, fileName, item.childItems),
|
||||
childItems: this.decorateNavigationBarItem(project, fileName, item.childItems, lineIndex),
|
||||
indent: item.indent
|
||||
}));
|
||||
}
|
||||
|
@ -881,7 +886,7 @@ namespace ts.server {
|
|||
private getNavigationBarItems(fileName: string): protocol.NavigationBarItem[] {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
|
@ -891,20 +896,20 @@ namespace ts.server {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
return this.decorateNavigationBarItem(project, fileName, items);
|
||||
return this.decorateNavigationBarItem(project, fileName, items, compilerService.host.getLineIndex(fileName));
|
||||
}
|
||||
|
||||
private getNavigateToItems(searchValue: string, fileName: string, maxResultCount?: number): protocol.NavtoItem[] {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const info = this.projectService.getScriptInfo(file);
|
||||
const projects = this.projectService.findReferencingProjects(info);
|
||||
const defaultProject = projects[0];
|
||||
if (!defaultProject) {
|
||||
const projectsWithLanguageServiceEnabeld = ts.filter(projects, p => !p.languageServiceDiabled);
|
||||
if (projectsWithLanguageServiceEnabeld.length === 0) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
const allNavToItems = combineProjectOutput(
|
||||
projects,
|
||||
projectsWithLanguageServiceEnabeld,
|
||||
(project: Project) => {
|
||||
const compilerService = project.compilerService;
|
||||
const navItems = compilerService.languageService.getNavigateToItems(searchValue, maxResultCount);
|
||||
|
@ -956,7 +961,7 @@ namespace ts.server {
|
|||
const file = ts.normalizePath(fileName);
|
||||
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
|
@ -975,7 +980,11 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
getDiagnosticsForProject(delay: number, fileName: string) {
|
||||
const { fileNames } = this.getProjectInfo(fileName, /*needFileNameList*/ true);
|
||||
const { fileNames, languageServiceDisabled } = this.getProjectInfo(fileName, /*needFileNameList*/ true);
|
||||
if (languageServiceDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No need to analyze lib.d.ts
|
||||
let fileNamesInProject = fileNames.filter((value, index, array) => value.indexOf("lib.d.ts") < 0);
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace ts.JsTyping {
|
|||
directoryExists: (path: string) => boolean;
|
||||
fileExists: (fileName: string) => boolean;
|
||||
readFile: (path: string, encoding?: string) => string;
|
||||
readDirectory: (path: string, extension?: string, exclude?: string[], depth?: number) => string[];
|
||||
readDirectory: (rootDir: string, extensions: string[], excludes: string[], includes: string[], depth?: number) => string[];
|
||||
};
|
||||
|
||||
interface PackageJson {
|
||||
|
@ -187,7 +187,7 @@ namespace ts.JsTyping {
|
|||
}
|
||||
|
||||
const typingNames: string[] = [];
|
||||
const fileNames = host.readDirectory(nodeModulesPath, "*.json", /*exclude*/ undefined, /*depth*/ 2);
|
||||
const fileNames = host.readDirectory(nodeModulesPath, ["*.json"], /*excludes*/ undefined, /*includes*/ undefined, /*depth*/ 2);
|
||||
for (const fileName of fileNames) {
|
||||
const normalizedFileName = normalizePath(fileName);
|
||||
if (getBaseFileName(normalizedFileName) !== "package.json") {
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,4 +1,5 @@
|
|||
/// <reference path="..\compiler\program.ts"/>
|
||||
/// <reference path="..\compiler\commandLineParser.ts"/>
|
||||
|
||||
/// <reference path='breakpoints.ts' />
|
||||
/// <reference path='outliningElementsCollector.ts' />
|
||||
|
@ -2001,6 +2002,18 @@ namespace ts {
|
|||
// so pass --noLib to avoid reporting a file not found error.
|
||||
options.noLib = true;
|
||||
|
||||
// Clear out other settings that would not be used in transpiling this module
|
||||
options.lib = undefined;
|
||||
options.types = undefined;
|
||||
options.noEmit = undefined;
|
||||
options.noEmitOnError = undefined;
|
||||
options.paths = undefined;
|
||||
options.rootDirs = undefined;
|
||||
options.declaration = undefined;
|
||||
options.declarationDir = undefined;
|
||||
options.out = undefined;
|
||||
options.outFile = undefined;
|
||||
|
||||
// We are not doing a full typecheck, we are not resolving the whole context,
|
||||
// so pass --noResolve to avoid reporting missing file errors.
|
||||
options.noResolve = true;
|
||||
|
@ -2978,7 +2991,8 @@ namespace ts {
|
|||
oldSettings.moduleResolution !== newSettings.moduleResolution ||
|
||||
oldSettings.noResolve !== newSettings.noResolve ||
|
||||
oldSettings.jsx !== newSettings.jsx ||
|
||||
oldSettings.allowJs !== newSettings.allowJs);
|
||||
oldSettings.allowJs !== newSettings.allowJs ||
|
||||
oldSettings.disableSizeLimit !== oldSettings.disableSizeLimit);
|
||||
|
||||
// Now create a new compiler
|
||||
const compilerHost: CompilerHost = {
|
||||
|
@ -7033,7 +7047,7 @@ namespace ts {
|
|||
function getNavigationBarItems(fileName: string): NavigationBarItem[] {
|
||||
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
|
||||
|
||||
return NavigationBar.getNavigationBarItems(sourceFile, host.getCompilationSettings());
|
||||
return NavigationBar.getNavigationBarItems(sourceFile);
|
||||
}
|
||||
|
||||
function getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[] {
|
||||
|
@ -7527,7 +7541,8 @@ namespace ts {
|
|||
return;
|
||||
case SyntaxKind.Parameter:
|
||||
if ((<ParameterDeclaration>token.parent).name === token) {
|
||||
return ClassificationType.parameterName;
|
||||
const isThis = token.kind === SyntaxKind.Identifier && (<Identifier>token).originalKeywordKind === SyntaxKind.ThisKeyword;
|
||||
return isThis ? ClassificationType.keyword : ClassificationType.parameterName;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -80,8 +80,9 @@ namespace ts {
|
|||
* @param exclude A JSON encoded string[] containing the paths to exclude
|
||||
* when enumerating the directory.
|
||||
*/
|
||||
readDirectory(rootDir: string, extension: string, exclude?: string, depth?: number): string;
|
||||
|
||||
readDirectory(rootDir: string, extension: string, basePaths?: string, excludeEx?: string, includeFileEx?: string, includeDirEx?: string, depth?: number): string;
|
||||
useCaseSensitiveFileNames?(): boolean;
|
||||
getCurrentDirectory(): string;
|
||||
trace(s: string): void;
|
||||
}
|
||||
|
||||
|
@ -437,8 +438,10 @@ namespace ts {
|
|||
|
||||
public directoryExists: (directoryName: string) => boolean;
|
||||
public realpath: (path: string) => string;
|
||||
public useCaseSensitiveFileNames: boolean;
|
||||
|
||||
constructor(private shimHost: CoreServicesShimHost) {
|
||||
this.useCaseSensitiveFileNames = this.shimHost.useCaseSensitiveFileNames ? this.shimHost.useCaseSensitiveFileNames() : false;
|
||||
if ("directoryExists" in this.shimHost) {
|
||||
this.directoryExists = directoryName => this.shimHost.directoryExists(directoryName);
|
||||
}
|
||||
|
@ -447,17 +450,34 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
public readDirectory(rootDir: string, extension: string, exclude: string[], depth?: number): string[] {
|
||||
public readDirectory(rootDir: string, extensions: string[], exclude: string[], include: string[], depth?: number): string[] {
|
||||
// Wrap the API changes for 2.0 release. This try/catch
|
||||
// should be removed once TypeScript 2.0 has shipped.
|
||||
let encoded: string;
|
||||
try {
|
||||
encoded = this.shimHost.readDirectory(rootDir, extension, JSON.stringify(exclude), depth);
|
||||
const pattern = getFileMatcherPatterns(rootDir, extensions, exclude, include,
|
||||
this.shimHost.useCaseSensitiveFileNames(), this.shimHost.getCurrentDirectory());
|
||||
return JSON.parse(this.shimHost.readDirectory(
|
||||
rootDir,
|
||||
JSON.stringify(extensions),
|
||||
JSON.stringify(pattern.basePaths),
|
||||
pattern.excludePattern,
|
||||
pattern.includeFilePattern,
|
||||
pattern.includeDirectoryPattern,
|
||||
depth
|
||||
));
|
||||
}
|
||||
catch (e) {
|
||||
encoded = this.shimHost.readDirectory(rootDir, extension, JSON.stringify(exclude));
|
||||
const results: string[] = [];
|
||||
for (const extension of extensions) {
|
||||
for (const file of this.readDirectoryFallback(rootDir, extension, exclude))
|
||||
{
|
||||
if (!contains(results, file)) {
|
||||
results.push(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
return JSON.parse(encoded);
|
||||
}
|
||||
|
||||
public fileExists(fileName: string): boolean {
|
||||
|
@ -467,6 +487,10 @@ namespace ts {
|
|||
public readFile(fileName: string): string {
|
||||
return this.shimHost.readFile(fileName);
|
||||
}
|
||||
|
||||
private readDirectoryFallback(rootDir: string, extension: string, exclude: string[]) {
|
||||
return JSON.parse(this.shimHost.readDirectory(rootDir, extension, JSON.stringify(exclude)));
|
||||
}
|
||||
}
|
||||
|
||||
function simpleForwardCall(logger: Logger, actionDescription: string, action: () => any, logPerformance: boolean): any {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
tests/cases/conformance/classes/classDeclarations/classExtendingClassLikeType.ts(7,18): error TS2304: Cannot find name 'Base'.
|
||||
tests/cases/conformance/classes/classDeclarations/classExtendingClassLikeType.ts(7,18): error TS2689: Cannot extend an interface 'Base'. Did you mean 'implements'?
|
||||
tests/cases/conformance/classes/classDeclarations/classExtendingClassLikeType.ts(45,18): error TS2508: No base constructor has the specified number of type arguments.
|
||||
tests/cases/conformance/classes/classDeclarations/classExtendingClassLikeType.ts(56,18): error TS2510: Base constructors must all have the same return type.
|
||||
|
||||
|
@ -12,7 +12,7 @@ tests/cases/conformance/classes/classDeclarations/classExtendingClassLikeType.ts
|
|||
// Error, no Base constructor function
|
||||
class D0 extends Base<string, string> {
|
||||
~~~~
|
||||
!!! error TS2304: Cannot find name 'Base'.
|
||||
!!! error TS2689: Cannot extend an interface 'Base'. Did you mean 'implements'?
|
||||
}
|
||||
|
||||
interface BaseConstructor {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendsEveryObjectType.ts(4,17): error TS2304: Cannot find name 'I'.
|
||||
tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendsEveryObjectType.ts(4,17): error TS2689: Cannot extend an interface 'I'. Did you mean 'implements'?
|
||||
tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendsEveryObjectType.ts(6,18): error TS2507: Type '{ foo: any; }' is not a constructor function type.
|
||||
tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendsEveryObjectType.ts(6,25): error TS2304: Cannot find name 'string'.
|
||||
tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendsEveryObjectType.ts(6,31): error TS1005: ',' expected.
|
||||
|
@ -14,7 +14,7 @@ tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/cla
|
|||
}
|
||||
class C extends I { } // error
|
||||
~
|
||||
!!! error TS2304: Cannot find name 'I'.
|
||||
!!! error TS2689: Cannot extend an interface 'I'. Did you mean 'implements'?
|
||||
|
||||
class C2 extends { foo: string; } { } // error
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
tests/cases/compiler/classExtendsInterface.ts(2,17): error TS2304: Cannot find name 'Comparable'.
|
||||
tests/cases/compiler/classExtendsInterface.ts(6,21): error TS2304: Cannot find name 'Comparable2'.
|
||||
tests/cases/compiler/classExtendsInterface.ts(2,17): error TS2689: Cannot extend an interface 'Comparable'. Did you mean 'implements'?
|
||||
tests/cases/compiler/classExtendsInterface.ts(6,21): error TS2689: Cannot extend an interface 'Comparable2'. Did you mean 'implements'?
|
||||
|
||||
|
||||
==== tests/cases/compiler/classExtendsInterface.ts (2 errors) ====
|
||||
interface Comparable {}
|
||||
class A extends Comparable {}
|
||||
~~~~~~~~~~
|
||||
!!! error TS2304: Cannot find name 'Comparable'.
|
||||
!!! error TS2689: Cannot extend an interface 'Comparable'. Did you mean 'implements'?
|
||||
class B implements Comparable {}
|
||||
|
||||
|
||||
interface Comparable2<T> {}
|
||||
class A2<T> extends Comparable2<T> {}
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2304: Cannot find name 'Comparable2'.
|
||||
!!! error TS2689: Cannot extend an interface 'Comparable2'. Did you mean 'implements'?
|
||||
class B2<T> implements Comparable2<T> {}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
interface Comparable {}
|
||||
class A extends Comparable {}
|
||||
class B implements Comparable {}
|
||||
|
||||
|
||||
interface Comparable2<T> {}
|
||||
class A2<T> extends Comparable2<T> {}
|
||||
class B2<T> implements Comparable2<T> {}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
tests/cases/compiler/classExtendsInterfaceInExpression.ts(7,25): error TS2304: Cannot find name 'A'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/classExtendsInterfaceInExpression.ts (1 errors) ====
|
||||
interface A {}
|
||||
|
||||
function factory(a: any): {new(): Object} {
|
||||
return null;
|
||||
}
|
||||
|
||||
class C extends factory(A) {}
|
||||
~
|
||||
!!! error TS2304: Cannot find name 'A'.
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
//// [classExtendsInterfaceInExpression.ts]
|
||||
interface A {}
|
||||
|
||||
function factory(a: any): {new(): Object} {
|
||||
return null;
|
||||
}
|
||||
|
||||
class C extends factory(A) {}
|
||||
|
||||
|
||||
//// [classExtendsInterfaceInExpression.js]
|
||||
var __extends = (this && this.__extends) || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
function factory(a) {
|
||||
return null;
|
||||
}
|
||||
var C = (function (_super) {
|
||||
__extends(C, _super);
|
||||
function C() {
|
||||
_super.apply(this, arguments);
|
||||
}
|
||||
return C;
|
||||
}(factory(A)));
|
|
@ -0,0 +1,27 @@
|
|||
tests/cases/compiler/classExtendsInterfaceInModule.ts(5,18): error TS2689: Cannot extend an interface 'M.I1'. Did you mean 'implements'?
|
||||
tests/cases/compiler/classExtendsInterfaceInModule.ts(6,21): error TS2689: Cannot extend an interface 'M.I2'. Did you mean 'implements'?
|
||||
tests/cases/compiler/classExtendsInterfaceInModule.ts(14,17): error TS2689: Cannot extend an interface 'Mod.Nested.I'. Did you mean 'implements'?
|
||||
|
||||
|
||||
==== tests/cases/compiler/classExtendsInterfaceInModule.ts (3 errors) ====
|
||||
module M {
|
||||
export interface I1 {}
|
||||
export interface I2<T> {}
|
||||
}
|
||||
class C1 extends M.I1 {}
|
||||
~
|
||||
!!! error TS2689: Cannot extend an interface 'M.I1'. Did you mean 'implements'?
|
||||
class C2<T> extends M.I2<T> {}
|
||||
~
|
||||
!!! error TS2689: Cannot extend an interface 'M.I2'. Did you mean 'implements'?
|
||||
|
||||
module Mod {
|
||||
export namespace Nested {
|
||||
export interface I {}
|
||||
}
|
||||
}
|
||||
|
||||
class D extends Mod.Nested.I {}
|
||||
~~~
|
||||
!!! error TS2689: Cannot extend an interface 'Mod.Nested.I'. Did you mean 'implements'?
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
//// [classExtendsInterfaceInModule.ts]
|
||||
module M {
|
||||
export interface I1 {}
|
||||
export interface I2<T> {}
|
||||
}
|
||||
class C1 extends M.I1 {}
|
||||
class C2<T> extends M.I2<T> {}
|
||||
|
||||
module Mod {
|
||||
export namespace Nested {
|
||||
export interface I {}
|
||||
}
|
||||
}
|
||||
|
||||
class D extends Mod.Nested.I {}
|
||||
|
||||
|
||||
//// [classExtendsInterfaceInModule.js]
|
||||
var __extends = (this && this.__extends) || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
var C1 = (function (_super) {
|
||||
__extends(C1, _super);
|
||||
function C1() {
|
||||
_super.apply(this, arguments);
|
||||
}
|
||||
return C1;
|
||||
}(M.I1));
|
||||
var C2 = (function (_super) {
|
||||
__extends(C2, _super);
|
||||
function C2() {
|
||||
_super.apply(this, arguments);
|
||||
}
|
||||
return C2;
|
||||
}(M.I2));
|
||||
var D = (function (_super) {
|
||||
__extends(D, _super);
|
||||
function D() {
|
||||
_super.apply(this, arguments);
|
||||
}
|
||||
return D;
|
||||
}(Mod.Nested.I));
|
|
@ -0,0 +1,11 @@
|
|||
tests/cases/compiler/file1.ts(2,1): error TS2448: Block-scoped variable 'c' used before its declaration.
|
||||
|
||||
|
||||
==== tests/cases/compiler/file1.ts (1 errors) ====
|
||||
|
||||
c;
|
||||
~
|
||||
!!! error TS2448: Block-scoped variable 'c' used before its declaration.
|
||||
|
||||
==== tests/cases/compiler/file2.ts (0 errors) ====
|
||||
const c = 0;
|
|
@ -1,8 +1,11 @@
|
|||
tests/cases/compiler/defaultValueInFunctionTypes.ts(1,9): error TS2371: A parameter initializer is only allowed in a function or constructor implementation.
|
||||
tests/cases/compiler/defaultValueInFunctionTypes.ts(2,11): error TS2371: A parameter initializer is only allowed in a function or constructor implementation.
|
||||
|
||||
|
||||
==== tests/cases/compiler/defaultValueInFunctionTypes.ts (1 errors) ====
|
||||
==== tests/cases/compiler/defaultValueInFunctionTypes.ts (2 errors) ====
|
||||
var x: (a: number = 1) => number;
|
||||
~~~~~~~~~~~~~
|
||||
!!! error TS2371: A parameter initializer is only allowed in a function or constructor implementation.
|
||||
var y = <(a : string = "") => any>(undefined)
|
||||
var y = <(a : string = "") => any>(undefined)
|
||||
~~~~~~~~~~~~~~~
|
||||
!!! error TS2371: A parameter initializer is only allowed in a function or constructor implementation.
|
|
@ -0,0 +1,252 @@
|
|||
//// [discriminatedUnionTypes1.ts]
|
||||
interface Square {
|
||||
kind: "square";
|
||||
size: number;
|
||||
}
|
||||
|
||||
interface Rectangle {
|
||||
kind: "rectangle";
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
interface Circle {
|
||||
kind: "circle";
|
||||
radius: number;
|
||||
}
|
||||
|
||||
type Shape = Square | Rectangle | Circle;
|
||||
|
||||
function area1(s: Shape) {
|
||||
if (s.kind === "square") {
|
||||
return s.size * s.size;
|
||||
}
|
||||
else if (s.kind === "circle") {
|
||||
return Math.PI * s.radius * s.radius;
|
||||
}
|
||||
else if (s.kind === "rectangle") {
|
||||
return s.width * s.height;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function area2(s: Shape) {
|
||||
switch (s.kind) {
|
||||
case "square": return s.size * s.size;
|
||||
case "rectangle": return s.width * s.height;
|
||||
case "circle": return Math.PI * s.radius * s.radius;
|
||||
}
|
||||
}
|
||||
|
||||
function assertNever(x: never): never {
|
||||
throw new Error("Unexpected object: " + x);
|
||||
}
|
||||
|
||||
function area3(s: Shape) {
|
||||
switch (s.kind) {
|
||||
case "square": return s.size * s.size;
|
||||
case "rectangle": return s.width * s.height;
|
||||
case "circle": return Math.PI * s.radius * s.radius;
|
||||
default: return assertNever(s);
|
||||
}
|
||||
}
|
||||
|
||||
function area4(s: Shape) {
|
||||
switch (s.kind) {
|
||||
case "square": return s.size * s.size;
|
||||
case "rectangle": return s.width * s.height;
|
||||
case "circle": return Math.PI * s.radius * s.radius;
|
||||
}
|
||||
return assertNever(s);
|
||||
}
|
||||
|
||||
type Message =
|
||||
{ kind: "A", x: string } |
|
||||
{ kind: "B" | "C", y: number } |
|
||||
{ kind: "D" };
|
||||
|
||||
function f1(m: Message) {
|
||||
if (m.kind === "A") {
|
||||
m; // { kind: "A", x: string }
|
||||
}
|
||||
else if (m.kind === "D") {
|
||||
m; // { kind: "D" }
|
||||
}
|
||||
else {
|
||||
m; // { kind: "B" | "C", y: number }
|
||||
}
|
||||
}
|
||||
|
||||
function f2(m: Message) {
|
||||
if (m.kind === "A") {
|
||||
return;
|
||||
}
|
||||
m; // { kind: "B" | "C", y: number } | { kind: "D" }
|
||||
}
|
||||
|
||||
function f3(m: Message) {
|
||||
if (m.kind === "X") {
|
||||
m; // never
|
||||
}
|
||||
}
|
||||
|
||||
function f4(m: Message, x: "A" | "D") {
|
||||
if (m.kind == x) {
|
||||
m; // { kind: "A", x: string } | { kind: "D" }
|
||||
}
|
||||
}
|
||||
|
||||
function f5(m: Message) {
|
||||
switch (m.kind) {
|
||||
case "A":
|
||||
m; // { kind: "A", x: string }
|
||||
break;
|
||||
case "D":
|
||||
m; // { kind: "D" }
|
||||
break;
|
||||
default:
|
||||
m; // { kind: "B" | "C", y: number }
|
||||
}
|
||||
}
|
||||
|
||||
function f6(m: Message) {
|
||||
switch (m.kind) {
|
||||
case "A":
|
||||
m; // { kind: "A", x: string }
|
||||
case "D":
|
||||
m; // { kind: "A", x: string } | { kind: "D" }
|
||||
break;
|
||||
default:
|
||||
m; // { kind: "B" | "C", y: number }
|
||||
}
|
||||
}
|
||||
|
||||
function f7(m: Message) {
|
||||
switch (m.kind) {
|
||||
case "A":
|
||||
case "B":
|
||||
return;
|
||||
}
|
||||
m; // { kind: "B" | "C", y: number } | { kind: "D" }
|
||||
}
|
||||
|
||||
function f8(m: Message) {
|
||||
switch (m.kind) {
|
||||
case "A":
|
||||
return;
|
||||
case "D":
|
||||
throw new Error();
|
||||
}
|
||||
m; // { kind: "B" | "C", y: number }
|
||||
}
|
||||
|
||||
//// [discriminatedUnionTypes1.js]
|
||||
function area1(s) {
|
||||
if (s.kind === "square") {
|
||||
return s.size * s.size;
|
||||
}
|
||||
else if (s.kind === "circle") {
|
||||
return Math.PI * s.radius * s.radius;
|
||||
}
|
||||
else if (s.kind === "rectangle") {
|
||||
return s.width * s.height;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
function area2(s) {
|
||||
switch (s.kind) {
|
||||
case "square": return s.size * s.size;
|
||||
case "rectangle": return s.width * s.height;
|
||||
case "circle": return Math.PI * s.radius * s.radius;
|
||||
}
|
||||
}
|
||||
function assertNever(x) {
|
||||
throw new Error("Unexpected object: " + x);
|
||||
}
|
||||
function area3(s) {
|
||||
switch (s.kind) {
|
||||
case "square": return s.size * s.size;
|
||||
case "rectangle": return s.width * s.height;
|
||||
case "circle": return Math.PI * s.radius * s.radius;
|
||||
default: return assertNever(s);
|
||||
}
|
||||
}
|
||||
function area4(s) {
|
||||
switch (s.kind) {
|
||||
case "square": return s.size * s.size;
|
||||
case "rectangle": return s.width * s.height;
|
||||
case "circle": return Math.PI * s.radius * s.radius;
|
||||
}
|
||||
return assertNever(s);
|
||||
}
|
||||
function f1(m) {
|
||||
if (m.kind === "A") {
|
||||
m; // { kind: "A", x: string }
|
||||
}
|
||||
else if (m.kind === "D") {
|
||||
m; // { kind: "D" }
|
||||
}
|
||||
else {
|
||||
m; // { kind: "B" | "C", y: number }
|
||||
}
|
||||
}
|
||||
function f2(m) {
|
||||
if (m.kind === "A") {
|
||||
return;
|
||||
}
|
||||
m; // { kind: "B" | "C", y: number } | { kind: "D" }
|
||||
}
|
||||
function f3(m) {
|
||||
if (m.kind === "X") {
|
||||
m; // never
|
||||
}
|
||||
}
|
||||
function f4(m, x) {
|
||||
if (m.kind == x) {
|
||||
m; // { kind: "A", x: string } | { kind: "D" }
|
||||
}
|
||||
}
|
||||
function f5(m) {
|
||||
switch (m.kind) {
|
||||
case "A":
|
||||
m; // { kind: "A", x: string }
|
||||
break;
|
||||
case "D":
|
||||
m; // { kind: "D" }
|
||||
break;
|
||||
default:
|
||||
m; // { kind: "B" | "C", y: number }
|
||||
}
|
||||
}
|
||||
function f6(m) {
|
||||
switch (m.kind) {
|
||||
case "A":
|
||||
m; // { kind: "A", x: string }
|
||||
case "D":
|
||||
m; // { kind: "A", x: string } | { kind: "D" }
|
||||
break;
|
||||
default:
|
||||
m; // { kind: "B" | "C", y: number }
|
||||
}
|
||||
}
|
||||
function f7(m) {
|
||||
switch (m.kind) {
|
||||
case "A":
|
||||
case "B":
|
||||
return;
|
||||
}
|
||||
m; // { kind: "B" | "C", y: number } | { kind: "D" }
|
||||
}
|
||||
function f8(m) {
|
||||
switch (m.kind) {
|
||||
case "A":
|
||||
return;
|
||||
case "D":
|
||||
throw new Error();
|
||||
}
|
||||
m; // { kind: "B" | "C", y: number }
|
||||
}
|
|
@ -0,0 +1,402 @@
|
|||
=== tests/cases/conformance/types/union/discriminatedUnionTypes1.ts ===
|
||||
interface Square {
|
||||
>Square : Symbol(Square, Decl(discriminatedUnionTypes1.ts, 0, 0))
|
||||
|
||||
kind: "square";
|
||||
>kind : Symbol(Square.kind, Decl(discriminatedUnionTypes1.ts, 0, 18))
|
||||
|
||||
size: number;
|
||||
>size : Symbol(Square.size, Decl(discriminatedUnionTypes1.ts, 1, 19))
|
||||
}
|
||||
|
||||
interface Rectangle {
|
||||
>Rectangle : Symbol(Rectangle, Decl(discriminatedUnionTypes1.ts, 3, 1))
|
||||
|
||||
kind: "rectangle";
|
||||
>kind : Symbol(Rectangle.kind, Decl(discriminatedUnionTypes1.ts, 5, 21))
|
||||
|
||||
width: number;
|
||||
>width : Symbol(Rectangle.width, Decl(discriminatedUnionTypes1.ts, 6, 22))
|
||||
|
||||
height: number;
|
||||
>height : Symbol(Rectangle.height, Decl(discriminatedUnionTypes1.ts, 7, 18))
|
||||
}
|
||||
|
||||
interface Circle {
|
||||
>Circle : Symbol(Circle, Decl(discriminatedUnionTypes1.ts, 9, 1))
|
||||
|
||||
kind: "circle";
|
||||
>kind : Symbol(Circle.kind, Decl(discriminatedUnionTypes1.ts, 11, 18))
|
||||
|
||||
radius: number;
|
||||
>radius : Symbol(Circle.radius, Decl(discriminatedUnionTypes1.ts, 12, 19))
|
||||
}
|
||||
|
||||
type Shape = Square | Rectangle | Circle;
|
||||
>Shape : Symbol(Shape, Decl(discriminatedUnionTypes1.ts, 14, 1))
|
||||
>Square : Symbol(Square, Decl(discriminatedUnionTypes1.ts, 0, 0))
|
||||
>Rectangle : Symbol(Rectangle, Decl(discriminatedUnionTypes1.ts, 3, 1))
|
||||
>Circle : Symbol(Circle, Decl(discriminatedUnionTypes1.ts, 9, 1))
|
||||
|
||||
function area1(s: Shape) {
|
||||
>area1 : Symbol(area1, Decl(discriminatedUnionTypes1.ts, 16, 41))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 18, 15))
|
||||
>Shape : Symbol(Shape, Decl(discriminatedUnionTypes1.ts, 14, 1))
|
||||
|
||||
if (s.kind === "square") {
|
||||
>s.kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 0, 18), Decl(discriminatedUnionTypes1.ts, 5, 21), Decl(discriminatedUnionTypes1.ts, 11, 18))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 18, 15))
|
||||
>kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 0, 18), Decl(discriminatedUnionTypes1.ts, 5, 21), Decl(discriminatedUnionTypes1.ts, 11, 18))
|
||||
|
||||
return s.size * s.size;
|
||||
>s.size : Symbol(Square.size, Decl(discriminatedUnionTypes1.ts, 1, 19))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 18, 15))
|
||||
>size : Symbol(Square.size, Decl(discriminatedUnionTypes1.ts, 1, 19))
|
||||
>s.size : Symbol(Square.size, Decl(discriminatedUnionTypes1.ts, 1, 19))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 18, 15))
|
||||
>size : Symbol(Square.size, Decl(discriminatedUnionTypes1.ts, 1, 19))
|
||||
}
|
||||
else if (s.kind === "circle") {
|
||||
>s.kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 5, 21), Decl(discriminatedUnionTypes1.ts, 11, 18))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 18, 15))
|
||||
>kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 5, 21), Decl(discriminatedUnionTypes1.ts, 11, 18))
|
||||
|
||||
return Math.PI * s.radius * s.radius;
|
||||
>Math.PI : Symbol(Math.PI, Decl(lib.d.ts, --, --))
|
||||
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>PI : Symbol(Math.PI, Decl(lib.d.ts, --, --))
|
||||
>s.radius : Symbol(Circle.radius, Decl(discriminatedUnionTypes1.ts, 12, 19))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 18, 15))
|
||||
>radius : Symbol(Circle.radius, Decl(discriminatedUnionTypes1.ts, 12, 19))
|
||||
>s.radius : Symbol(Circle.radius, Decl(discriminatedUnionTypes1.ts, 12, 19))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 18, 15))
|
||||
>radius : Symbol(Circle.radius, Decl(discriminatedUnionTypes1.ts, 12, 19))
|
||||
}
|
||||
else if (s.kind === "rectangle") {
|
||||
>s.kind : Symbol(Rectangle.kind, Decl(discriminatedUnionTypes1.ts, 5, 21))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 18, 15))
|
||||
>kind : Symbol(Rectangle.kind, Decl(discriminatedUnionTypes1.ts, 5, 21))
|
||||
|
||||
return s.width * s.height;
|
||||
>s.width : Symbol(Rectangle.width, Decl(discriminatedUnionTypes1.ts, 6, 22))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 18, 15))
|
||||
>width : Symbol(Rectangle.width, Decl(discriminatedUnionTypes1.ts, 6, 22))
|
||||
>s.height : Symbol(Rectangle.height, Decl(discriminatedUnionTypes1.ts, 7, 18))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 18, 15))
|
||||
>height : Symbol(Rectangle.height, Decl(discriminatedUnionTypes1.ts, 7, 18))
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function area2(s: Shape) {
|
||||
>area2 : Symbol(area2, Decl(discriminatedUnionTypes1.ts, 31, 1))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 33, 15))
|
||||
>Shape : Symbol(Shape, Decl(discriminatedUnionTypes1.ts, 14, 1))
|
||||
|
||||
switch (s.kind) {
|
||||
>s.kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 0, 18), Decl(discriminatedUnionTypes1.ts, 5, 21), Decl(discriminatedUnionTypes1.ts, 11, 18))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 33, 15))
|
||||
>kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 0, 18), Decl(discriminatedUnionTypes1.ts, 5, 21), Decl(discriminatedUnionTypes1.ts, 11, 18))
|
||||
|
||||
case "square": return s.size * s.size;
|
||||
>s.size : Symbol(Square.size, Decl(discriminatedUnionTypes1.ts, 1, 19))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 33, 15))
|
||||
>size : Symbol(Square.size, Decl(discriminatedUnionTypes1.ts, 1, 19))
|
||||
>s.size : Symbol(Square.size, Decl(discriminatedUnionTypes1.ts, 1, 19))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 33, 15))
|
||||
>size : Symbol(Square.size, Decl(discriminatedUnionTypes1.ts, 1, 19))
|
||||
|
||||
case "rectangle": return s.width * s.height;
|
||||
>s.width : Symbol(Rectangle.width, Decl(discriminatedUnionTypes1.ts, 6, 22))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 33, 15))
|
||||
>width : Symbol(Rectangle.width, Decl(discriminatedUnionTypes1.ts, 6, 22))
|
||||
>s.height : Symbol(Rectangle.height, Decl(discriminatedUnionTypes1.ts, 7, 18))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 33, 15))
|
||||
>height : Symbol(Rectangle.height, Decl(discriminatedUnionTypes1.ts, 7, 18))
|
||||
|
||||
case "circle": return Math.PI * s.radius * s.radius;
|
||||
>Math.PI : Symbol(Math.PI, Decl(lib.d.ts, --, --))
|
||||
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>PI : Symbol(Math.PI, Decl(lib.d.ts, --, --))
|
||||
>s.radius : Symbol(Circle.radius, Decl(discriminatedUnionTypes1.ts, 12, 19))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 33, 15))
|
||||
>radius : Symbol(Circle.radius, Decl(discriminatedUnionTypes1.ts, 12, 19))
|
||||
>s.radius : Symbol(Circle.radius, Decl(discriminatedUnionTypes1.ts, 12, 19))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 33, 15))
|
||||
>radius : Symbol(Circle.radius, Decl(discriminatedUnionTypes1.ts, 12, 19))
|
||||
}
|
||||
}
|
||||
|
||||
function assertNever(x: never): never {
|
||||
>assertNever : Symbol(assertNever, Decl(discriminatedUnionTypes1.ts, 39, 1))
|
||||
>x : Symbol(x, Decl(discriminatedUnionTypes1.ts, 41, 21))
|
||||
|
||||
throw new Error("Unexpected object: " + x);
|
||||
>Error : Symbol(Error, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(discriminatedUnionTypes1.ts, 41, 21))
|
||||
}
|
||||
|
||||
function area3(s: Shape) {
|
||||
>area3 : Symbol(area3, Decl(discriminatedUnionTypes1.ts, 43, 1))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 45, 15))
|
||||
>Shape : Symbol(Shape, Decl(discriminatedUnionTypes1.ts, 14, 1))
|
||||
|
||||
switch (s.kind) {
|
||||
>s.kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 0, 18), Decl(discriminatedUnionTypes1.ts, 5, 21), Decl(discriminatedUnionTypes1.ts, 11, 18))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 45, 15))
|
||||
>kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 0, 18), Decl(discriminatedUnionTypes1.ts, 5, 21), Decl(discriminatedUnionTypes1.ts, 11, 18))
|
||||
|
||||
case "square": return s.size * s.size;
|
||||
>s.size : Symbol(Square.size, Decl(discriminatedUnionTypes1.ts, 1, 19))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 45, 15))
|
||||
>size : Symbol(Square.size, Decl(discriminatedUnionTypes1.ts, 1, 19))
|
||||
>s.size : Symbol(Square.size, Decl(discriminatedUnionTypes1.ts, 1, 19))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 45, 15))
|
||||
>size : Symbol(Square.size, Decl(discriminatedUnionTypes1.ts, 1, 19))
|
||||
|
||||
case "rectangle": return s.width * s.height;
|
||||
>s.width : Symbol(Rectangle.width, Decl(discriminatedUnionTypes1.ts, 6, 22))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 45, 15))
|
||||
>width : Symbol(Rectangle.width, Decl(discriminatedUnionTypes1.ts, 6, 22))
|
||||
>s.height : Symbol(Rectangle.height, Decl(discriminatedUnionTypes1.ts, 7, 18))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 45, 15))
|
||||
>height : Symbol(Rectangle.height, Decl(discriminatedUnionTypes1.ts, 7, 18))
|
||||
|
||||
case "circle": return Math.PI * s.radius * s.radius;
|
||||
>Math.PI : Symbol(Math.PI, Decl(lib.d.ts, --, --))
|
||||
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>PI : Symbol(Math.PI, Decl(lib.d.ts, --, --))
|
||||
>s.radius : Symbol(Circle.radius, Decl(discriminatedUnionTypes1.ts, 12, 19))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 45, 15))
|
||||
>radius : Symbol(Circle.radius, Decl(discriminatedUnionTypes1.ts, 12, 19))
|
||||
>s.radius : Symbol(Circle.radius, Decl(discriminatedUnionTypes1.ts, 12, 19))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 45, 15))
|
||||
>radius : Symbol(Circle.radius, Decl(discriminatedUnionTypes1.ts, 12, 19))
|
||||
|
||||
default: return assertNever(s);
|
||||
>assertNever : Symbol(assertNever, Decl(discriminatedUnionTypes1.ts, 39, 1))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 45, 15))
|
||||
}
|
||||
}
|
||||
|
||||
function area4(s: Shape) {
|
||||
>area4 : Symbol(area4, Decl(discriminatedUnionTypes1.ts, 52, 1))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 54, 15))
|
||||
>Shape : Symbol(Shape, Decl(discriminatedUnionTypes1.ts, 14, 1))
|
||||
|
||||
switch (s.kind) {
|
||||
>s.kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 0, 18), Decl(discriminatedUnionTypes1.ts, 5, 21), Decl(discriminatedUnionTypes1.ts, 11, 18))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 54, 15))
|
||||
>kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 0, 18), Decl(discriminatedUnionTypes1.ts, 5, 21), Decl(discriminatedUnionTypes1.ts, 11, 18))
|
||||
|
||||
case "square": return s.size * s.size;
|
||||
>s.size : Symbol(Square.size, Decl(discriminatedUnionTypes1.ts, 1, 19))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 54, 15))
|
||||
>size : Symbol(Square.size, Decl(discriminatedUnionTypes1.ts, 1, 19))
|
||||
>s.size : Symbol(Square.size, Decl(discriminatedUnionTypes1.ts, 1, 19))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 54, 15))
|
||||
>size : Symbol(Square.size, Decl(discriminatedUnionTypes1.ts, 1, 19))
|
||||
|
||||
case "rectangle": return s.width * s.height;
|
||||
>s.width : Symbol(Rectangle.width, Decl(discriminatedUnionTypes1.ts, 6, 22))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 54, 15))
|
||||
>width : Symbol(Rectangle.width, Decl(discriminatedUnionTypes1.ts, 6, 22))
|
||||
>s.height : Symbol(Rectangle.height, Decl(discriminatedUnionTypes1.ts, 7, 18))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 54, 15))
|
||||
>height : Symbol(Rectangle.height, Decl(discriminatedUnionTypes1.ts, 7, 18))
|
||||
|
||||
case "circle": return Math.PI * s.radius * s.radius;
|
||||
>Math.PI : Symbol(Math.PI, Decl(lib.d.ts, --, --))
|
||||
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>PI : Symbol(Math.PI, Decl(lib.d.ts, --, --))
|
||||
>s.radius : Symbol(Circle.radius, Decl(discriminatedUnionTypes1.ts, 12, 19))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 54, 15))
|
||||
>radius : Symbol(Circle.radius, Decl(discriminatedUnionTypes1.ts, 12, 19))
|
||||
>s.radius : Symbol(Circle.radius, Decl(discriminatedUnionTypes1.ts, 12, 19))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 54, 15))
|
||||
>radius : Symbol(Circle.radius, Decl(discriminatedUnionTypes1.ts, 12, 19))
|
||||
}
|
||||
return assertNever(s);
|
||||
>assertNever : Symbol(assertNever, Decl(discriminatedUnionTypes1.ts, 39, 1))
|
||||
>s : Symbol(s, Decl(discriminatedUnionTypes1.ts, 54, 15))
|
||||
}
|
||||
|
||||
type Message =
|
||||
>Message : Symbol(Message, Decl(discriminatedUnionTypes1.ts, 61, 1))
|
||||
|
||||
{ kind: "A", x: string } |
|
||||
>kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 64, 5))
|
||||
>x : Symbol(x, Decl(discriminatedUnionTypes1.ts, 64, 16))
|
||||
|
||||
{ kind: "B" | "C", y: number } |
|
||||
>kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 65, 5))
|
||||
>y : Symbol(y, Decl(discriminatedUnionTypes1.ts, 65, 22))
|
||||
|
||||
{ kind: "D" };
|
||||
>kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 66, 5))
|
||||
|
||||
function f1(m: Message) {
|
||||
>f1 : Symbol(f1, Decl(discriminatedUnionTypes1.ts, 66, 18))
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 68, 12))
|
||||
>Message : Symbol(Message, Decl(discriminatedUnionTypes1.ts, 61, 1))
|
||||
|
||||
if (m.kind === "A") {
|
||||
>m.kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 64, 5), Decl(discriminatedUnionTypes1.ts, 65, 5), Decl(discriminatedUnionTypes1.ts, 66, 5))
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 68, 12))
|
||||
>kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 64, 5), Decl(discriminatedUnionTypes1.ts, 65, 5), Decl(discriminatedUnionTypes1.ts, 66, 5))
|
||||
|
||||
m; // { kind: "A", x: string }
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 68, 12))
|
||||
}
|
||||
else if (m.kind === "D") {
|
||||
>m.kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 65, 5), Decl(discriminatedUnionTypes1.ts, 66, 5))
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 68, 12))
|
||||
>kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 65, 5), Decl(discriminatedUnionTypes1.ts, 66, 5))
|
||||
|
||||
m; // { kind: "D" }
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 68, 12))
|
||||
}
|
||||
else {
|
||||
m; // { kind: "B" | "C", y: number }
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 68, 12))
|
||||
}
|
||||
}
|
||||
|
||||
function f2(m: Message) {
|
||||
>f2 : Symbol(f2, Decl(discriminatedUnionTypes1.ts, 78, 1))
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 80, 12))
|
||||
>Message : Symbol(Message, Decl(discriminatedUnionTypes1.ts, 61, 1))
|
||||
|
||||
if (m.kind === "A") {
|
||||
>m.kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 64, 5), Decl(discriminatedUnionTypes1.ts, 65, 5), Decl(discriminatedUnionTypes1.ts, 66, 5))
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 80, 12))
|
||||
>kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 64, 5), Decl(discriminatedUnionTypes1.ts, 65, 5), Decl(discriminatedUnionTypes1.ts, 66, 5))
|
||||
|
||||
return;
|
||||
}
|
||||
m; // { kind: "B" | "C", y: number } | { kind: "D" }
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 80, 12))
|
||||
}
|
||||
|
||||
function f3(m: Message) {
|
||||
>f3 : Symbol(f3, Decl(discriminatedUnionTypes1.ts, 85, 1))
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 87, 12))
|
||||
>Message : Symbol(Message, Decl(discriminatedUnionTypes1.ts, 61, 1))
|
||||
|
||||
if (m.kind === "X") {
|
||||
>m.kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 64, 5), Decl(discriminatedUnionTypes1.ts, 65, 5), Decl(discriminatedUnionTypes1.ts, 66, 5))
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 87, 12))
|
||||
>kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 64, 5), Decl(discriminatedUnionTypes1.ts, 65, 5), Decl(discriminatedUnionTypes1.ts, 66, 5))
|
||||
|
||||
m; // never
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 87, 12))
|
||||
}
|
||||
}
|
||||
|
||||
function f4(m: Message, x: "A" | "D") {
|
||||
>f4 : Symbol(f4, Decl(discriminatedUnionTypes1.ts, 91, 1))
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 93, 12))
|
||||
>Message : Symbol(Message, Decl(discriminatedUnionTypes1.ts, 61, 1))
|
||||
>x : Symbol(x, Decl(discriminatedUnionTypes1.ts, 93, 23))
|
||||
|
||||
if (m.kind == x) {
|
||||
>m.kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 64, 5), Decl(discriminatedUnionTypes1.ts, 65, 5), Decl(discriminatedUnionTypes1.ts, 66, 5))
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 93, 12))
|
||||
>kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 64, 5), Decl(discriminatedUnionTypes1.ts, 65, 5), Decl(discriminatedUnionTypes1.ts, 66, 5))
|
||||
>x : Symbol(x, Decl(discriminatedUnionTypes1.ts, 93, 23))
|
||||
|
||||
m; // { kind: "A", x: string } | { kind: "D" }
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 93, 12))
|
||||
}
|
||||
}
|
||||
|
||||
function f5(m: Message) {
|
||||
>f5 : Symbol(f5, Decl(discriminatedUnionTypes1.ts, 97, 1))
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 99, 12))
|
||||
>Message : Symbol(Message, Decl(discriminatedUnionTypes1.ts, 61, 1))
|
||||
|
||||
switch (m.kind) {
|
||||
>m.kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 64, 5), Decl(discriminatedUnionTypes1.ts, 65, 5), Decl(discriminatedUnionTypes1.ts, 66, 5))
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 99, 12))
|
||||
>kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 64, 5), Decl(discriminatedUnionTypes1.ts, 65, 5), Decl(discriminatedUnionTypes1.ts, 66, 5))
|
||||
|
||||
case "A":
|
||||
m; // { kind: "A", x: string }
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 99, 12))
|
||||
|
||||
break;
|
||||
case "D":
|
||||
m; // { kind: "D" }
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 99, 12))
|
||||
|
||||
break;
|
||||
default:
|
||||
m; // { kind: "B" | "C", y: number }
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 99, 12))
|
||||
}
|
||||
}
|
||||
|
||||
function f6(m: Message) {
|
||||
>f6 : Symbol(f6, Decl(discriminatedUnionTypes1.ts, 110, 1))
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 112, 12))
|
||||
>Message : Symbol(Message, Decl(discriminatedUnionTypes1.ts, 61, 1))
|
||||
|
||||
switch (m.kind) {
|
||||
>m.kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 64, 5), Decl(discriminatedUnionTypes1.ts, 65, 5), Decl(discriminatedUnionTypes1.ts, 66, 5))
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 112, 12))
|
||||
>kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 64, 5), Decl(discriminatedUnionTypes1.ts, 65, 5), Decl(discriminatedUnionTypes1.ts, 66, 5))
|
||||
|
||||
case "A":
|
||||
m; // { kind: "A", x: string }
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 112, 12))
|
||||
|
||||
case "D":
|
||||
m; // { kind: "A", x: string } | { kind: "D" }
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 112, 12))
|
||||
|
||||
break;
|
||||
default:
|
||||
m; // { kind: "B" | "C", y: number }
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 112, 12))
|
||||
}
|
||||
}
|
||||
|
||||
function f7(m: Message) {
|
||||
>f7 : Symbol(f7, Decl(discriminatedUnionTypes1.ts, 122, 1))
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 124, 12))
|
||||
>Message : Symbol(Message, Decl(discriminatedUnionTypes1.ts, 61, 1))
|
||||
|
||||
switch (m.kind) {
|
||||
>m.kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 64, 5), Decl(discriminatedUnionTypes1.ts, 65, 5), Decl(discriminatedUnionTypes1.ts, 66, 5))
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 124, 12))
|
||||
>kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 64, 5), Decl(discriminatedUnionTypes1.ts, 65, 5), Decl(discriminatedUnionTypes1.ts, 66, 5))
|
||||
|
||||
case "A":
|
||||
case "B":
|
||||
return;
|
||||
}
|
||||
m; // { kind: "B" | "C", y: number } | { kind: "D" }
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 124, 12))
|
||||
}
|
||||
|
||||
function f8(m: Message) {
|
||||
>f8 : Symbol(f8, Decl(discriminatedUnionTypes1.ts, 131, 1))
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 133, 12))
|
||||
>Message : Symbol(Message, Decl(discriminatedUnionTypes1.ts, 61, 1))
|
||||
|
||||
switch (m.kind) {
|
||||
>m.kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 64, 5), Decl(discriminatedUnionTypes1.ts, 65, 5), Decl(discriminatedUnionTypes1.ts, 66, 5))
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 133, 12))
|
||||
>kind : Symbol(kind, Decl(discriminatedUnionTypes1.ts, 64, 5), Decl(discriminatedUnionTypes1.ts, 65, 5), Decl(discriminatedUnionTypes1.ts, 66, 5))
|
||||
|
||||
case "A":
|
||||
return;
|
||||
case "D":
|
||||
throw new Error();
|
||||
>Error : Symbol(Error, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
}
|
||||
m; // { kind: "B" | "C", y: number }
|
||||
>m : Symbol(m, Decl(discriminatedUnionTypes1.ts, 133, 12))
|
||||
}
|
|
@ -0,0 +1,465 @@
|
|||
=== tests/cases/conformance/types/union/discriminatedUnionTypes1.ts ===
|
||||
interface Square {
|
||||
>Square : Square
|
||||
|
||||
kind: "square";
|
||||
>kind : "square"
|
||||
|
||||
size: number;
|
||||
>size : number
|
||||
}
|
||||
|
||||
interface Rectangle {
|
||||
>Rectangle : Rectangle
|
||||
|
||||
kind: "rectangle";
|
||||
>kind : "rectangle"
|
||||
|
||||
width: number;
|
||||
>width : number
|
||||
|
||||
height: number;
|
||||
>height : number
|
||||
}
|
||||
|
||||
interface Circle {
|
||||
>Circle : Circle
|
||||
|
||||
kind: "circle";
|
||||
>kind : "circle"
|
||||
|
||||
radius: number;
|
||||
>radius : number
|
||||
}
|
||||
|
||||
type Shape = Square | Rectangle | Circle;
|
||||
>Shape : Square | Rectangle | Circle
|
||||
>Square : Square
|
||||
>Rectangle : Rectangle
|
||||
>Circle : Circle
|
||||
|
||||
function area1(s: Shape) {
|
||||
>area1 : (s: Square | Rectangle | Circle) => number
|
||||
>s : Square | Rectangle | Circle
|
||||
>Shape : Square | Rectangle | Circle
|
||||
|
||||
if (s.kind === "square") {
|
||||
>s.kind === "square" : boolean
|
||||
>s.kind : "square" | "rectangle" | "circle"
|
||||
>s : Square | Rectangle | Circle
|
||||
>kind : "square" | "rectangle" | "circle"
|
||||
>"square" : string
|
||||
|
||||
return s.size * s.size;
|
||||
>s.size * s.size : number
|
||||
>s.size : number
|
||||
>s : Square
|
||||
>size : number
|
||||
>s.size : number
|
||||
>s : Square
|
||||
>size : number
|
||||
}
|
||||
else if (s.kind === "circle") {
|
||||
>s.kind === "circle" : boolean
|
||||
>s.kind : "rectangle" | "circle"
|
||||
>s : Rectangle | Circle
|
||||
>kind : "rectangle" | "circle"
|
||||
>"circle" : string
|
||||
|
||||
return Math.PI * s.radius * s.radius;
|
||||
>Math.PI * s.radius * s.radius : number
|
||||
>Math.PI * s.radius : number
|
||||
>Math.PI : number
|
||||
>Math : Math
|
||||
>PI : number
|
||||
>s.radius : number
|
||||
>s : Circle
|
||||
>radius : number
|
||||
>s.radius : number
|
||||
>s : Circle
|
||||
>radius : number
|
||||
}
|
||||
else if (s.kind === "rectangle") {
|
||||
>s.kind === "rectangle" : boolean
|
||||
>s.kind : "rectangle"
|
||||
>s : Rectangle
|
||||
>kind : "rectangle"
|
||||
>"rectangle" : string
|
||||
|
||||
return s.width * s.height;
|
||||
>s.width * s.height : number
|
||||
>s.width : number
|
||||
>s : Rectangle
|
||||
>width : number
|
||||
>s.height : number
|
||||
>s : Rectangle
|
||||
>height : number
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
>0 : number
|
||||
}
|
||||
}
|
||||
|
||||
function area2(s: Shape) {
|
||||
>area2 : (s: Square | Rectangle | Circle) => number
|
||||
>s : Square | Rectangle | Circle
|
||||
>Shape : Square | Rectangle | Circle
|
||||
|
||||
switch (s.kind) {
|
||||
>s.kind : "square" | "rectangle" | "circle"
|
||||
>s : Square | Rectangle | Circle
|
||||
>kind : "square" | "rectangle" | "circle"
|
||||
|
||||
case "square": return s.size * s.size;
|
||||
>"square" : string
|
||||
>s.size * s.size : number
|
||||
>s.size : number
|
||||
>s : Square
|
||||
>size : number
|
||||
>s.size : number
|
||||
>s : Square
|
||||
>size : number
|
||||
|
||||
case "rectangle": return s.width * s.height;
|
||||
>"rectangle" : string
|
||||
>s.width * s.height : number
|
||||
>s.width : number
|
||||
>s : Rectangle
|
||||
>width : number
|
||||
>s.height : number
|
||||
>s : Rectangle
|
||||
>height : number
|
||||
|
||||
case "circle": return Math.PI * s.radius * s.radius;
|
||||
>"circle" : string
|
||||
>Math.PI * s.radius * s.radius : number
|
||||
>Math.PI * s.radius : number
|
||||
>Math.PI : number
|
||||
>Math : Math
|
||||
>PI : number
|
||||
>s.radius : number
|
||||
>s : Circle
|
||||
>radius : number
|
||||
>s.radius : number
|
||||
>s : Circle
|
||||
>radius : number
|
||||
}
|
||||
}
|
||||
|
||||
function assertNever(x: never): never {
|
||||
>assertNever : (x: never) => never
|
||||
>x : never
|
||||
|
||||
throw new Error("Unexpected object: " + x);
|
||||
>new Error("Unexpected object: " + x) : Error
|
||||
>Error : ErrorConstructor
|
||||
>"Unexpected object: " + x : string
|
||||
>"Unexpected object: " : string
|
||||
>x : never
|
||||
}
|
||||
|
||||
function area3(s: Shape) {
|
||||
>area3 : (s: Square | Rectangle | Circle) => number
|
||||
>s : Square | Rectangle | Circle
|
||||
>Shape : Square | Rectangle | Circle
|
||||
|
||||
switch (s.kind) {
|
||||
>s.kind : "square" | "rectangle" | "circle"
|
||||
>s : Square | Rectangle | Circle
|
||||
>kind : "square" | "rectangle" | "circle"
|
||||
|
||||
case "square": return s.size * s.size;
|
||||
>"square" : string
|
||||
>s.size * s.size : number
|
||||
>s.size : number
|
||||
>s : Square
|
||||
>size : number
|
||||
>s.size : number
|
||||
>s : Square
|
||||
>size : number
|
||||
|
||||
case "rectangle": return s.width * s.height;
|
||||
>"rectangle" : string
|
||||
>s.width * s.height : number
|
||||
>s.width : number
|
||||
>s : Rectangle
|
||||
>width : number
|
||||
>s.height : number
|
||||
>s : Rectangle
|
||||
>height : number
|
||||
|
||||
case "circle": return Math.PI * s.radius * s.radius;
|
||||
>"circle" : string
|
||||
>Math.PI * s.radius * s.radius : number
|
||||
>Math.PI * s.radius : number
|
||||
>Math.PI : number
|
||||
>Math : Math
|
||||
>PI : number
|
||||
>s.radius : number
|
||||
>s : Circle
|
||||
>radius : number
|
||||
>s.radius : number
|
||||
>s : Circle
|
||||
>radius : number
|
||||
|
||||
default: return assertNever(s);
|
||||
>assertNever(s) : never
|
||||
>assertNever : (x: never) => never
|
||||
>s : never
|
||||
}
|
||||
}
|
||||
|
||||
function area4(s: Shape) {
|
||||
>area4 : (s: Square | Rectangle | Circle) => number
|
||||
>s : Square | Rectangle | Circle
|
||||
>Shape : Square | Rectangle | Circle
|
||||
|
||||
switch (s.kind) {
|
||||
>s.kind : "square" | "rectangle" | "circle"
|
||||
>s : Square | Rectangle | Circle
|
||||
>kind : "square" | "rectangle" | "circle"
|
||||
|
||||
case "square": return s.size * s.size;
|
||||
>"square" : string
|
||||
>s.size * s.size : number
|
||||
>s.size : number
|
||||
>s : Square
|
||||
>size : number
|
||||
>s.size : number
|
||||
>s : Square
|
||||
>size : number
|
||||
|
||||
case "rectangle": return s.width * s.height;
|
||||
>"rectangle" : string
|
||||
>s.width * s.height : number
|
||||
>s.width : number
|
||||
>s : Rectangle
|
||||
>width : number
|
||||
>s.height : number
|
||||
>s : Rectangle
|
||||
>height : number
|
||||
|
||||
case "circle": return Math.PI * s.radius * s.radius;
|
||||
>"circle" : string
|
||||
>Math.PI * s.radius * s.radius : number
|
||||
>Math.PI * s.radius : number
|
||||
>Math.PI : number
|
||||
>Math : Math
|
||||
>PI : number
|
||||
>s.radius : number
|
||||
>s : Circle
|
||||
>radius : number
|
||||
>s.radius : number
|
||||
>s : Circle
|
||||
>radius : number
|
||||
}
|
||||
return assertNever(s);
|
||||
>assertNever(s) : never
|
||||
>assertNever : (x: never) => never
|
||||
>s : never
|
||||
}
|
||||
|
||||
type Message =
|
||||
>Message : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
|
||||
{ kind: "A", x: string } |
|
||||
>kind : "A"
|
||||
>x : string
|
||||
|
||||
{ kind: "B" | "C", y: number } |
|
||||
>kind : "B" | "C"
|
||||
>y : number
|
||||
|
||||
{ kind: "D" };
|
||||
>kind : "D"
|
||||
|
||||
function f1(m: Message) {
|
||||
>f1 : (m: { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }) => void
|
||||
>m : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
>Message : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
|
||||
if (m.kind === "A") {
|
||||
>m.kind === "A" : boolean
|
||||
>m.kind : "A" | "B" | "C" | "D"
|
||||
>m : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
>kind : "A" | "B" | "C" | "D"
|
||||
>"A" : string
|
||||
|
||||
m; // { kind: "A", x: string }
|
||||
>m : { kind: "A"; x: string; }
|
||||
}
|
||||
else if (m.kind === "D") {
|
||||
>m.kind === "D" : boolean
|
||||
>m.kind : "B" | "C" | "D"
|
||||
>m : { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
>kind : "B" | "C" | "D"
|
||||
>"D" : string
|
||||
|
||||
m; // { kind: "D" }
|
||||
>m : { kind: "D"; }
|
||||
}
|
||||
else {
|
||||
m; // { kind: "B" | "C", y: number }
|
||||
>m : { kind: "B" | "C"; y: number; }
|
||||
}
|
||||
}
|
||||
|
||||
function f2(m: Message) {
|
||||
>f2 : (m: { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }) => void
|
||||
>m : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
>Message : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
|
||||
if (m.kind === "A") {
|
||||
>m.kind === "A" : boolean
|
||||
>m.kind : "A" | "B" | "C" | "D"
|
||||
>m : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
>kind : "A" | "B" | "C" | "D"
|
||||
>"A" : string
|
||||
|
||||
return;
|
||||
}
|
||||
m; // { kind: "B" | "C", y: number } | { kind: "D" }
|
||||
>m : { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
}
|
||||
|
||||
function f3(m: Message) {
|
||||
>f3 : (m: { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }) => void
|
||||
>m : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
>Message : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
|
||||
if (m.kind === "X") {
|
||||
>m.kind === "X" : boolean
|
||||
>m.kind : "A" | "B" | "C" | "D"
|
||||
>m : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
>kind : "A" | "B" | "C" | "D"
|
||||
>"X" : string
|
||||
|
||||
m; // never
|
||||
>m : never
|
||||
}
|
||||
}
|
||||
|
||||
function f4(m: Message, x: "A" | "D") {
|
||||
>f4 : (m: { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }, x: "A" | "D") => void
|
||||
>m : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
>Message : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
>x : "A" | "D"
|
||||
|
||||
if (m.kind == x) {
|
||||
>m.kind == x : boolean
|
||||
>m.kind : "A" | "B" | "C" | "D"
|
||||
>m : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
>kind : "A" | "B" | "C" | "D"
|
||||
>x : "A" | "D"
|
||||
|
||||
m; // { kind: "A", x: string } | { kind: "D" }
|
||||
>m : { kind: "A"; x: string; } | { kind: "D"; }
|
||||
}
|
||||
}
|
||||
|
||||
function f5(m: Message) {
|
||||
>f5 : (m: { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }) => void
|
||||
>m : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
>Message : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
|
||||
switch (m.kind) {
|
||||
>m.kind : "A" | "B" | "C" | "D"
|
||||
>m : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
>kind : "A" | "B" | "C" | "D"
|
||||
|
||||
case "A":
|
||||
>"A" : string
|
||||
|
||||
m; // { kind: "A", x: string }
|
||||
>m : { kind: "A"; x: string; }
|
||||
|
||||
break;
|
||||
case "D":
|
||||
>"D" : string
|
||||
|
||||
m; // { kind: "D" }
|
||||
>m : { kind: "D"; }
|
||||
|
||||
break;
|
||||
default:
|
||||
m; // { kind: "B" | "C", y: number }
|
||||
>m : { kind: "B" | "C"; y: number; }
|
||||
}
|
||||
}
|
||||
|
||||
function f6(m: Message) {
|
||||
>f6 : (m: { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }) => void
|
||||
>m : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
>Message : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
|
||||
switch (m.kind) {
|
||||
>m.kind : "A" | "B" | "C" | "D"
|
||||
>m : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
>kind : "A" | "B" | "C" | "D"
|
||||
|
||||
case "A":
|
||||
>"A" : string
|
||||
|
||||
m; // { kind: "A", x: string }
|
||||
>m : { kind: "A"; x: string; }
|
||||
|
||||
case "D":
|
||||
>"D" : string
|
||||
|
||||
m; // { kind: "A", x: string } | { kind: "D" }
|
||||
>m : { kind: "D"; } | { kind: "A"; x: string; }
|
||||
|
||||
break;
|
||||
default:
|
||||
m; // { kind: "B" | "C", y: number }
|
||||
>m : { kind: "B" | "C"; y: number; }
|
||||
}
|
||||
}
|
||||
|
||||
function f7(m: Message) {
|
||||
>f7 : (m: { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }) => void
|
||||
>m : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
>Message : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
|
||||
switch (m.kind) {
|
||||
>m.kind : "A" | "B" | "C" | "D"
|
||||
>m : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
>kind : "A" | "B" | "C" | "D"
|
||||
|
||||
case "A":
|
||||
>"A" : string
|
||||
|
||||
case "B":
|
||||
>"B" : string
|
||||
|
||||
return;
|
||||
}
|
||||
m; // { kind: "B" | "C", y: number } | { kind: "D" }
|
||||
>m : { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
}
|
||||
|
||||
function f8(m: Message) {
|
||||
>f8 : (m: { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }) => void
|
||||
>m : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
>Message : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
|
||||
switch (m.kind) {
|
||||
>m.kind : "A" | "B" | "C" | "D"
|
||||
>m : { kind: "A"; x: string; } | { kind: "B" | "C"; y: number; } | { kind: "D"; }
|
||||
>kind : "A" | "B" | "C" | "D"
|
||||
|
||||
case "A":
|
||||
>"A" : string
|
||||
|
||||
return;
|
||||
case "D":
|
||||
>"D" : string
|
||||
|
||||
throw new Error();
|
||||
>new Error() : Error
|
||||
>Error : ErrorConstructor
|
||||
}
|
||||
m; // { kind: "B" | "C", y: number }
|
||||
>m : { kind: "B" | "C"; y: number; }
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
tests/cases/conformance/expressions/typeAssertions/duplicatePropertiesInTypeAssertions01.ts(2,11): error TS2300: Duplicate identifier 'a'.
|
||||
tests/cases/conformance/expressions/typeAssertions/duplicatePropertiesInTypeAssertions01.ts(2,22): error TS2300: Duplicate identifier 'a'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/expressions/typeAssertions/duplicatePropertiesInTypeAssertions01.ts (2 errors) ====
|
||||
|
||||
let x = <{a: number; a: number}>{};
|
||||
~
|
||||
!!! error TS2300: Duplicate identifier 'a'.
|
||||
~
|
||||
!!! error TS2300: Duplicate identifier 'a'.
|
|
@ -0,0 +1,12 @@
|
|||
//// [duplicatePropertiesInTypeAssertions01.ts]
|
||||
|
||||
let x = <{a: number; a: number}>{};
|
||||
|
||||
//// [duplicatePropertiesInTypeAssertions01.js]
|
||||
var x = {};
|
||||
|
||||
|
||||
//// [duplicatePropertiesInTypeAssertions01.d.ts]
|
||||
declare let x: {
|
||||
a: number;
|
||||
};
|
|
@ -0,0 +1,11 @@
|
|||
tests/cases/conformance/expressions/typeAssertions/duplicatePropertiesInTypeAssertions02.ts(2,16): error TS2300: Duplicate identifier 'a'.
|
||||
tests/cases/conformance/expressions/typeAssertions/duplicatePropertiesInTypeAssertions02.ts(2,27): error TS2300: Duplicate identifier 'a'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/expressions/typeAssertions/duplicatePropertiesInTypeAssertions02.ts (2 errors) ====
|
||||
|
||||
let x = {} as {a: number; a: number};
|
||||
~
|
||||
!!! error TS2300: Duplicate identifier 'a'.
|
||||
~
|
||||
!!! error TS2300: Duplicate identifier 'a'.
|
|
@ -0,0 +1,12 @@
|
|||
//// [duplicatePropertiesInTypeAssertions02.ts]
|
||||
|
||||
let x = {} as {a: number; a: number};
|
||||
|
||||
//// [duplicatePropertiesInTypeAssertions02.js]
|
||||
var x = {};
|
||||
|
||||
|
||||
//// [duplicatePropertiesInTypeAssertions02.d.ts]
|
||||
declare let x: {
|
||||
a: number;
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
tests/cases/conformance/types/tuple/emptyTuples/emptyTuplesTypeAssertion01.ts(2,10): error TS1122: A tuple type element list cannot be empty.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/tuple/emptyTuples/emptyTuplesTypeAssertion01.ts (1 errors) ====
|
||||
|
||||
let x = <[]>[];
|
||||
~~
|
||||
!!! error TS1122: A tuple type element list cannot be empty.
|
||||
let y = x[0];
|
|
@ -0,0 +1,13 @@
|
|||
//// [emptyTuplesTypeAssertion01.ts]
|
||||
|
||||
let x = <[]>[];
|
||||
let y = x[0];
|
||||
|
||||
//// [emptyTuplesTypeAssertion01.js]
|
||||
var x = [];
|
||||
var y = x[0];
|
||||
|
||||
|
||||
//// [emptyTuplesTypeAssertion01.d.ts]
|
||||
declare let x: [];
|
||||
declare let y: never;
|
|
@ -0,0 +1,9 @@
|
|||
tests/cases/conformance/types/tuple/emptyTuples/emptyTuplesTypeAssertion02.ts(2,15): error TS1122: A tuple type element list cannot be empty.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/tuple/emptyTuples/emptyTuplesTypeAssertion02.ts (1 errors) ====
|
||||
|
||||
let x = [] as [];
|
||||
~~
|
||||
!!! error TS1122: A tuple type element list cannot be empty.
|
||||
let y = x[0];
|
|
@ -0,0 +1,13 @@
|
|||
//// [emptyTuplesTypeAssertion02.ts]
|
||||
|
||||
let x = [] as [];
|
||||
let y = x[0];
|
||||
|
||||
//// [emptyTuplesTypeAssertion02.js]
|
||||
var x = [];
|
||||
var y = x[0];
|
||||
|
||||
|
||||
//// [emptyTuplesTypeAssertion02.d.ts]
|
||||
declare let x: [];
|
||||
declare let y: never;
|
|
@ -13,7 +13,7 @@ tests/cases/conformance/types/specifyingTypes/typeReferences/genericTypeReferenc
|
|||
tests/cases/conformance/types/specifyingTypes/typeReferences/genericTypeReferenceWithoutTypeArgument2.ts(18,23): error TS2314: Generic type 'I<T>' requires 1 type argument(s).
|
||||
tests/cases/conformance/types/specifyingTypes/typeReferences/genericTypeReferenceWithoutTypeArgument2.ts(18,27): error TS2314: Generic type 'I<T>' requires 1 type argument(s).
|
||||
tests/cases/conformance/types/specifyingTypes/typeReferences/genericTypeReferenceWithoutTypeArgument2.ts(18,38): error TS2314: Generic type 'I<T>' requires 1 type argument(s).
|
||||
tests/cases/conformance/types/specifyingTypes/typeReferences/genericTypeReferenceWithoutTypeArgument2.ts(20,17): error TS2304: Cannot find name 'I'.
|
||||
tests/cases/conformance/types/specifyingTypes/typeReferences/genericTypeReferenceWithoutTypeArgument2.ts(20,17): error TS2689: Cannot extend an interface 'I'. Did you mean 'implements'?
|
||||
tests/cases/conformance/types/specifyingTypes/typeReferences/genericTypeReferenceWithoutTypeArgument2.ts(23,21): error TS2314: Generic type 'I<T>' requires 1 type argument(s).
|
||||
tests/cases/conformance/types/specifyingTypes/typeReferences/genericTypeReferenceWithoutTypeArgument2.ts(29,18): error TS2304: Cannot find name 'M'.
|
||||
tests/cases/conformance/types/specifyingTypes/typeReferences/genericTypeReferenceWithoutTypeArgument2.ts(30,24): error TS2314: Generic type 'E<T>' requires 1 type argument(s).
|
||||
|
@ -76,7 +76,7 @@ tests/cases/conformance/types/specifyingTypes/typeReferences/genericTypeReferenc
|
|||
|
||||
class D extends I {
|
||||
~
|
||||
!!! error TS2304: Cannot find name 'I'.
|
||||
!!! error TS2689: Cannot extend an interface 'I'. Did you mean 'implements'?
|
||||
}
|
||||
|
||||
interface U extends I {}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
|
||||
tests/cases/compiler/a.ts(2,1): error TS2448: Block-scoped variable 'a' used before its declaration.
|
||||
|
||||
|
||||
!!! error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
|
||||
==== tests/cases/compiler/a.ts (0 errors) ====
|
||||
==== tests/cases/compiler/a.ts (1 errors) ====
|
||||
let b = 30;
|
||||
a = 10;
|
||||
~
|
||||
!!! error TS2448: Block-scoped variable 'a' used before its declaration.
|
||||
==== tests/cases/compiler/b.js (0 errors) ====
|
||||
let a = 10;
|
||||
b = 30;
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
error TS5055: Cannot write file 'tests/cases/compiler/a.js' because it would overwrite input file.
|
||||
tests/cases/compiler/a.js(1,11): error TS8014: 'property declarations' can only be used in a .ts file.
|
||||
|
||||
|
||||
!!! error TS5055: Cannot write file 'tests/cases/compiler/a.js' because it would overwrite input file.
|
||||
==== tests/cases/compiler/a.js (1 errors) ====
|
||||
class C { v }
|
||||
~
|
||||
!!! error TS8014: 'property declarations' can only be used in a .ts file.
|
|
@ -0,0 +1,11 @@
|
|||
tests/cases/compiler/file1.ts(2,1): error TS2448: Block-scoped variable 'l' used before its declaration.
|
||||
|
||||
|
||||
==== tests/cases/compiler/file1.ts (1 errors) ====
|
||||
|
||||
l;
|
||||
~
|
||||
!!! error TS2448: Block-scoped variable 'l' used before its declaration.
|
||||
|
||||
==== tests/cases/compiler/file2.ts (0 errors) ====
|
||||
const l = 0;
|
|
@ -86,8 +86,8 @@ const a8 = a && z;
|
|||
>z : string | number | undefined
|
||||
|
||||
const s1 = s && a;
|
||||
>s1 : number[] | string
|
||||
>s && a : number[] | string
|
||||
>s1 : number[]
|
||||
>s && a : number[]
|
||||
>s : string
|
||||
>a : number[]
|
||||
|
||||
|
@ -98,32 +98,32 @@ const s2 = s && s;
|
|||
>s : string
|
||||
|
||||
const s3 = s && x;
|
||||
>s3 : number | string
|
||||
>s && x : number | string
|
||||
>s3 : number
|
||||
>s && x : number
|
||||
>s : string
|
||||
>x : number
|
||||
|
||||
const s4 = s && b;
|
||||
>s4 : boolean | string
|
||||
>s && b : boolean | string
|
||||
>s4 : boolean
|
||||
>s && b : boolean
|
||||
>s : string
|
||||
>b : boolean
|
||||
|
||||
const s5 = s && v;
|
||||
>s5 : void | string
|
||||
>s && v : void | string
|
||||
>s5 : void
|
||||
>s && v : void
|
||||
>s : string
|
||||
>v : void
|
||||
|
||||
const s6 = s && u;
|
||||
>s6 : string | undefined
|
||||
>s && u : string | undefined
|
||||
>s6 : undefined
|
||||
>s && u : undefined
|
||||
>s : string
|
||||
>u : undefined
|
||||
|
||||
const s7 = s && n;
|
||||
>s7 : string | null
|
||||
>s && n : string | null
|
||||
>s7 : null
|
||||
>s && n : null
|
||||
>s : string
|
||||
>n : null
|
||||
|
||||
|
@ -134,14 +134,14 @@ const s8 = s && z;
|
|||
>z : string | number | undefined
|
||||
|
||||
const x1 = x && a;
|
||||
>x1 : number[] | number
|
||||
>x && a : number[] | number
|
||||
>x1 : number[]
|
||||
>x && a : number[]
|
||||
>x : number
|
||||
>a : number[]
|
||||
|
||||
const x2 = x && s;
|
||||
>x2 : string | number
|
||||
>x && s : string | number
|
||||
>x2 : string
|
||||
>x && s : string
|
||||
>x : number
|
||||
>s : string
|
||||
|
||||
|
@ -152,26 +152,26 @@ const x3 = x && x;
|
|||
>x : number
|
||||
|
||||
const x4 = x && b;
|
||||
>x4 : boolean | number
|
||||
>x && b : boolean | number
|
||||
>x4 : boolean
|
||||
>x && b : boolean
|
||||
>x : number
|
||||
>b : boolean
|
||||
|
||||
const x5 = x && v;
|
||||
>x5 : void | number
|
||||
>x && v : void | number
|
||||
>x5 : void
|
||||
>x && v : void
|
||||
>x : number
|
||||
>v : void
|
||||
|
||||
const x6 = x && u;
|
||||
>x6 : number | undefined
|
||||
>x && u : number | undefined
|
||||
>x6 : undefined
|
||||
>x && u : undefined
|
||||
>x : number
|
||||
>u : undefined
|
||||
|
||||
const x7 = x && n;
|
||||
>x7 : number | null
|
||||
>x && n : number | null
|
||||
>x7 : null
|
||||
>x && n : null
|
||||
>x : number
|
||||
>n : null
|
||||
|
||||
|
@ -182,20 +182,20 @@ const x8 = x && z;
|
|||
>z : string | number | undefined
|
||||
|
||||
const b1 = b && a;
|
||||
>b1 : number[] | boolean
|
||||
>b && a : number[] | boolean
|
||||
>b1 : number[]
|
||||
>b && a : number[]
|
||||
>b : boolean
|
||||
>a : number[]
|
||||
|
||||
const b2 = b && s;
|
||||
>b2 : string | boolean
|
||||
>b && s : string | boolean
|
||||
>b2 : string
|
||||
>b && s : string
|
||||
>b : boolean
|
||||
>s : string
|
||||
|
||||
const b3 = b && x;
|
||||
>b3 : number | boolean
|
||||
>b && x : number | boolean
|
||||
>b3 : number
|
||||
>b && x : number
|
||||
>b : boolean
|
||||
>x : number
|
||||
|
||||
|
@ -206,26 +206,26 @@ const b4 = b && b;
|
|||
>b : boolean
|
||||
|
||||
const b5 = b && v;
|
||||
>b5 : void | boolean
|
||||
>b && v : void | boolean
|
||||
>b5 : void
|
||||
>b && v : void
|
||||
>b : boolean
|
||||
>v : void
|
||||
|
||||
const b6 = b && u;
|
||||
>b6 : boolean | undefined
|
||||
>b && u : boolean | undefined
|
||||
>b6 : undefined
|
||||
>b && u : undefined
|
||||
>b : boolean
|
||||
>u : undefined
|
||||
|
||||
const b7 = b && n;
|
||||
>b7 : boolean | null
|
||||
>b && n : boolean | null
|
||||
>b7 : null
|
||||
>b && n : null
|
||||
>b : boolean
|
||||
>n : null
|
||||
|
||||
const b8 = b && z;
|
||||
>b8 : string | number | boolean | undefined
|
||||
>b && z : string | number | boolean | undefined
|
||||
>b8 : string | number | undefined
|
||||
>b && z : string | number | undefined
|
||||
>b : boolean
|
||||
>z : string | number | undefined
|
||||
|
||||
|
@ -374,44 +374,44 @@ const n8 = n && z;
|
|||
>z : string | number | undefined
|
||||
|
||||
const z1 = z && a;
|
||||
>z1 : number[] | string | number | undefined
|
||||
>z && a : number[] | string | number | undefined
|
||||
>z1 : number[] | undefined
|
||||
>z && a : number[] | undefined
|
||||
>z : string | number | undefined
|
||||
>a : number[]
|
||||
|
||||
const z2 = z && s;
|
||||
>z2 : string | number | undefined
|
||||
>z && s : string | number | undefined
|
||||
>z2 : string | undefined
|
||||
>z && s : string | undefined
|
||||
>z : string | number | undefined
|
||||
>s : string
|
||||
|
||||
const z3 = z && x;
|
||||
>z3 : number | string | undefined
|
||||
>z && x : number | string | undefined
|
||||
>z3 : number | undefined
|
||||
>z && x : number | undefined
|
||||
>z : string | number | undefined
|
||||
>x : number
|
||||
|
||||
const z4 = z && b;
|
||||
>z4 : boolean | string | number | undefined
|
||||
>z && b : boolean | string | number | undefined
|
||||
>z4 : boolean | undefined
|
||||
>z && b : boolean | undefined
|
||||
>z : string | number | undefined
|
||||
>b : boolean
|
||||
|
||||
const z5 = z && v;
|
||||
>z5 : void | string | number
|
||||
>z && v : void | string | number
|
||||
>z5 : void
|
||||
>z && v : void
|
||||
>z : string | number | undefined
|
||||
>v : void
|
||||
|
||||
const z6 = z && u;
|
||||
>z6 : string | number | undefined
|
||||
>z && u : string | number | undefined
|
||||
>z6 : undefined
|
||||
>z && u : undefined
|
||||
>z : string | number | undefined
|
||||
>u : undefined
|
||||
|
||||
const z7 = z && n;
|
||||
>z7 : string | number | null | undefined
|
||||
>z && n : string | number | null | undefined
|
||||
>z7 : null | undefined
|
||||
>z && n : null | undefined
|
||||
>z : string | number | undefined
|
||||
>n : null
|
||||
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
tests/cases/compiler/missingFunctionImplementation.ts(3,3): error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
tests/cases/compiler/missingFunctionImplementation.ts(8,3): error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
tests/cases/compiler/missingFunctionImplementation.ts(16,3): error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
tests/cases/compiler/missingFunctionImplementation.ts(22,10): error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
tests/cases/compiler/missingFunctionImplementation.ts(28,10): error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
tests/cases/compiler/missingFunctionImplementation.ts(33,10): error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
tests/cases/compiler/missingFunctionImplementation.ts(41,10): error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
tests/cases/compiler/missingFunctionImplementation.ts(48,10): error TS2300: Duplicate identifier 'm'.
|
||||
tests/cases/compiler/missingFunctionImplementation.ts(49,10): error TS2300: Duplicate identifier 'm'.
|
||||
tests/cases/compiler/missingFunctionImplementation.ts(49,10): error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
tests/cases/compiler/missingFunctionImplementation.ts(52,19): error TS2300: Duplicate identifier 'm'.
|
||||
tests/cases/compiler/missingFunctionImplementation.ts(57,10): error TS2300: Duplicate identifier 'm'.
|
||||
tests/cases/compiler/missingFunctionImplementation.ts(60,19): error TS2300: Duplicate identifier 'm'.
|
||||
tests/cases/compiler/missingFunctionImplementation.ts(60,19): error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
tests/cases/compiler/missingFunctionImplementation.ts(65,19): error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
tests/cases/compiler/missingFunctionImplementation.ts(73,19): error TS2393: Duplicate function implementation.
|
||||
tests/cases/compiler/missingFunctionImplementation.ts(74,19): error TS2393: Duplicate function implementation.
|
||||
tests/cases/compiler/missingFunctionImplementation.ts(75,19): error TS2393: Duplicate function implementation.
|
||||
tests/cases/compiler/missingFunctionImplementation.ts(78,19): error TS2393: Duplicate function implementation.
|
||||
|
||||
|
||||
==== tests/cases/compiler/missingFunctionImplementation.ts (19 errors) ====
|
||||
|
||||
export class C1 {
|
||||
m(): void;
|
||||
~
|
||||
!!! error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
}
|
||||
|
||||
// merged with a namespace
|
||||
export class C2 {
|
||||
m(): void;
|
||||
~
|
||||
!!! error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
}
|
||||
export namespace C2 { }
|
||||
|
||||
|
||||
// merged with a namespace, multiple overloads
|
||||
class C3 {
|
||||
m(a, b);
|
||||
m(a);
|
||||
~
|
||||
!!! error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
}
|
||||
namespace C3 { }
|
||||
|
||||
// static methods, multiple overloads
|
||||
class C4 {
|
||||
static m(a): void;
|
||||
~
|
||||
!!! error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
}
|
||||
|
||||
// static methods, multiple overloads
|
||||
class C5 {
|
||||
static m(a): void;
|
||||
static m(): void;
|
||||
~
|
||||
!!! error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
}
|
||||
|
||||
// merged with namespace, static methods
|
||||
class C6 {
|
||||
static m(): void;
|
||||
~
|
||||
!!! error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
}
|
||||
namespace C6 {
|
||||
}
|
||||
|
||||
// merged with namespace, static methods, multiple overloads
|
||||
class C7 {
|
||||
static m(a): void;
|
||||
static m(): void;
|
||||
~
|
||||
!!! error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
}
|
||||
namespace C7 {
|
||||
}
|
||||
|
||||
// merged with namespace, static methods, duplicate declarations
|
||||
class C8 {
|
||||
static m(a): void;
|
||||
~
|
||||
!!! error TS2300: Duplicate identifier 'm'.
|
||||
static m(a, b): void;
|
||||
~
|
||||
!!! error TS2300: Duplicate identifier 'm'.
|
||||
~
|
||||
!!! error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
}
|
||||
namespace C8 {
|
||||
export function m(a?, b?): void { }
|
||||
~
|
||||
!!! error TS2300: Duplicate identifier 'm'.
|
||||
}
|
||||
|
||||
// merged with namespace, static methods, duplicate declarations
|
||||
class C9 {
|
||||
static m(a): void { }
|
||||
~
|
||||
!!! error TS2300: Duplicate identifier 'm'.
|
||||
}
|
||||
namespace C9 {
|
||||
export function m(a): void;
|
||||
~
|
||||
!!! error TS2300: Duplicate identifier 'm'.
|
||||
~
|
||||
!!! error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
}
|
||||
|
||||
// merged namespaces
|
||||
namespace N10 {
|
||||
export function m(a): void;
|
||||
~
|
||||
!!! error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
}
|
||||
namespace N10 {
|
||||
export function m(a): void { }
|
||||
}
|
||||
|
||||
// merged namespaces, duplicate defintions
|
||||
namespace N12 {
|
||||
export function m(a): void;
|
||||
~
|
||||
!!! error TS2393: Duplicate function implementation.
|
||||
export function m(): void;
|
||||
~
|
||||
!!! error TS2393: Duplicate function implementation.
|
||||
export function m(a?): void { }
|
||||
~
|
||||
!!! error TS2393: Duplicate function implementation.
|
||||
}
|
||||
namespace N12 {
|
||||
export function m(a): void { }
|
||||
~
|
||||
!!! error TS2393: Duplicate function implementation.
|
||||
}
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
//// [missingFunctionImplementation.ts]
|
||||
|
||||
export class C1 {
|
||||
m(): void;
|
||||
}
|
||||
|
||||
// merged with a namespace
|
||||
export class C2 {
|
||||
m(): void;
|
||||
}
|
||||
export namespace C2 { }
|
||||
|
||||
|
||||
// merged with a namespace, multiple overloads
|
||||
class C3 {
|
||||
m(a, b);
|
||||
m(a);
|
||||
}
|
||||
namespace C3 { }
|
||||
|
||||
// static methods, multiple overloads
|
||||
class C4 {
|
||||
static m(a): void;
|
||||
}
|
||||
|
||||
// static methods, multiple overloads
|
||||
class C5 {
|
||||
static m(a): void;
|
||||
static m(): void;
|
||||
}
|
||||
|
||||
// merged with namespace, static methods
|
||||
class C6 {
|
||||
static m(): void;
|
||||
}
|
||||
namespace C6 {
|
||||
}
|
||||
|
||||
// merged with namespace, static methods, multiple overloads
|
||||
class C7 {
|
||||
static m(a): void;
|
||||
static m(): void;
|
||||
}
|
||||
namespace C7 {
|
||||
}
|
||||
|
||||
// merged with namespace, static methods, duplicate declarations
|
||||
class C8 {
|
||||
static m(a): void;
|
||||
static m(a, b): void;
|
||||
}
|
||||
namespace C8 {
|
||||
export function m(a?, b?): void { }
|
||||
}
|
||||
|
||||
// merged with namespace, static methods, duplicate declarations
|
||||
class C9 {
|
||||
static m(a): void { }
|
||||
}
|
||||
namespace C9 {
|
||||
export function m(a): void;
|
||||
}
|
||||
|
||||
// merged namespaces
|
||||
namespace N10 {
|
||||
export function m(a): void;
|
||||
}
|
||||
namespace N10 {
|
||||
export function m(a): void { }
|
||||
}
|
||||
|
||||
// merged namespaces, duplicate defintions
|
||||
namespace N12 {
|
||||
export function m(a): void;
|
||||
export function m(): void;
|
||||
export function m(a?): void { }
|
||||
}
|
||||
namespace N12 {
|
||||
export function m(a): void { }
|
||||
}
|
||||
|
||||
|
||||
//// [missingFunctionImplementation.js]
|
||||
"use strict";
|
||||
var C1 = (function () {
|
||||
function C1() {
|
||||
}
|
||||
return C1;
|
||||
}());
|
||||
exports.C1 = C1;
|
||||
// merged with a namespace
|
||||
var C2 = (function () {
|
||||
function C2() {
|
||||
}
|
||||
return C2;
|
||||
}());
|
||||
exports.C2 = C2;
|
||||
// merged with a namespace, multiple overloads
|
||||
var C3 = (function () {
|
||||
function C3() {
|
||||
}
|
||||
return C3;
|
||||
}());
|
||||
// static methods, multiple overloads
|
||||
var C4 = (function () {
|
||||
function C4() {
|
||||
}
|
||||
return C4;
|
||||
}());
|
||||
// static methods, multiple overloads
|
||||
var C5 = (function () {
|
||||
function C5() {
|
||||
}
|
||||
return C5;
|
||||
}());
|
||||
// merged with namespace, static methods
|
||||
var C6 = (function () {
|
||||
function C6() {
|
||||
}
|
||||
return C6;
|
||||
}());
|
||||
// merged with namespace, static methods, multiple overloads
|
||||
var C7 = (function () {
|
||||
function C7() {
|
||||
}
|
||||
return C7;
|
||||
}());
|
||||
// merged with namespace, static methods, duplicate declarations
|
||||
var C8 = (function () {
|
||||
function C8() {
|
||||
}
|
||||
return C8;
|
||||
}());
|
||||
var C8;
|
||||
(function (C8) {
|
||||
function m(a, b) { }
|
||||
C8.m = m;
|
||||
})(C8 || (C8 = {}));
|
||||
// merged with namespace, static methods, duplicate declarations
|
||||
var C9 = (function () {
|
||||
function C9() {
|
||||
}
|
||||
C9.m = function (a) { };
|
||||
return C9;
|
||||
}());
|
||||
var C9;
|
||||
(function (C9) {
|
||||
})(C9 || (C9 = {}));
|
||||
// merged namespaces
|
||||
var N10;
|
||||
(function (N10) {
|
||||
})(N10 || (N10 = {}));
|
||||
var N10;
|
||||
(function (N10) {
|
||||
function m(a) { }
|
||||
N10.m = m;
|
||||
})(N10 || (N10 = {}));
|
||||
// merged namespaces, duplicate defintions
|
||||
var N12;
|
||||
(function (N12) {
|
||||
function m(a) { }
|
||||
N12.m = m;
|
||||
})(N12 || (N12 = {}));
|
||||
var N12;
|
||||
(function (N12) {
|
||||
function m(a) { }
|
||||
N12.m = m;
|
||||
})(N12 || (N12 = {}));
|
|
@ -0,0 +1,16 @@
|
|||
tests/cases/compiler/missingFunctionImplementation2_a.ts(3,19): error TS2384: Overload signatures must all be ambient or non-ambient.
|
||||
tests/cases/compiler/missingFunctionImplementation2_b.ts(1,17): error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
|
||||
|
||||
==== tests/cases/compiler/missingFunctionImplementation2_a.ts (1 errors) ====
|
||||
export {};
|
||||
declare module "./missingFunctionImplementation2_b.ts" {
|
||||
export function f(a, b): void;
|
||||
~
|
||||
!!! error TS2384: Overload signatures must all be ambient or non-ambient.
|
||||
}
|
||||
|
||||
==== tests/cases/compiler/missingFunctionImplementation2_b.ts (1 errors) ====
|
||||
export function f(a?, b?);
|
||||
~
|
||||
!!! error TS2391: Function implementation is missing or not immediately following the declaration.
|
|
@ -0,0 +1,15 @@
|
|||
//// [tests/cases/compiler/missingFunctionImplementation2.ts] ////
|
||||
|
||||
//// [missingFunctionImplementation2_a.ts]
|
||||
export {};
|
||||
declare module "./missingFunctionImplementation2_b.ts" {
|
||||
export function f(a, b): void;
|
||||
}
|
||||
|
||||
//// [missingFunctionImplementation2_b.ts]
|
||||
export function f(a?, b?);
|
||||
|
||||
//// [missingFunctionImplementation2_a.js]
|
||||
"use strict";
|
||||
//// [missingFunctionImplementation2_b.js]
|
||||
"use strict";
|
|
@ -0,0 +1,26 @@
|
|||
//// [strictNullLogicalAndOr.ts]
|
||||
|
||||
// Repro from #9113
|
||||
|
||||
let sinOrCos = Math.random() < .5;
|
||||
let choice = sinOrCos && Math.sin || Math.cos;
|
||||
|
||||
choice(Math.PI);
|
||||
|
||||
function sq(n?: number): number {
|
||||
const r = n !== undefined && n*n || 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
sq(3);
|
||||
|
||||
//// [strictNullLogicalAndOr.js]
|
||||
// Repro from #9113
|
||||
var sinOrCos = Math.random() < .5;
|
||||
var choice = sinOrCos && Math.sin || Math.cos;
|
||||
choice(Math.PI);
|
||||
function sq(n) {
|
||||
var r = n !== undefined && n * n || 0;
|
||||
return r;
|
||||
}
|
||||
sq(3);
|
|
@ -0,0 +1,44 @@
|
|||
=== tests/cases/compiler/strictNullLogicalAndOr.ts ===
|
||||
|
||||
// Repro from #9113
|
||||
|
||||
let sinOrCos = Math.random() < .5;
|
||||
>sinOrCos : Symbol(sinOrCos, Decl(strictNullLogicalAndOr.ts, 3, 3))
|
||||
>Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --))
|
||||
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>random : Symbol(Math.random, Decl(lib.d.ts, --, --))
|
||||
|
||||
let choice = sinOrCos && Math.sin || Math.cos;
|
||||
>choice : Symbol(choice, Decl(strictNullLogicalAndOr.ts, 4, 3))
|
||||
>sinOrCos : Symbol(sinOrCos, Decl(strictNullLogicalAndOr.ts, 3, 3))
|
||||
>Math.sin : Symbol(Math.sin, Decl(lib.d.ts, --, --))
|
||||
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>sin : Symbol(Math.sin, Decl(lib.d.ts, --, --))
|
||||
>Math.cos : Symbol(Math.cos, Decl(lib.d.ts, --, --))
|
||||
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>cos : Symbol(Math.cos, Decl(lib.d.ts, --, --))
|
||||
|
||||
choice(Math.PI);
|
||||
>choice : Symbol(choice, Decl(strictNullLogicalAndOr.ts, 4, 3))
|
||||
>Math.PI : Symbol(Math.PI, Decl(lib.d.ts, --, --))
|
||||
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>PI : Symbol(Math.PI, Decl(lib.d.ts, --, --))
|
||||
|
||||
function sq(n?: number): number {
|
||||
>sq : Symbol(sq, Decl(strictNullLogicalAndOr.ts, 6, 16))
|
||||
>n : Symbol(n, Decl(strictNullLogicalAndOr.ts, 8, 12))
|
||||
|
||||
const r = n !== undefined && n*n || 0;
|
||||
>r : Symbol(r, Decl(strictNullLogicalAndOr.ts, 9, 7))
|
||||
>n : Symbol(n, Decl(strictNullLogicalAndOr.ts, 8, 12))
|
||||
>undefined : Symbol(undefined)
|
||||
>n : Symbol(n, Decl(strictNullLogicalAndOr.ts, 8, 12))
|
||||
>n : Symbol(n, Decl(strictNullLogicalAndOr.ts, 8, 12))
|
||||
|
||||
return r;
|
||||
>r : Symbol(r, Decl(strictNullLogicalAndOr.ts, 9, 7))
|
||||
}
|
||||
|
||||
sq(3);
|
||||
>sq : Symbol(sq, Decl(strictNullLogicalAndOr.ts, 6, 16))
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
=== tests/cases/compiler/strictNullLogicalAndOr.ts ===
|
||||
|
||||
// Repro from #9113
|
||||
|
||||
let sinOrCos = Math.random() < .5;
|
||||
>sinOrCos : boolean
|
||||
>Math.random() < .5 : boolean
|
||||
>Math.random() : number
|
||||
>Math.random : () => number
|
||||
>Math : Math
|
||||
>random : () => number
|
||||
>.5 : number
|
||||
|
||||
let choice = sinOrCos && Math.sin || Math.cos;
|
||||
>choice : (x: number) => number
|
||||
>sinOrCos && Math.sin || Math.cos : (x: number) => number
|
||||
>sinOrCos && Math.sin : (x: number) => number
|
||||
>sinOrCos : boolean
|
||||
>Math.sin : (x: number) => number
|
||||
>Math : Math
|
||||
>sin : (x: number) => number
|
||||
>Math.cos : (x: number) => number
|
||||
>Math : Math
|
||||
>cos : (x: number) => number
|
||||
|
||||
choice(Math.PI);
|
||||
>choice(Math.PI) : number
|
||||
>choice : (x: number) => number
|
||||
>Math.PI : number
|
||||
>Math : Math
|
||||
>PI : number
|
||||
|
||||
function sq(n?: number): number {
|
||||
>sq : (n?: number | undefined) => number
|
||||
>n : number | undefined
|
||||
|
||||
const r = n !== undefined && n*n || 0;
|
||||
>r : number
|
||||
>n !== undefined && n*n || 0 : number
|
||||
>n !== undefined && n*n : number
|
||||
>n !== undefined : boolean
|
||||
>n : number | undefined
|
||||
>undefined : undefined
|
||||
>n*n : number
|
||||
>n : number
|
||||
>n : number
|
||||
>0 : number
|
||||
|
||||
return r;
|
||||
>r : number
|
||||
}
|
||||
|
||||
sq(3);
|
||||
>sq(3) : number
|
||||
>sq : (n?: number | undefined) => number
|
||||
>3 : number
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
export const x = 0;
|
||||
//# sourceMappingURL=file.js.map
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
var x = 0;
|
||||
//# sourceMappingURL=file.js.map
|
|
@ -0,0 +1,7 @@
|
|||
file.ts(1,3): error TS1005: ';' expected.
|
||||
|
||||
|
||||
==== file.ts (1 errors) ====
|
||||
a b
|
||||
~
|
||||
!!! error TS1005: ';' expected.
|
|
@ -0,0 +1,4 @@
|
|||
"use strict";
|
||||
a;
|
||||
b;
|
||||
//# sourceMappingURL=file.js.map
|
|
@ -0,0 +1,5 @@
|
|||
define(["require", "exports"], function (require, exports) {
|
||||
"use strict";
|
||||
var x = 0;
|
||||
});
|
||||
//# sourceMappingURL=file.js.map
|
|
@ -0,0 +1,4 @@
|
|||
"use strict";
|
||||
/// <reference path="file2.ts" />
|
||||
var x = 0;
|
||||
//# sourceMappingURL=file.js.map
|
|
@ -0,0 +1,2 @@
|
|||
"use strict";
|
||||
//# sourceMappingURL=file.js.map
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
var x = 0;
|
||||
//# sourceMappingURL=file.js.map
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
var x = 0;
|
||||
//# sourceMappingURL=file.js.map
|
|
@ -0,0 +1,5 @@
|
|||
define(["require", "exports", "SomeOtherName"], function (require, exports, SomeName_1) {
|
||||
"use strict";
|
||||
use(SomeName_1.foo);
|
||||
});
|
||||
//# sourceMappingURL=file.js.map
|
|
@ -0,0 +1,15 @@
|
|||
System.register(["SomeOtherName"], function(exports_1, context_1) {
|
||||
"use strict";
|
||||
var __moduleName = context_1 && context_1.id;
|
||||
var SomeName_1;
|
||||
return {
|
||||
setters:[
|
||||
function (SomeName_1_1) {
|
||||
SomeName_1 = SomeName_1_1;
|
||||
}],
|
||||
execute: function() {
|
||||
use(SomeName_1.foo);
|
||||
}
|
||||
}
|
||||
});
|
||||
//# sourceMappingURL=file.js.map
|
|
@ -0,0 +1,13 @@
|
|||
(function (factory) {
|
||||
if (typeof module === 'object' && typeof module.exports === 'object') {
|
||||
var v = factory(require, exports); if (v !== undefined) module.exports = v;
|
||||
}
|
||||
else if (typeof define === 'function' && define.amd) {
|
||||
define(["require", "exports", "SomeOtherName"], factory);
|
||||
}
|
||||
})(function (require, exports) {
|
||||
"use strict";
|
||||
var SomeName_1 = require("SomeOtherName");
|
||||
use(SomeName_1.foo);
|
||||
});
|
||||
//# sourceMappingURL=file.js.map
|
|
@ -0,0 +1,6 @@
|
|||
error TS6046: Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015'
|
||||
|
||||
|
||||
!!! error TS6046: Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015'
|
||||
==== file.ts (0 errors) ====
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
"use strict";
|
||||
//# sourceMappingURL=file.js.map
|
|
@ -0,0 +1,6 @@
|
|||
error TS6046: Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015'
|
||||
|
||||
|
||||
!!! error TS6046: Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015'
|
||||
==== file.ts (0 errors) ====
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
"use strict";
|
||||
//# sourceMappingURL=file.js.map
|
|
@ -0,0 +1,6 @@
|
|||
error TS6046: Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015'
|
||||
|
||||
|
||||
!!! error TS6046: Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015'
|
||||
==== file.ts (0 errors) ====
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
"use strict";
|
||||
//# sourceMappingURL=file.js.map
|
|
@ -0,0 +1,6 @@
|
|||
error TS6046: Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015'
|
||||
|
||||
|
||||
!!! error TS6046: Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015'
|
||||
==== file.ts (0 errors) ====
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
"use strict";
|
||||
//# sourceMappingURL=file.js.map
|
|
@ -0,0 +1,12 @@
|
|||
System.register("NamedModule", [], function(exports_1, context_1) {
|
||||
"use strict";
|
||||
var __moduleName = context_1 && context_1.id;
|
||||
var x;
|
||||
return {
|
||||
setters:[],
|
||||
execute: function() {
|
||||
var x = 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
//# sourceMappingURL=file.js.map
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
var a = 10;
|
||||
//# sourceMappingURL=input.js.map
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
var a = 10;
|
||||
//# sourceMappingURL=input.js.map
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
var x;
|
||||
//# sourceMappingURL=b.js.map
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
x;
|
||||
//# sourceMappingURL=input.js.map
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
x;
|
||||
//# sourceMappingURL=input.js.map
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
x;
|
||||
//# sourceMappingURL=input.js.map
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
x;
|
||||
//# sourceMappingURL=input.js.map
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
x;
|
||||
//# sourceMappingURL=input.js.map
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
x;
|
||||
//# sourceMappingURL=input.js.map
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
x;
|
||||
//# sourceMappingURL=input.js.map
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
x;
|
||||
//# sourceMappingURL=input.js.map
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
x;
|
||||
//# sourceMappingURL=input.js.map
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
x;
|
||||
//# sourceMappingURL=input.js.map
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
x;
|
||||
//# sourceMappingURL=input.js.map
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
x;
|
||||
//# sourceMappingURL=input.js.map
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
x;
|
||||
//# sourceMappingURL=input.js.map
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче