diff --git a/Jakefile.js b/Jakefile.js index 55a1852082d6b..d71af3339e915 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -145,6 +145,7 @@ var languageServiceLibrarySources = [ var harnessCoreSources = [ "harness.ts", + "virtualFileSystem.ts", "sourceMapRecorder.ts", "harnessLanguageService.ts", "fourslash.ts", @@ -179,7 +180,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([ diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index d443c7c907a5a..16900f22a6298 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -599,12 +599,6 @@ namespace ts { } } - function isNarrowableReference(expr: Expression): boolean { - return expr.kind === SyntaxKind.Identifier || - expr.kind === SyntaxKind.ThisKeyword || - expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((expr).expression); - } - function isNarrowingExpression(expr: Expression): boolean { switch (expr.kind) { case SyntaxKind.Identifier: @@ -612,7 +606,7 @@ namespace ts { case SyntaxKind.PropertyAccessExpression: return isNarrowableReference(expr); case SyntaxKind.CallExpression: - return true; + return hasNarrowableArgument(expr); case SyntaxKind.ParenthesizedExpression: return isNarrowingExpression((expr).expression); case SyntaxKind.BinaryExpression: @@ -623,6 +617,39 @@ namespace ts { return false; } + function isNarrowableReference(expr: Expression): boolean { + return expr.kind === SyntaxKind.Identifier || + expr.kind === SyntaxKind.ThisKeyword || + expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((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((expr.expression).expression)) { + return true; + } + return false; + } + + function isNarrowingNullCheckOperands(expr1: Expression, expr2: Expression) { + return (expr1.kind === SyntaxKind.NullKeyword || expr1.kind === SyntaxKind.Identifier && (expr1).text === "undefined") && isNarrowableOperand(expr2); + } + + function isNarrowingTypeofOperands(expr1: Expression, expr2: Expression) { + return expr1.kind === SyntaxKind.TypeOfExpression && isNarrowableOperand((expr1).expression) && expr2.kind === SyntaxKind.StringLiteral; + } + + function isNarrowingDiscriminant(expr: Expression) { + return expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((expr).expression); + } + function isNarrowingBinaryExpression(expr: BinaryExpression) { switch (expr.operatorToken.kind) { case SyntaxKind.EqualsToken: @@ -631,34 +658,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; - } - else if (expr.right.kind === SyntaxKind.StringLiteral) { - typeOf = expr.left; - } - else { - typeOf = undefined; + function isNarrowableOperand(expr: Expression): boolean { + switch (expr.kind) { + case SyntaxKind.ParenthesizedExpression: + return isNarrowableOperand((expr).expression); + case SyntaxKind.BinaryExpression: + switch ((expr).operatorToken.kind) { + case SyntaxKind.EqualsToken: + return isNarrowableOperand((expr).left); + case SyntaxKind.CommaToken: + return isNarrowableOperand((expr).right); + } } - return typeOf && typeOf.kind === SyntaxKind.TypeOfExpression && isNarrowingExpression((typeOf).expression); + return isNarrowableReference(expr); + } + + function isNarrowingSwitchStatement(switchStatement: SwitchStatement) { + const expr = switchStatement.expression; + return expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((expr).expression); } function createBranchLabel(): FlowLabel { @@ -704,8 +732,22 @@ namespace ts { setFlowNodeReferenced(antecedent); return { flags, - antecedent, expression, + antecedent + }; + } + + function createFlowSwitchClause(antecedent: FlowNode, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): FlowNode { + if (!isNarrowingSwitchStatement(switchStatement)) { + return antecedent; + } + setFlowNodeReferenced(antecedent); + return { + flags: FlowFlags.SwitchClause, + switchStatement, + clauseStart, + clauseEnd, + antecedent }; } @@ -934,9 +976,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; @@ -945,25 +990,22 @@ namespace ts { function bindCaseBlock(node: CaseBlock): void { const clauses = node.clauses; + let fallthroughFlow = unreachableFlow; for (let i = 0; i < clauses.length; i++) { + const clauseStart = i; + while (!clauses[i].statements.length && i + 1 < clauses.length) { + bind(clauses[i]); + i++; + } + const preCaseLabel = createBranchLabel(); + addAntecedent(preCaseLabel, createFlowSwitchClause(preSwitchCaseFlow, node.parent, clauseStart, i + 1)); + addAntecedent(preCaseLabel, fallthroughFlow); + currentFlow = finishFlowLabel(preCaseLabel); 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); - } - } - else { - bind(clause); + bind(clause); + fallthroughFlow = currentFlow; + if (!(currentFlow.flags & FlowFlags.Unreachable) && i !== clauses.length - 1 && options.noFallthroughCasesInSwitch) { + errorOnFirstToken(clause, Diagnostics.Fallthrough_case_in_switch); } } } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 08287d37fa31e..72d637c221766 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -851,7 +851,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)); } } @@ -935,6 +936,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 = (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 @@ -5187,7 +5213,6 @@ namespace ts { if (hasProperty(stringLiteralTypes, text)) { return stringLiteralTypes[text]; } - const type = stringLiteralTypes[text] = createType(TypeFlags.StringLiteral); type.text = text; return type; @@ -5652,6 +5677,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); } @@ -6832,8 +6861,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((type).types, isStringLiteralUnionType) : + false; } /** @@ -7698,6 +7729,35 @@ namespace ts { return node; } + function getTypeOfSwitchClause(clause: CaseClause | DefaultClause) { + if (clause.kind === SyntaxKind.CaseClause) { + const expr = (clause).expression; + return expr.kind === SyntaxKind.StringLiteral ? getStringLiteralTypeForText((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((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((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)) { @@ -7735,6 +7795,9 @@ namespace ts { else if (flow.flags & FlowFlags.Condition) { type = getTypeAtFlowCondition(flow); } + else if (flow.flags & FlowFlags.SwitchClause) { + type = getTypeAtSwitchClause(flow); + } else if (flow.flags & FlowFlags.Label) { if ((flow).antecedents.length === 1) { flow = (flow).antecedents[0]; @@ -7818,6 +7881,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) { @@ -7897,12 +7965,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, left, operator, right, assumeTrue); + } + if (right.kind === SyntaxKind.TypeOfExpression && left.kind === SyntaxKind.StringLiteral) { + return narrowTypeByTypeof(type, right, operator, left, assumeTrue); + } + if (left.kind === SyntaxKind.PropertyAccessExpression) { + return narrowTypeByDiscriminant(type, left, operator, right, assumeTrue); + } + if (right.kind === SyntaxKind.PropertyAccessExpression) { + return narrowTypeByDiscriminant(type, right, operator, left, assumeTrue); } break; case SyntaxKind.InstanceOfKeyword: @@ -7913,41 +7995,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(((expr.left.kind === SyntaxKind.TypeOfExpression ? expr.left : expr.right)).expression); - const literal = (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)) { @@ -7965,6 +8041,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((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, (switchStatement.expression).expression)) { + return type; + } + const propName = (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)) { @@ -8935,10 +9063,6 @@ namespace ts { return applyToContextualType(type, t => getIndexTypeOfStructuredType(t, kind)); } - function contextualTypeIsStringLiteralType(type: Type): boolean { - return !!(type.flags & TypeFlags.Union ? forEach((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((type).types, isTupleLikeType) : isTupleLikeType(type)); @@ -10044,7 +10168,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; @@ -11773,10 +11897,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((expr).expression); + if (!(type.flags & TypeFlags.Union)) { + return false; + } + const propName = (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((func.body).statements); + if (lastStatement && lastStatement.kind === SyntaxKind.SwitchStatement && isExhaustiveSwitchStatement(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(func.body, returnStatement => { const expr = returnStatement.expression; @@ -11833,7 +11989,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; } @@ -12611,7 +12767,7 @@ namespace ts { function checkStringLiteralExpression(node: StringLiteral): Type { const contextualType = getContextualType(node); - if (contextualType && contextualTypeIsStringLiteralType(contextualType)) { + if (contextualType && isStringLiteralUnionType(contextualType)) { return getStringLiteralTypeForText(node.text); } diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index b2b2a78741bfa..1948dd8261634 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -696,7 +696,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 @@ -712,80 +712,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(json["files"], s => combinePaths(basePath, s)); + fileNames = json["files"]; } else { errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "files", "Array")); } } - else { - const filesSeen: Map = {}; - let exclude: string[] = []; - if (isArray(json["exclude"])) { - exclude = json["exclude"]; + let includeSpecs: string[]; + if (hasProperty(json, "include")) { + if (isArray(json["include"])) { + includeSpecs = 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); + errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "include", "Array")); } - 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; - } - } + } - if (!filesSeen[fileName]) { - filesSeen[fileName] = true; - fileNames.push(fileName); - } - } + let excludeSpecs: string[]; + if (hasProperty(json, "exclude")) { + if (isArray(json["exclude"])) { + excludeSpecs = json["exclude"]; + } + else { + errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "exclude", "Array")); } } - if (hasProperty(json, "excludes") && !hasProperty(json, "exclude")) { + 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); } } @@ -881,4 +867,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 = {}; + + // 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 = {}; + + 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 = 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 .ts and + // .d.ts (or .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 = {}; + 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, wildcardFiles: Map, 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, 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(); + } } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 4d100e33d5d5d..f9a8b19a9854a 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -25,7 +25,7 @@ namespace ts { contains, remove, forEachValue: forEachValueInMap, - clear + clear, }; function forEachValueInMap(f: (key: Path, value: T) => void) { @@ -130,6 +130,14 @@ 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(array: T[], predicate: (x: T, i: number) => boolean): number { let count = 0; if (array) { @@ -159,6 +167,17 @@ namespace ts { return result; } + export function filterMutate(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(array: T[], f: (x: T, i: number) => U): U[] { let result: U[]; if (array) { @@ -694,6 +713,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; } @@ -963,12 +1004,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[]; + } + + export 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` @@ -1017,6 +1321,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(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) { @@ -1036,6 +1393,10 @@ namespace ts { return ext === ".jsx" || ext === ".tsx"; } + export function changeExtension(path: T, newExtension: string): T { + return (removeFileExtension(path) + newExtension); + } + export interface ObjectAllocator { getNodeConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => Node; getSourceFileConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => SourceFile; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 06c829da89096..6055084fa5824 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -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 diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 9f1f5b3cdbf4d..647118e361384 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1084,8 +1084,15 @@ const _super = (function (geti, seti) { return; } - const indentBeforeDot = needsIndentation(node, node.expression, node.dotToken); - const indentAfterDot = needsIndentation(node, node.dotToken, node.name); + let indentBeforeDot = false; + let indentAfterDot = false; + if (!(node.emitFlags & NodeEmitFlags.NoIndentation)) { + const dotRangeStart = node.expression.end; + const dotRangeEnd = skipTrivia(currentText, node.expression.end) + 1; + const dotToken = { kind: SyntaxKind.DotToken, pos: dotRangeStart, end: dotRangeEnd }; + indentBeforeDot = needsIndentation(node, node.expression, dotToken); + indentAfterDot = needsIndentation(node, dotToken, node.name); + } const shouldEmitDotDot = !indentBeforeDot && needsDotDotForPropertyAccess(node.expression); emitExpression(node.expression); diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index f879f3660e405..e516d9d1463b8 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -338,21 +338,20 @@ namespace ts { return node; } - export function createPropertyAccess(expression: Expression, name: string | Identifier, location?: TextRange) { - return createPropertyAccessWithDotToken(expression, createSynthesizedNode(SyntaxKind.DotToken), name, location, /*flags*/ undefined); - } - - export function createPropertyAccessWithDotToken(expression: Expression, dotToken: Node, name: string | Identifier, location?: TextRange, flags?: NodeFlags) { + export function createPropertyAccess(expression: Expression, name: string | Identifier, location?: TextRange, flags?: NodeFlags) { const node = createNode(SyntaxKind.PropertyAccessExpression, location, flags); node.expression = parenthesizeForAccess(expression); - node.dotToken = dotToken; + node.emitFlags = NodeEmitFlags.NoIndentation; node.name = typeof name === "string" ? createIdentifier(name) : name; return node; } export function updatePropertyAccess(node: PropertyAccessExpression, expression: Expression, name: Identifier) { if (node.expression !== expression || node.name !== name) { - return updateNode(createPropertyAccessWithDotToken(expression, node.dotToken, name, /*location*/ node, node.flags), node); + const propertyAccess = createPropertyAccess(expression, name, /*location*/ node, node.flags); + // Because we are updating existed propertyAccess we want to inherit its emitFlags instead of using default from createPropertyAccess + propertyAccess.emitFlags = node.emitFlags; + return updateNode(propertyAccess, node); } return node; } @@ -937,16 +936,13 @@ namespace ts { } export function createMemberAccessForPropertyName(target: Expression, memberName: PropertyName, setNodeEmitFlags: (node: Node, flags: NodeEmitFlags) => void, location?: TextRange): MemberExpression { - if (isIdentifier(memberName)) { - const expression = createPropertyAccess(target, memberName, location); - setNodeEmitFlags(expression, NodeEmitFlags.NoNestedSourceMaps); - return expression; - } - else if (isComputedPropertyName(memberName)) { - return createElementAccess(target, memberName.expression, location); + if (isComputedPropertyName(memberName)) { + return createElementAccess(target, memberName.expression, location); } else { - return createElementAccess(target, memberName, location); + const expression = isIdentifier(memberName) ? createPropertyAccess(target, memberName, location) : createElementAccess(target, memberName, location); + setNodeEmitFlags(expression, expression.emitFlags ? NodeEmitFlags.NoNestedSourceMaps | expression.emitFlags : NodeEmitFlags.NoNestedSourceMaps); + return expression; } } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 4b973d3a89e35..1dfe242ac4d2c 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -138,7 +138,6 @@ namespace ts { return visitNodes(cbNodes, (node).properties); case SyntaxKind.PropertyAccessExpression: return visitNode(cbNode, (node).expression) || - visitNode(cbNode, (node).dotToken) || visitNode(cbNode, (node).name); case SyntaxKind.ElementAccessExpression: return visitNode(cbNode, (node).expression) || @@ -3568,7 +3567,7 @@ namespace ts { // If it wasn't then just try to parse out a '.' and report an error. const node = 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); + parseExpected(SyntaxKind.DotToken, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access); node.name = parseRightSideOfDot(/*allowIdentifierNames*/ true); return finishNode(node); } @@ -3803,7 +3802,6 @@ namespace ts { if (dotToken) { const propertyAccess = createNode(SyntaxKind.PropertyAccessExpression, expression.pos); propertyAccess.expression = expression; - propertyAccess.dotToken = dotToken; propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true); expression = finishNode(propertyAccess); continue; diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 1a3848ca72293..ee84c0e981ad8 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -175,7 +175,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)); } /** diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 4cdffbbb1d4e8..3d3c2ba273b1d 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -26,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; @@ -76,7 +76,7 @@ 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; @@ -88,6 +88,7 @@ namespace ts { 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*/; @@ -155,10 +156,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()) { @@ -172,30 +169,22 @@ 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 { args, newLine: "\r\n", @@ -223,7 +212,7 @@ namespace ts { return WScript.ScriptFullName; }, getCurrentDirectory() { - return new ActiveXObject("WScript.Shell").CurrentDirectory; + return shell.CurrentDirectory; }, getDirectories, getEnvironmentVariable(name: string) { @@ -387,8 +376,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 { @@ -421,39 +445,6 @@ namespace ts { return filter(_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, @@ -604,7 +595,10 @@ namespace ts { getCurrentDirectory: () => ChakraHost.currentDirectory, getDirectories: ChakraHost.getDirectories, getEnvironmentVariable: ChakraHost.getEnvironmentVariable || ((name: string) => ""), - 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 }; diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 2faf1fe141c57..30bc5e64c4b2c 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -1085,9 +1085,6 @@ namespace ts { const propertyName = visitPropertyNameOfClassElement(property); const initializer = visitNode(property.initializer, visitor, isExpression); const memberAccess = createMemberAccessForPropertyName(receiver, propertyName, setNodeEmitFlags, /*location*/ propertyName); - if (!isComputedPropertyName(propertyName)) { - setNodeEmitFlags(memberAccess, NodeEmitFlags.NoNestedSourceMaps); - } return createAssignment(memberAccess, initializer); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3d7b2bd06b024..3c55e773cf68e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1029,7 +1029,6 @@ namespace ts { // @kind(SyntaxKind.PropertyAccessExpression) export interface PropertyAccessExpression extends MemberExpression, Declaration { expression: LeftHandSideExpression; - dotToken: Node; name: Identifier; } @@ -1249,6 +1248,7 @@ namespace ts { export interface SwitchStatement extends Statement { expression: Expression; caseBlock: CaseBlock; + possiblyExhaustive?: boolean; } // @kind(SyntaxKind.CaseBlock) @@ -1621,8 +1621,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 } @@ -1658,6 +1659,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; @@ -1738,7 +1746,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 { @@ -2254,6 +2270,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 { @@ -2722,6 +2739,17 @@ namespace ts { fileNames: string[]; raw?: any; errors: Diagnostic[]; + wildcardDirectories?: Map; + } + + export const enum WatchDirectoryFlags { + None = 0, + Recursive = 1 << 0, + } + + export interface ExpandResult { + fileNames: string[]; + wildcardDirectories: Map; } /* @internal */ @@ -3052,13 +3080,14 @@ namespace ts { ExportName = 1 << 17, // Ensure an export prefix is added for an identifier that points to an exported declaration with a local name (see SymbolFlags.ExportHasLocal). LocalName = 1 << 18, // Ensure an export prefix is not added for an identifier that points to an exported declaration. Indented = 1 << 19, // Adds an explicit extra indentation level for class and function bodies when printing (used to match old emitter). + NoIndentation = 1 << 20, // Do not indent the node. // SourceMap Specialization. // TODO(rbuckton): These should be removed once source maps are aligned with the old // emitter and new baselines are taken. This exists solely to // align with the old emitter. - SourceMapEmitOpenBraceAsToken = 1 << 20, // Emits the open brace of a block function body as a source mapped token. - SourceMapAdjustRestParameterLoop = 1 << 21, // Emits adjusted source map positions for a ForStatement generated when transforming a rest parameter for ES5/3. + SourceMapEmitOpenBraceAsToken = 1 << 21, // Emits the open brace of a block function body as a source mapped token. + SourceMapAdjustRestParameterLoop = 1 << 22, // Emits adjusted source map positions for a ForStatement generated when transforming a rest parameter for ES5/3. } /** Additional context provided to `visitEachChild` */ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index d7f6738085830..573128e6fd255 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2678,7 +2678,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); } diff --git a/src/harness/external/chai.d.ts b/src/harness/external/chai.d.ts index 59cf2834b27a3..5e4e6e7d00010 100644 --- a/src/harness/external/chai.d.ts +++ b/src/harness/external/chai.d.ts @@ -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(actual: T, expected: T, message?: string): void; + function notDeepEqual(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; } } \ No newline at end of file diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 55258162d23b2..a185c406462e9 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -23,6 +23,7 @@ /// /// /// +/// // Block scoped definitions work poorly for global variables, temporarily enable var /* tslint:disable:no-var-keyword */ @@ -497,7 +498,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[]; tryEnableSourceMapsForHost?(): void; getEnvironmentVariable?(name: string): string; } @@ -538,8 +539,8 @@ 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 getEnvironmentVariable: typeof IO.getEnvironmentVariable = name => ts.sys.getEnvironmentVariable(name); + 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)) { @@ -608,8 +609,6 @@ namespace Harness { export const writeFile: typeof IO.writeFile = (path, content) => ts.sys.writeFile(path, content); 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 getEnvironmentVariable: typeof IO.getEnvironmentVariable = name => ts.sys.getEnvironmentVariable(name); export function tryEnableSourceMapsForHost() { @@ -617,6 +616,7 @@ namespace Harness { ts.sys.tryEnableSourceMapsForHost(); } } + 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)) { @@ -813,8 +813,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 = entry; + return { + files: ts.map(directory.getFiles(), f => f.name), + directories: ts.map(directory.getDirectories(), d => d.name) + }; + } + return { files: [], directories: [] }; + }); } } } @@ -1126,7 +1140,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(); @@ -1606,7 +1620,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 diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index bc0ed0b57c768..a1823ac8714af 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -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); @@ -615,7 +621,7 @@ namespace Harness.LanguageService { return ts.sys.getEnvironmentVariable(name); } - readDirectory(path: string, extension?: string): string[] { + readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[]): string[] { throw new Error("Not implemented Yet."); } diff --git a/src/harness/loggedIO.ts b/src/harness/loggedIO.ts index 3535decf12180..a60c7341206c8 100644 --- a/src/harness/loggedIO.ts +++ b/src/harness/loggedIO.ts @@ -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 = (underlying).readDirectory(path, extension, exclude); - const logEntry = { path, extension, exclude, result }; + (path, extension, exclude, include) => { + const result = (underlying).readDirectory(path, extension, exclude, include); + const logEntry = { path, extension, exclude, include, result }; recordLog.directoriesRead.push(logEntry); return result; }, diff --git a/src/harness/projectsRunner.ts b/src/harness/projectsRunner.ts index 5cabbed1ec146..162d7dd8ef494 100644 --- a/src/harness/projectsRunner.ts +++ b/src/harness/projectsRunner.ts @@ -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], diff --git a/src/harness/rwcRunner.ts b/src/harness/rwcRunner.ts index 2ca69b091261f..1266ffa5d3783 100644 --- a/src/harness/rwcRunner.ts +++ b/src/harness/rwcRunner.ts @@ -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); } diff --git a/src/harness/virtualFileSystem.ts b/src/harness/virtualFileSystem.ts new file mode 100644 index 0000000000000..30192b8b8ec4d --- /dev/null +++ b/src/harness/virtualFileSystem.ts @@ -0,0 +1,186 @@ +/// +/// +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 ts.filter(this.getFileSystemEntries(), entry => entry.isDirectory()); + } + + getFiles(): VirtualFile[] { + return ts.filter(this.getFileSystemEntries(), entry => entry.isFile()); + } + + getDirectory(name: string): VirtualDirectory { + const entry = this.getFileSystemEntry(name); + return entry.isDirectory() ? entry : undefined; + } + + getFile(name: string): VirtualFile { + const entry = this.getFileSystemEntry(name); + return entry.isFile() ? 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 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 = 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 = 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 = entry; + return { + files: ts.map(directory.getFiles(), f => f.name), + directories: ts.map(directory.getDirectories(), d => d.name) + }; + } + return { files: [], directories: [] }; + } + } +} \ No newline at end of file diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts index 5865e48575407..0911586dd5d54 100644 --- a/src/lib/dom.generated.d.ts +++ b/src/lib/dom.generated.d.ts @@ -4,7 +4,7 @@ ///////////////////////////// interface Algorithm { - name?: string; + name: string; } interface AriaRequestEventInit extends EventInit { @@ -851,6 +851,7 @@ interface UIEventInit extends EventInit { } interface WebGLContextAttributes { + failIfMajorPerformanceCaveat?: boolean; alpha?: boolean; depth?: boolean; stencil?: boolean; @@ -919,7 +920,7 @@ interface ApplicationCache extends EventTarget { oncached: (ev: Event) => any; onchecking: (ev: Event) => any; ondownloading: (ev: Event) => any; - onerror: (ev: Event) => any; + onerror: (ev: ErrorEvent) => any; onnoupdate: (ev: Event) => any; onobsolete: (ev: Event) => any; onprogress: (ev: ProgressEvent) => any; @@ -2289,7 +2290,7 @@ declare var DeviceRotationRate: { interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEvent { /** - * Sets or gets the URL for the current document. + * Sets or gets the URL for the current document. */ readonly URL: string; /** @@ -2317,7 +2318,7 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven */ applets: HTMLCollectionOf; /** - * Deprecated. Sets or retrieves a value that indicates the background color behind the object. + * Deprecated. Sets or retrieves a value that indicates the background color behind the object. */ bgColor: string; /** @@ -2345,19 +2346,19 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven */ designMode: string; /** - * Sets or retrieves a value that indicates the reading order of the object. + * Sets or retrieves a value that indicates the reading order of the object. */ dir: string; /** - * Gets an object representing the document type declaration associated with the current document. + * Gets an object representing the document type declaration associated with the current document. */ readonly doctype: DocumentType; /** - * Gets a reference to the root node of the document. + * Gets a reference to the root node of the document. */ documentElement: HTMLElement; /** - * Sets or gets the security domain of the document. + * Sets or gets the security domain of the document. */ domain: string; /** @@ -2381,7 +2382,7 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven */ images: HTMLCollectionOf; /** - * Gets the implementation object of the current document. + * Gets the implementation object of the current document. */ readonly implementation: DOMImplementation; /** @@ -2389,11 +2390,11 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven */ readonly inputEncoding: string | null; /** - * Gets the date that the page was last modified, if the page supplies one. + * Gets the date that the page was last modified, if the page supplies one. */ readonly lastModified: string; /** - * Sets or gets the color of the document links. + * Sets or gets the color of the document links. */ linkColor: string; /** @@ -2401,7 +2402,7 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven */ links: HTMLCollectionOf; /** - * Contains information about the current URL. + * Contains information about the current URL. */ readonly location: Location; msCSSOMElementFloatMetrics: boolean; @@ -2410,7 +2411,7 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven * Fires when the user aborts the download. * @param ev The event. */ - onabort: (ev: Event) => any; + onabort: (ev: UIEvent) => any; /** * Fires when the object is set as the active element. * @param ev The event. @@ -2426,19 +2427,19 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven * @param ev The event. */ onbeforedeactivate: (ev: UIEvent) => any; - /** - * Fires when the object loses the input focus. + /** + * Fires when the object loses the input focus. * @param ev The focus event. */ onblur: (ev: FocusEvent) => any; /** - * Occurs when playback is possible, but would require further buffering. + * Occurs when playback is possible, but would require further buffering. * @param ev The event. */ oncanplay: (ev: Event) => any; oncanplaythrough: (ev: Event) => any; /** - * Fires when the contents of the object or selection have changed. + * Fires when the contents of the object or selection have changed. * @param ev The event. */ onchange: (ev: Event) => any; @@ -2448,7 +2449,7 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven */ onclick: (ev: MouseEvent) => any; /** - * Fires when the user clicks the right mouse button in the client area, opening the context menu. + * Fires when the user clicks the right mouse button in the client area, opening the context menu. * @param ev The mouse event. */ oncontextmenu: (ev: PointerEvent) => any; @@ -2472,12 +2473,12 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven * @param ev The event. */ ondragend: (ev: DragEvent) => any; - /** + /** * Fires on the target element when the user drags the object to a valid drop target. * @param ev The drag event. */ ondragenter: (ev: DragEvent) => any; - /** + /** * Fires on the target object when the user moves the mouse out of a valid drop target during a drag operation. * @param ev The drag event. */ @@ -2488,23 +2489,23 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven */ ondragover: (ev: DragEvent) => any; /** - * Fires on the source object when the user starts to drag a text selection or selected object. + * Fires on the source object when the user starts to drag a text selection or selected object. * @param ev The event. */ ondragstart: (ev: DragEvent) => any; ondrop: (ev: DragEvent) => any; /** - * Occurs when the duration attribute is updated. + * Occurs when the duration attribute is updated. * @param ev The event. */ ondurationchange: (ev: Event) => any; /** - * Occurs when the media element is reset to its initial state. + * Occurs when the media element is reset to its initial state. * @param ev The event. */ onemptied: (ev: Event) => any; /** - * Occurs when the end of playback is reached. + * Occurs when the end of playback is reached. * @param ev The event */ onended: (ev: MediaStreamErrorEvent) => any; @@ -2512,9 +2513,9 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven * Fires when an error occurs during object loading. * @param ev The event. */ - onerror: (ev: Event) => any; + onerror: (ev: ErrorEvent) => any; /** - * Fires when the object receives focus. + * Fires when the object receives focus. * @param ev The event. */ onfocus: (ev: FocusEvent) => any; @@ -2538,12 +2539,12 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven */ onkeyup: (ev: KeyboardEvent) => any; /** - * Fires immediately after the browser loads the object. + * Fires immediately after the browser loads the object. * @param ev The event. */ onload: (ev: Event) => any; /** - * Occurs when media data is loaded at the current playback position. + * Occurs when media data is loaded at the current playback position. * @param ev The event. */ onloadeddata: (ev: Event) => any; @@ -2553,22 +2554,22 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven */ onloadedmetadata: (ev: Event) => any; /** - * Occurs when Internet Explorer begins looking for media data. + * Occurs when Internet Explorer begins looking for media data. * @param ev The event. */ onloadstart: (ev: Event) => any; /** - * Fires when the user clicks the object with either mouse button. + * Fires when the user clicks the object with either mouse button. * @param ev The mouse event. */ onmousedown: (ev: MouseEvent) => any; /** - * Fires when the user moves the mouse over the object. + * Fires when the user moves the mouse over the object. * @param ev The mouse event. */ onmousemove: (ev: MouseEvent) => any; /** - * Fires when the user moves the mouse pointer outside the boundaries of the object. + * Fires when the user moves the mouse pointer outside the boundaries of the object. * @param ev The mouse event. */ onmouseout: (ev: MouseEvent) => any; @@ -2578,12 +2579,12 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven */ onmouseover: (ev: MouseEvent) => any; /** - * Fires when the user releases a mouse button while the mouse is over the object. + * Fires when the user releases a mouse button while the mouse is over the object. * @param ev The mouse event. */ onmouseup: (ev: MouseEvent) => any; /** - * Fires when the wheel button is rotated. + * Fires when the wheel button is rotated. * @param ev The mouse event */ onmousewheel: (ev: WheelEvent) => any; @@ -2605,7 +2606,7 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven onmspointerover: (ev: MSPointerEvent) => any; onmspointerup: (ev: MSPointerEvent) => any; /** - * Occurs when an item is removed from a Jump List of a webpage running in Site Mode. + * Occurs when an item is removed from a Jump List of a webpage running in Site Mode. * @param ev The event. */ onmssitemodejumplistitemremoved: (ev: MSSiteModeEvent) => any; @@ -2620,24 +2621,24 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven */ onpause: (ev: Event) => any; /** - * Occurs when the play method is requested. + * Occurs when the play method is requested. * @param ev The event. */ onplay: (ev: Event) => any; /** - * Occurs when the audio or video has started playing. + * Occurs when the audio or video has started playing. * @param ev The event. */ onplaying: (ev: Event) => any; onpointerlockchange: (ev: Event) => any; onpointerlockerror: (ev: Event) => any; /** - * Occurs to indicate progress while downloading media data. + * Occurs to indicate progress while downloading media data. * @param ev The event. */ onprogress: (ev: ProgressEvent) => any; /** - * Occurs when the playback rate is increased or decreased. + * Occurs when the playback rate is increased or decreased. * @param ev The event. */ onratechange: (ev: Event) => any; @@ -2647,22 +2648,22 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven */ onreadystatechange: (ev: ProgressEvent) => any; /** - * Fires when the user resets a form. + * Fires when the user resets a form. * @param ev The event. */ onreset: (ev: Event) => any; /** - * Fires when the user repositions the scroll box in the scroll bar on the object. + * Fires when the user repositions the scroll box in the scroll bar on the object. * @param ev The event. */ onscroll: (ev: UIEvent) => any; /** - * Occurs when the seek operation ends. + * Occurs when the seek operation ends. * @param ev The event. */ onseeked: (ev: Event) => any; /** - * Occurs when the current playback position is moved. + * Occurs when the current playback position is moved. * @param ev The event. */ onseeking: (ev: Event) => any; @@ -2678,7 +2679,7 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven onselectionchange: (ev: Event) => any; onselectstart: (ev: Event) => any; /** - * Occurs when the download has stopped. + * Occurs when the download has stopped. * @param ev The event. */ onstalled: (ev: Event) => any; @@ -2689,7 +2690,7 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven onstop: (ev: Event) => any; onsubmit: (ev: Event) => any; /** - * Occurs if the load operation has been intentionally halted. + * Occurs if the load operation has been intentionally halted. * @param ev The event. */ onsuspend: (ev: Event) => any; @@ -2708,7 +2709,7 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven */ onvolumechange: (ev: Event) => any; /** - * Occurs when playback stops because the next frame of a video resource is not available. + * Occurs when playback stops because the next frame of a video resource is not available. * @param ev The event. */ onwaiting: (ev: Event) => any; @@ -2742,7 +2743,7 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven */ title: string; readonly visibilityState: string; - /** + /** * Sets or gets the color of the links that the user has visited. */ vlinkColor: string; @@ -2932,7 +2933,7 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven createExpression(expression: string, resolver: XPathNSResolver): XPathExpression; createNSResolver(nodeResolver: Node): XPathNSResolver; /** - * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document. + * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document. * @param root The root element or node to start traversing on. * @param whatToShow The type of nodes or elements to appear in the node list * @param filter A custom NodeFilter function to use. For more information, see filter. Use null for no filter. @@ -2941,11 +2942,11 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven createNodeIterator(root: Node, whatToShow?: number, filter?: NodeFilter, entityReferenceExpansion?: boolean): NodeIterator; createProcessingInstruction(target: string, data: string): ProcessingInstruction; /** - * Returns an empty range object that has both of its boundary points positioned at the beginning of the document. + * Returns an empty range object that has both of its boundary points positioned at the beginning of the document. */ createRange(): Range; /** - * Creates a text string from the specified value. + * Creates a text string from the specified value. * @param data String that specifies the nodeValue property of the text node. */ createTextNode(data: string): Text; @@ -2960,7 +2961,7 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven */ createTreeWalker(root: Node, whatToShow?: number, filter?: NodeFilter, entityReferenceExpansion?: boolean): TreeWalker; /** - * Returns the element for the specified x coordinate and the specified y coordinate. + * Returns the element for the specified x coordinate and the specified y coordinate. * @param x The x-offset * @param y The y-offset */ @@ -2988,7 +2989,7 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven * Returns a reference to the first object with the specified value of the ID or NAME attribute. * @param elementId String that specifies the ID value. Case-insensitive. */ - getElementById(elementId: string): HTMLElement; + getElementById(elementId: string): HTMLElement | null; getElementsByClassName(classNames: string): HTMLCollectionOf; /** * Gets a collection of objects based on the value of the NAME or ID attribute. @@ -3198,7 +3199,7 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven * @param replace Specifies whether the existing entry for the document is replaced in the history list. */ open(url?: string, name?: string, features?: string, replace?: boolean): Document; - /** + /** * Returns a Boolean value that indicates whether a specified command can be successfully executed using execCommand, given the current state of the document. * @param commandId Specifies a command identifier. */ @@ -3220,7 +3221,7 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven queryCommandSupported(commandId: string): boolean; /** * Retrieves the string associated with a command. - * @param commandId String that contains the identifier of a command. This can be any command identifier given in the list of Command Identifiers. + * @param commandId String that contains the identifier of a command. This can be any command identifier given in the list of Command Identifiers. */ queryCommandText(commandId: string): string; /** @@ -3236,12 +3237,12 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven webkitCancelFullScreen(): void; webkitExitFullscreen(): void; /** - * Writes one or more HTML expressions to a document in the specified window. + * Writes one or more HTML expressions to a document in the specified window. * @param content Specifies the text and HTML tags to write. */ write(...content: string[]): void; /** - * Writes one or more HTML expressions, followed by a carriage return, to a document in the specified window. + * Writes one or more HTML expressions, followed by a carriage return, to a document in the specified window. * @param content The text and HTML tags to write. */ writeln(...content: string[]): void; @@ -3463,7 +3464,7 @@ interface Element extends Node, GlobalEventHandlers, ElementTraversal, NodeSelec readonly scrollWidth: number; readonly tagName: string; innerHTML: string; - getAttribute(name?: string): string | null; + getAttribute(name: string): string | null; getAttributeNS(namespaceURI: string, localName: string): string; getAttributeNode(name: string): Attr; getAttributeNodeNS(namespaceURI: string, localName: string): Attr; @@ -3673,6 +3674,7 @@ interface Element extends Node, GlobalEventHandlers, ElementTraversal, NodeSelec webkitRequestFullscreen(): void; getElementsByClassName(classNames: string): NodeListOf; matches(selector: string): boolean; + closest(selector: string): Element | null; addEventListener(type: "MSGestureChange", listener: (ev: MSGestureEvent) => any, useCapture?: boolean): void; addEventListener(type: "MSGestureDoubleTap", listener: (ev: MSGestureEvent) => any, useCapture?: boolean): void; addEventListener(type: "MSGestureEnd", listener: (ev: MSGestureEvent) => any, useCapture?: boolean): void; @@ -3969,12 +3971,12 @@ interface HTMLAnchorElement extends HTMLElement { */ target: string; /** - * Retrieves or sets the text of the object as a string. + * Retrieves or sets the text of the object as a string. */ text: string; type: string; urn: string; - /** + /** * Returns a string representation of an object. */ toString(): string; @@ -4076,7 +4078,7 @@ interface HTMLAreaElement extends HTMLElement { */ host: string; /** - * Sets or retrieves the host name part of the location or URL. + * Sets or retrieves the host name part of the location or URL. */ hostname: string; /** @@ -4112,7 +4114,7 @@ interface HTMLAreaElement extends HTMLElement { * Sets or retrieves the window or frame at which to target content. */ target: string; - /** + /** * Returns a string representation of an object. */ toString(): string; @@ -4203,7 +4205,7 @@ interface HTMLBodyElement extends HTMLElement { onbeforeprint: (ev: Event) => any; onbeforeunload: (ev: BeforeUnloadEvent) => any; onblur: (ev: FocusEvent) => any; - onerror: (ev: Event) => any; + onerror: (ev: ErrorEvent) => any; onfocus: (ev: FocusEvent) => any; onhashchange: (ev: HashChangeEvent) => any; onload: (ev: Event) => any; @@ -4378,7 +4380,7 @@ interface HTMLButtonElement extends HTMLElement { * Overrides the target attribute on a form element. */ formTarget: string; - /** + /** * Sets or retrieves the name of the object. */ name: string; @@ -4395,7 +4397,7 @@ interface HTMLButtonElement extends HTMLElement { * Returns a ValidityState object that represents the validity states of an element. */ readonly validity: ValidityState; - /** + /** * Sets or retrieves the default or selected value of the control. */ value: string; @@ -4432,9 +4434,9 @@ interface HTMLCanvasElement extends HTMLElement { * Returns an object that provides methods and properties for drawing and manipulating images and graphics on a canvas element in a document. A context object includes information about colors, line widths, fonts, and other graphic parameters that can be drawn on a canvas. * @param contextId The identifier (ID) of the type of canvas to create. Internet Explorer 9 and Internet Explorer 10 support only a 2-D context using canvas.getContext("2d"); IE11 Preview also supports 3-D or WebGL context using canvas.getContext("experimental-webgl"); */ - getContext(contextId: "2d"): CanvasRenderingContext2D; - getContext(contextId: "experimental-webgl"): WebGLRenderingContext; - getContext(contextId: string, ...args: any[]): CanvasRenderingContext2D | WebGLRenderingContext; + getContext(contextId: "2d", contextAttributes?: Canvas2DContextAttributes): CanvasRenderingContext2D | null; + getContext(contextId: "webgl" | "experimental-webgl", contextAttributes?: WebGLContextAttributes): WebGLRenderingContext | null; + getContext(contextId: string, contextAttributes?: {}): CanvasRenderingContext2D | WebGLRenderingContext | null; /** * Returns a blob object encoded as a Portable Network Graphics (PNG) format from a canvas image or drawing. */ @@ -4444,7 +4446,7 @@ interface HTMLCanvasElement extends HTMLElement { * @param type The standard MIME type for the image format to return. If you do not specify this parameter, the default value is a PNG format image. */ toDataURL(type?: string, ...args: any[]): string; - toBlob(): Blob; + toBlob(callback: (result: Blob | null) => void, ... arguments: any[]): void; } declare var HTMLCanvasElement: { @@ -4502,7 +4504,7 @@ declare var HTMLDirectoryElement: { interface HTMLDivElement extends HTMLElement { /** - * Sets or retrieves how the object is aligned with adjacent text. + * Sets or retrieves how the object is aligned with adjacent text. */ align: string; /** @@ -4542,7 +4544,7 @@ interface HTMLElement extends Element { readonly offsetParent: Element; readonly offsetTop: number; readonly offsetWidth: number; - onabort: (ev: Event) => any; + onabort: (ev: UIEvent) => any; onactivate: (ev: UIEvent) => any; onbeforeactivate: (ev: UIEvent) => any; onbeforecopy: (ev: ClipboardEvent) => any; @@ -4570,7 +4572,7 @@ interface HTMLElement extends Element { ondurationchange: (ev: Event) => any; onemptied: (ev: Event) => any; onended: (ev: MediaStreamErrorEvent) => any; - onerror: (ev: Event) => any; + onerror: (ev: ErrorEvent) => any; onfocus: (ev: FocusEvent) => any; oninput: (ev: Event) => any; oninvalid: (ev: Event) => any; @@ -5120,7 +5122,7 @@ interface HTMLFrameSetElement extends HTMLElement { * Fires when the object loses the input focus. */ onblur: (ev: FocusEvent) => any; - onerror: (ev: Event) => any; + onerror: (ev: ErrorEvent) => any; /** * Fires when the object receives focus. */ @@ -5643,9 +5645,9 @@ interface HTMLInputElement extends HTMLElement { /** * Returns a FileList object on a file type input object. */ - readonly files: FileList; + readonly files: FileList | null; /** - * Retrieves a reference to the form that the object is embedded in. + * Retrieves a reference to the form that the object is embedded in. */ readonly form: HTMLFormElement; /** @@ -6365,7 +6367,7 @@ interface HTMLMetaElement extends HTMLElement { */ scheme: string; /** - * Sets or retrieves the URL property that will be loaded after the specified time has elapsed. + * Sets or retrieves the URL property that will be loaded after the specified time has elapsed. */ url: string; } @@ -6614,7 +6616,7 @@ declare var HTMLOptionElement: { create(): HTMLOptionElement; } -interface HTMLOptionsCollection extends HTMLCollection { +interface HTMLOptionsCollection extends HTMLCollectionOf { length: number; selectedIndex: number; add(element: HTMLOptionElement | HTMLOptGroupElement, before?: HTMLElement | number): void; @@ -6628,7 +6630,7 @@ declare var HTMLOptionsCollection: { interface HTMLParagraphElement extends HTMLElement { /** - * Sets or retrieves how the object is aligned with adjacent text. + * Sets or retrieves how the object is aligned with adjacent text. */ align: string; clear: string; @@ -6730,10 +6732,10 @@ interface HTMLScriptElement extends HTMLElement { */ defer: boolean; /** - * Sets or retrieves the event for which the script is written. + * Sets or retrieves the event for which the script is written. */ event: string; - /** + /** * Sets or retrieves the object that is bound to the event script. */ htmlFor: string; @@ -6742,7 +6744,7 @@ interface HTMLScriptElement extends HTMLElement { */ src: string; /** - * Retrieves or sets the text of the object as a string. + * Retrieves or sets the text of the object as a string. */ text: string; /** @@ -6763,7 +6765,7 @@ interface HTMLSelectElement extends HTMLElement { autofocus: boolean; disabled: boolean; /** - * Retrieves a reference to the form that the object is embedded in. + * Retrieves a reference to the form that the object is embedded in. */ readonly form: HTMLFormElement; /** @@ -6778,7 +6780,7 @@ interface HTMLSelectElement extends HTMLElement { * Sets or retrieves the name of the object. */ name: string; - options: HTMLCollectionOf; + readonly options: HTMLOptionsCollection; /** * When present, marks an element that can't be submitted without a value. */ @@ -6789,7 +6791,7 @@ interface HTMLSelectElement extends HTMLElement { selectedIndex: number; selectedOptions: HTMLCollectionOf; /** - * Sets or retrieves the number of rows in the list box. + * Sets or retrieves the number of rows in the list box. */ size: number; /** @@ -6815,7 +6817,7 @@ interface HTMLSelectElement extends HTMLElement { /** * Adds an element to the areas, controlRange, or options collection. * @param element Variant of type Number that specifies the index position in the collection where the element is placed. If no value is given, the method places the element at the end of the collection. - * @param before Variant of type Object that specifies an element to insert before, or null to append the object to the collection. + * @param before Variant of type Object that specifies an element to insert before, or null to append the object to the collection. */ add(element: HTMLElement, before?: HTMLElement | number): void; /** @@ -7010,7 +7012,7 @@ interface HTMLTableElement extends HTMLElement { */ border: string; /** - * Sets or retrieves the border color of the object. + * Sets or retrieves the border color of the object. */ borderColor: any; /** @@ -7305,7 +7307,7 @@ declare var HTMLTextAreaElement: { interface HTMLTitleElement extends HTMLElement { /** - * Retrieves or sets the text of the object as a string. + * Retrieves or sets the text of the object as a string. */ text: string; } @@ -7574,7 +7576,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; @@ -7677,7 +7679,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; @@ -7699,7 +7701,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; @@ -7842,7 +7844,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; @@ -8202,7 +8204,7 @@ declare var MSStreamReader: { interface MSWebViewAsyncOperation extends EventTarget { readonly error: DOMError; oncomplete: (ev: Event) => any; - onerror: (ev: Event) => any; + onerror: (ev: ErrorEvent) => any; readonly readyState: number; readonly result: any; readonly target: MSHTMLWebViewElement; @@ -8738,7 +8740,7 @@ interface Node extends EventTarget { contains(child: Node): boolean; hasAttributes(): boolean; hasChildNodes(): boolean; - insertBefore(newChild: Node, refChild: Node): Node; + insertBefore(newChild: Node, refChild: Node | null): Node; isDefaultNamespace(namespaceURI: string | null): boolean; isEqualNode(arg: Node): boolean; isSameNode(other: Node): boolean; @@ -8747,7 +8749,6 @@ interface Node extends EventTarget { normalize(): void; removeChild(oldChild: Node): Node; replaceChild(newChild: Node, oldChild: Node): Node; - contains(node: Node): boolean; readonly ATTRIBUTE_NODE: number; readonly CDATA_SECTION_NODE: number; readonly COMMENT_NODE: number; @@ -9283,7 +9284,7 @@ declare var RTCDTMFToneChangeEvent: { interface RTCDtlsTransport extends RTCStatsProvider { ondtlsstatechange: ((ev: RTCDtlsTransportStateChangedEvent) => any) | null; - onerror: ((ev: Event) => any) | null; + onerror: ((ev: ErrorEvent) => any) | null; readonly state: string; readonly transport: RTCIceTransport; getLocalParameters(): RTCDtlsParameters; @@ -9338,7 +9339,7 @@ declare var RTCIceCandidatePairChangedEvent: { interface RTCIceGatherer extends RTCStatsProvider { readonly component: string; - onerror: ((ev: Event) => any) | null; + onerror: ((ev: ErrorEvent) => any) | null; onlocalcandidate: ((ev: RTCIceGathererEvent) => any) | null; createAssociatedGatherer(): RTCIceGatherer; getLocalCandidates(): RTCIceCandidate[]; @@ -9397,7 +9398,7 @@ declare var RTCIceTransportStateChangedEvent: { } interface RTCRtpReceiver extends RTCStatsProvider { - onerror: ((ev: Event) => any) | null; + onerror: ((ev: ErrorEvent) => any) | null; readonly rtcpTransport: RTCDtlsTransport; readonly track: MediaStreamTrack | null; readonly transport: RTCDtlsTransport | RTCSrtpSdesTransport; @@ -9417,7 +9418,7 @@ declare var RTCRtpReceiver: { } interface RTCRtpSender extends RTCStatsProvider { - onerror: ((ev: Event) => any) | null; + onerror: ((ev: ErrorEvent) => any) | null; onssrcconflict: ((ev: RTCSsrcConflictEvent) => any) | null; readonly rtcpTransport: RTCDtlsTransport; readonly track: MediaStreamTrack; @@ -9438,7 +9439,7 @@ declare var RTCRtpSender: { } interface RTCSrtpSdesTransport extends EventTarget { - onerror: ((ev: Event) => any) | null; + onerror: ((ev: ErrorEvent) => any) | null; readonly transport: RTCIceTransport; addEventListener(type: "error", listener: (ev: ErrorEvent) => any, useCapture?: boolean): void; addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; @@ -11478,18 +11479,24 @@ declare var StyleSheetPageList: { } interface SubtleCrypto { - decrypt(algorithm: string | Algorithm, key: CryptoKey, data: ArrayBufferView): PromiseLike; - deriveBits(algorithm: string | Algorithm, baseKey: CryptoKey, length: number): PromiseLike; - deriveKey(algorithm: string | Algorithm, baseKey: CryptoKey, derivedKeyType: string | Algorithm, extractable: boolean, keyUsages: string[]): PromiseLike; - digest(algorithm: string | Algorithm, data: ArrayBufferView): PromiseLike; - encrypt(algorithm: string | Algorithm, key: CryptoKey, data: ArrayBufferView): PromiseLike; - exportKey(format: string, key: CryptoKey): PromiseLike; - generateKey(algorithm: string | Algorithm, extractable: boolean, keyUsages: string[]): PromiseLike; - importKey(format: string, keyData: ArrayBufferView, algorithm: string | Algorithm | null, extractable: boolean, keyUsages: string[]): PromiseLike; - sign(algorithm: string | Algorithm, key: CryptoKey, data: ArrayBufferView): PromiseLike; - unwrapKey(format: string, wrappedKey: ArrayBufferView, unwrappingKey: CryptoKey, unwrapAlgorithm: string | Algorithm, unwrappedKeyAlgorithm: string | Algorithm | null, extractable: boolean, keyUsages: string[]): PromiseLike; - verify(algorithm: string | Algorithm, key: CryptoKey, signature: ArrayBufferView, data: ArrayBufferView): PromiseLike; - wrapKey(format: string, key: CryptoKey, wrappingKey: CryptoKey, wrapAlgorithm: string | Algorithm): PromiseLike; + decrypt(algorithm: string | RsaOaepParams | AesCtrParams | AesCbcParams | AesCmacParams | AesGcmParams | AesCfbParams, key: CryptoKey, data: BufferSource): PromiseLike; + deriveBits(algorithm: string | EcdhKeyDeriveParams | DhKeyDeriveParams | ConcatParams | HkdfCtrParams | Pbkdf2Params, baseKey: CryptoKey, length: number): PromiseLike; + deriveKey(algorithm: string | EcdhKeyDeriveParams | DhKeyDeriveParams | ConcatParams | HkdfCtrParams | Pbkdf2Params, baseKey: CryptoKey, derivedKeyType: string | AesDerivedKeyParams | HmacImportParams | ConcatParams | HkdfCtrParams | Pbkdf2Params, extractable: boolean, keyUsages: string[]): PromiseLike; + digest(algorithm: AlgorithmIdentifier, data: BufferSource): PromiseLike; + encrypt(algorithm: string | RsaOaepParams | AesCtrParams | AesCbcParams | AesCmacParams | AesGcmParams | AesCfbParams, key: CryptoKey, data: BufferSource): PromiseLike; + exportKey(format: "jwk", key: CryptoKey): PromiseLike; + exportKey(format: "raw" | "pkcs8" | "spki", key: CryptoKey): PromiseLike; + exportKey(format: string, key: CryptoKey): PromiseLike; + generateKey(algorithm: string, extractable: boolean, keyUsages: string[]): PromiseLike; + generateKey(algorithm: RsaHashedKeyGenParams | EcKeyGenParams | DhKeyGenParams, extractable: boolean, keyUsages: string[]): PromiseLike; + generateKey(algorithm: AesKeyGenParams | HmacKeyGenParams | Pbkdf2Params, extractable: boolean, keyUsages: string[]): PromiseLike; + importKey(format: "jwk", keyData: JsonWebKey, algorithm: string | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | DhImportKeyParams, extractable:boolean, keyUsages: string[]): PromiseLike; + importKey(format: "raw" | "pkcs8" | "spki", keyData: BufferSource, algorithm: string | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | DhImportKeyParams, extractable:boolean, keyUsages: string[]): PromiseLike; + importKey(format: string, keyData: JsonWebKey | BufferSource, algorithm: string | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | DhImportKeyParams, extractable:boolean, keyUsages: string[]): PromiseLike; + sign(algorithm: string | RsaPssParams | EcdsaParams | AesCmacParams, key: CryptoKey, data: BufferSource): PromiseLike; + unwrapKey(format: string, wrappedKey: BufferSource, unwrappingKey: CryptoKey, unwrapAlgorithm: AlgorithmIdentifier, unwrappedKeyAlgorithm: AlgorithmIdentifier, extractable: boolean, keyUsages: string[]): PromiseLike; + verify(algorithm: string | RsaPssParams | EcdsaParams | AesCmacParams, key: CryptoKey, signature: BufferSource, data: BufferSource): PromiseLike; + wrapKey(format: string, key: CryptoKey, wrappingKey: CryptoKey, wrapAlgorithm: AlgorithmIdentifier): PromiseLike; } declare var SubtleCrypto: { @@ -11557,7 +11564,7 @@ interface TextTrack extends EventTarget { readonly language: string; mode: any; oncuechange: (ev: Event) => any; - onerror: (ev: Event) => any; + onerror: (ev: ErrorEvent) => any; onload: (ev: Event) => any; readonly readyState: number; addCue(cue: TextTrackCue): void; @@ -12046,18 +12053,12 @@ interface WebGLRenderingContext { stencilMaskSeparate(face: number, mask: number): void; stencilOp(fail: number, zfail: number, zpass: number): void; stencilOpSeparate(face: number, fail: number, zfail: number, zpass: number): void; - texImage2D(target: number, level: number, internalformat: number, width: number, height: number, border: number, format: number, type: number, pixels: ArrayBufferView): void; - texImage2D(target: number, level: number, internalformat: number, format: number, type: number, image: HTMLImageElement): void; - texImage2D(target: number, level: number, internalformat: number, format: number, type: number, canvas: HTMLCanvasElement): void; - texImage2D(target: number, level: number, internalformat: number, format: number, type: number, video: HTMLVideoElement): void; - texImage2D(target: number, level: number, internalformat: number, format: number, type: number, pixels: ImageData): void; + texImage2D(target: number, level: number, internalformat: number, width: number, height: number, border: number, format: number, type: number, pixels?: ArrayBufferView): void; + texImage2D(target: number, level: number, internalformat: number, format: number, type: number, pixels?: ImageData | HTMLVideoElement | HTMLImageElement | HTMLCanvasElement): void; texParameterf(target: number, pname: number, param: number): void; texParameteri(target: number, pname: number, param: number): void; - texSubImage2D(target: number, level: number, xoffset: number, yoffset: number, width: number, height: number, format: number, type: number, pixels: ArrayBufferView): void; - texSubImage2D(target: number, level: number, xoffset: number, yoffset: number, format: number, type: number, image: HTMLImageElement): void; - texSubImage2D(target: number, level: number, xoffset: number, yoffset: number, format: number, type: number, canvas: HTMLCanvasElement): void; - texSubImage2D(target: number, level: number, xoffset: number, yoffset: number, format: number, type: number, video: HTMLVideoElement): void; - texSubImage2D(target: number, level: number, xoffset: number, yoffset: number, format: number, type: number, pixels: ImageData): void; + texSubImage2D(target: number, level: number, xoffset: number, yoffset: number, width: number, height: number, format: number, type: number, pixels?: ArrayBufferView): void; + texSubImage2D(target: number, level: number, xoffset: number, yoffset: number, format: number, type: number, pixels?: ImageData | HTMLVideoElement | HTMLImageElement | HTMLCanvasElement): void; uniform1f(location: WebGLUniformLocation | null, x: number): void; uniform1fv(location: WebGLUniformLocation, v: Float32Array | number[]): void; uniform1i(location: WebGLUniformLocation | null, x: number): void; @@ -12780,7 +12781,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; @@ -12855,7 +12856,7 @@ interface Window extends EventTarget, WindowTimers, WindowSessionStorage, Window name: string; readonly navigator: Navigator; offscreenBuffering: string | boolean; - onabort: (ev: Event) => any; + onabort: (ev: UIEvent) => any; onafterprint: (ev: Event) => any; onbeforeprint: (ev: Event) => any; onbeforeunload: (ev: BeforeUnloadEvent) => any; @@ -12971,6 +12972,7 @@ interface Window extends EventTarget, WindowTimers, WindowSessionStorage, Window readonly top: Window; readonly window: Window; URL: typeof URL; + Blob: typeof Blob; alert(message?: any): void; blur(): void; cancelAnimationFrame(handle: number): void; @@ -13127,7 +13129,6 @@ declare var XMLDocument: { } interface XMLHttpRequest extends EventTarget, XMLHttpRequestEventTarget { - msCaching: string; onreadystatechange: (ev: ProgressEvent) => any; readonly readyState: number; readonly response: any; @@ -13139,6 +13140,7 @@ interface XMLHttpRequest extends EventTarget, XMLHttpRequestEventTarget { timeout: number; readonly upload: XMLHttpRequestUpload; withCredentials: boolean; + msCaching?: string; abort(): void; getAllResponseHeaders(): string; getResponseHeader(header: string): string | null; @@ -13277,7 +13279,7 @@ declare var XSLTProcessor: { } 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; } @@ -13436,7 +13438,7 @@ interface LinkStyle { 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; @@ -13501,7 +13503,359 @@ interface NavigatorUserMedia { } interface NodeSelector { + querySelector(selectors: "a"): HTMLAnchorElement; + querySelector(selectors: "abbr"): HTMLElement; + querySelector(selectors: "acronym"): HTMLElement; + querySelector(selectors: "address"): HTMLElement; + querySelector(selectors: "applet"): HTMLAppletElement; + querySelector(selectors: "area"): HTMLAreaElement; + querySelector(selectors: "article"): HTMLElement; + querySelector(selectors: "aside"): HTMLElement; + querySelector(selectors: "audio"): HTMLAudioElement; + querySelector(selectors: "b"): HTMLElement; + querySelector(selectors: "base"): HTMLBaseElement; + querySelector(selectors: "basefont"): HTMLBaseFontElement; + querySelector(selectors: "bdo"): HTMLElement; + querySelector(selectors: "big"): HTMLElement; + querySelector(selectors: "blockquote"): HTMLQuoteElement; + querySelector(selectors: "body"): HTMLBodyElement; + querySelector(selectors: "br"): HTMLBRElement; + querySelector(selectors: "button"): HTMLButtonElement; + querySelector(selectors: "canvas"): HTMLCanvasElement; + querySelector(selectors: "caption"): HTMLTableCaptionElement; + querySelector(selectors: "center"): HTMLElement; + querySelector(selectors: "circle"): SVGCircleElement; + querySelector(selectors: "cite"): HTMLElement; + querySelector(selectors: "clippath"): SVGClipPathElement; + querySelector(selectors: "code"): HTMLElement; + querySelector(selectors: "col"): HTMLTableColElement; + querySelector(selectors: "colgroup"): HTMLTableColElement; + querySelector(selectors: "datalist"): HTMLDataListElement; + querySelector(selectors: "dd"): HTMLElement; + querySelector(selectors: "defs"): SVGDefsElement; + querySelector(selectors: "del"): HTMLModElement; + querySelector(selectors: "desc"): SVGDescElement; + querySelector(selectors: "dfn"): HTMLElement; + querySelector(selectors: "dir"): HTMLDirectoryElement; + querySelector(selectors: "div"): HTMLDivElement; + querySelector(selectors: "dl"): HTMLDListElement; + querySelector(selectors: "dt"): HTMLElement; + querySelector(selectors: "ellipse"): SVGEllipseElement; + querySelector(selectors: "em"): HTMLElement; + querySelector(selectors: "embed"): HTMLEmbedElement; + querySelector(selectors: "feblend"): SVGFEBlendElement; + querySelector(selectors: "fecolormatrix"): SVGFEColorMatrixElement; + querySelector(selectors: "fecomponenttransfer"): SVGFEComponentTransferElement; + querySelector(selectors: "fecomposite"): SVGFECompositeElement; + querySelector(selectors: "feconvolvematrix"): SVGFEConvolveMatrixElement; + querySelector(selectors: "fediffuselighting"): SVGFEDiffuseLightingElement; + querySelector(selectors: "fedisplacementmap"): SVGFEDisplacementMapElement; + querySelector(selectors: "fedistantlight"): SVGFEDistantLightElement; + querySelector(selectors: "feflood"): SVGFEFloodElement; + querySelector(selectors: "fefunca"): SVGFEFuncAElement; + querySelector(selectors: "fefuncb"): SVGFEFuncBElement; + querySelector(selectors: "fefuncg"): SVGFEFuncGElement; + querySelector(selectors: "fefuncr"): SVGFEFuncRElement; + querySelector(selectors: "fegaussianblur"): SVGFEGaussianBlurElement; + querySelector(selectors: "feimage"): SVGFEImageElement; + querySelector(selectors: "femerge"): SVGFEMergeElement; + querySelector(selectors: "femergenode"): SVGFEMergeNodeElement; + querySelector(selectors: "femorphology"): SVGFEMorphologyElement; + querySelector(selectors: "feoffset"): SVGFEOffsetElement; + querySelector(selectors: "fepointlight"): SVGFEPointLightElement; + querySelector(selectors: "fespecularlighting"): SVGFESpecularLightingElement; + querySelector(selectors: "fespotlight"): SVGFESpotLightElement; + querySelector(selectors: "fetile"): SVGFETileElement; + querySelector(selectors: "feturbulence"): SVGFETurbulenceElement; + querySelector(selectors: "fieldset"): HTMLFieldSetElement; + querySelector(selectors: "figcaption"): HTMLElement; + querySelector(selectors: "figure"): HTMLElement; + querySelector(selectors: "filter"): SVGFilterElement; + querySelector(selectors: "font"): HTMLFontElement; + querySelector(selectors: "footer"): HTMLElement; + querySelector(selectors: "foreignobject"): SVGForeignObjectElement; + querySelector(selectors: "form"): HTMLFormElement; + querySelector(selectors: "frame"): HTMLFrameElement; + querySelector(selectors: "frameset"): HTMLFrameSetElement; + querySelector(selectors: "g"): SVGGElement; + querySelector(selectors: "h1"): HTMLHeadingElement; + querySelector(selectors: "h2"): HTMLHeadingElement; + querySelector(selectors: "h3"): HTMLHeadingElement; + querySelector(selectors: "h4"): HTMLHeadingElement; + querySelector(selectors: "h5"): HTMLHeadingElement; + querySelector(selectors: "h6"): HTMLHeadingElement; + querySelector(selectors: "head"): HTMLHeadElement; + querySelector(selectors: "header"): HTMLElement; + querySelector(selectors: "hgroup"): HTMLElement; + querySelector(selectors: "hr"): HTMLHRElement; + querySelector(selectors: "html"): HTMLHtmlElement; + querySelector(selectors: "i"): HTMLElement; + querySelector(selectors: "iframe"): HTMLIFrameElement; + querySelector(selectors: "image"): SVGImageElement; + querySelector(selectors: "img"): HTMLImageElement; + querySelector(selectors: "input"): HTMLInputElement; + querySelector(selectors: "ins"): HTMLModElement; + querySelector(selectors: "isindex"): HTMLUnknownElement; + querySelector(selectors: "kbd"): HTMLElement; + querySelector(selectors: "keygen"): HTMLElement; + querySelector(selectors: "label"): HTMLLabelElement; + querySelector(selectors: "legend"): HTMLLegendElement; + querySelector(selectors: "li"): HTMLLIElement; + querySelector(selectors: "line"): SVGLineElement; + querySelector(selectors: "lineargradient"): SVGLinearGradientElement; + querySelector(selectors: "link"): HTMLLinkElement; + querySelector(selectors: "listing"): HTMLPreElement; + querySelector(selectors: "map"): HTMLMapElement; + querySelector(selectors: "mark"): HTMLElement; + querySelector(selectors: "marker"): SVGMarkerElement; + querySelector(selectors: "marquee"): HTMLMarqueeElement; + querySelector(selectors: "mask"): SVGMaskElement; + querySelector(selectors: "menu"): HTMLMenuElement; + querySelector(selectors: "meta"): HTMLMetaElement; + querySelector(selectors: "metadata"): SVGMetadataElement; + querySelector(selectors: "meter"): HTMLMeterElement; + querySelector(selectors: "nav"): HTMLElement; + querySelector(selectors: "nextid"): HTMLUnknownElement; + querySelector(selectors: "nobr"): HTMLElement; + querySelector(selectors: "noframes"): HTMLElement; + querySelector(selectors: "noscript"): HTMLElement; + querySelector(selectors: "object"): HTMLObjectElement; + querySelector(selectors: "ol"): HTMLOListElement; + querySelector(selectors: "optgroup"): HTMLOptGroupElement; + querySelector(selectors: "option"): HTMLOptionElement; + querySelector(selectors: "p"): HTMLParagraphElement; + querySelector(selectors: "param"): HTMLParamElement; + querySelector(selectors: "path"): SVGPathElement; + querySelector(selectors: "pattern"): SVGPatternElement; + querySelector(selectors: "picture"): HTMLPictureElement; + querySelector(selectors: "plaintext"): HTMLElement; + querySelector(selectors: "polygon"): SVGPolygonElement; + querySelector(selectors: "polyline"): SVGPolylineElement; + querySelector(selectors: "pre"): HTMLPreElement; + querySelector(selectors: "progress"): HTMLProgressElement; + querySelector(selectors: "q"): HTMLQuoteElement; + querySelector(selectors: "radialgradient"): SVGRadialGradientElement; + querySelector(selectors: "rect"): SVGRectElement; + querySelector(selectors: "rt"): HTMLElement; + querySelector(selectors: "ruby"): HTMLElement; + querySelector(selectors: "s"): HTMLElement; + querySelector(selectors: "samp"): HTMLElement; + querySelector(selectors: "script"): HTMLScriptElement; + querySelector(selectors: "section"): HTMLElement; + querySelector(selectors: "select"): HTMLSelectElement; + querySelector(selectors: "small"): HTMLElement; + querySelector(selectors: "source"): HTMLSourceElement; + querySelector(selectors: "span"): HTMLSpanElement; + querySelector(selectors: "stop"): SVGStopElement; + querySelector(selectors: "strike"): HTMLElement; + querySelector(selectors: "strong"): HTMLElement; + querySelector(selectors: "style"): HTMLStyleElement; + querySelector(selectors: "sub"): HTMLElement; + querySelector(selectors: "sup"): HTMLElement; + querySelector(selectors: "svg"): SVGSVGElement; + querySelector(selectors: "switch"): SVGSwitchElement; + querySelector(selectors: "symbol"): SVGSymbolElement; + querySelector(selectors: "table"): HTMLTableElement; + querySelector(selectors: "tbody"): HTMLTableSectionElement; + querySelector(selectors: "td"): HTMLTableDataCellElement; + querySelector(selectors: "template"): HTMLTemplateElement; + querySelector(selectors: "text"): SVGTextElement; + querySelector(selectors: "textpath"): SVGTextPathElement; + querySelector(selectors: "textarea"): HTMLTextAreaElement; + querySelector(selectors: "tfoot"): HTMLTableSectionElement; + querySelector(selectors: "th"): HTMLTableHeaderCellElement; + querySelector(selectors: "thead"): HTMLTableSectionElement; + querySelector(selectors: "title"): HTMLTitleElement; + querySelector(selectors: "tr"): HTMLTableRowElement; + querySelector(selectors: "track"): HTMLTrackElement; + querySelector(selectors: "tspan"): SVGTSpanElement; + querySelector(selectors: "tt"): HTMLElement; + querySelector(selectors: "u"): HTMLElement; + querySelector(selectors: "ul"): HTMLUListElement; + querySelector(selectors: "use"): SVGUseElement; + querySelector(selectors: "var"): HTMLElement; + querySelector(selectors: "video"): HTMLVideoElement; + querySelector(selectors: "view"): SVGViewElement; + querySelector(selectors: "wbr"): HTMLElement; + querySelector(selectors: "x-ms-webview"): MSHTMLWebViewElement; + querySelector(selectors: "xmp"): HTMLPreElement; querySelector(selectors: string): Element; + querySelectorAll(selectors: "a"): NodeListOf; + querySelectorAll(selectors: "abbr"): NodeListOf; + querySelectorAll(selectors: "acronym"): NodeListOf; + querySelectorAll(selectors: "address"): NodeListOf; + querySelectorAll(selectors: "applet"): NodeListOf; + querySelectorAll(selectors: "area"): NodeListOf; + querySelectorAll(selectors: "article"): NodeListOf; + querySelectorAll(selectors: "aside"): NodeListOf; + querySelectorAll(selectors: "audio"): NodeListOf; + querySelectorAll(selectors: "b"): NodeListOf; + querySelectorAll(selectors: "base"): NodeListOf; + querySelectorAll(selectors: "basefont"): NodeListOf; + querySelectorAll(selectors: "bdo"): NodeListOf; + querySelectorAll(selectors: "big"): NodeListOf; + querySelectorAll(selectors: "blockquote"): NodeListOf; + querySelectorAll(selectors: "body"): NodeListOf; + querySelectorAll(selectors: "br"): NodeListOf; + querySelectorAll(selectors: "button"): NodeListOf; + querySelectorAll(selectors: "canvas"): NodeListOf; + querySelectorAll(selectors: "caption"): NodeListOf; + querySelectorAll(selectors: "center"): NodeListOf; + querySelectorAll(selectors: "circle"): NodeListOf; + querySelectorAll(selectors: "cite"): NodeListOf; + querySelectorAll(selectors: "clippath"): NodeListOf; + querySelectorAll(selectors: "code"): NodeListOf; + querySelectorAll(selectors: "col"): NodeListOf; + querySelectorAll(selectors: "colgroup"): NodeListOf; + querySelectorAll(selectors: "datalist"): NodeListOf; + querySelectorAll(selectors: "dd"): NodeListOf; + querySelectorAll(selectors: "defs"): NodeListOf; + querySelectorAll(selectors: "del"): NodeListOf; + querySelectorAll(selectors: "desc"): NodeListOf; + querySelectorAll(selectors: "dfn"): NodeListOf; + querySelectorAll(selectors: "dir"): NodeListOf; + querySelectorAll(selectors: "div"): NodeListOf; + querySelectorAll(selectors: "dl"): NodeListOf; + querySelectorAll(selectors: "dt"): NodeListOf; + querySelectorAll(selectors: "ellipse"): NodeListOf; + querySelectorAll(selectors: "em"): NodeListOf; + querySelectorAll(selectors: "embed"): NodeListOf; + querySelectorAll(selectors: "feblend"): NodeListOf; + querySelectorAll(selectors: "fecolormatrix"): NodeListOf; + querySelectorAll(selectors: "fecomponenttransfer"): NodeListOf; + querySelectorAll(selectors: "fecomposite"): NodeListOf; + querySelectorAll(selectors: "feconvolvematrix"): NodeListOf; + querySelectorAll(selectors: "fediffuselighting"): NodeListOf; + querySelectorAll(selectors: "fedisplacementmap"): NodeListOf; + querySelectorAll(selectors: "fedistantlight"): NodeListOf; + querySelectorAll(selectors: "feflood"): NodeListOf; + querySelectorAll(selectors: "fefunca"): NodeListOf; + querySelectorAll(selectors: "fefuncb"): NodeListOf; + querySelectorAll(selectors: "fefuncg"): NodeListOf; + querySelectorAll(selectors: "fefuncr"): NodeListOf; + querySelectorAll(selectors: "fegaussianblur"): NodeListOf; + querySelectorAll(selectors: "feimage"): NodeListOf; + querySelectorAll(selectors: "femerge"): NodeListOf; + querySelectorAll(selectors: "femergenode"): NodeListOf; + querySelectorAll(selectors: "femorphology"): NodeListOf; + querySelectorAll(selectors: "feoffset"): NodeListOf; + querySelectorAll(selectors: "fepointlight"): NodeListOf; + querySelectorAll(selectors: "fespecularlighting"): NodeListOf; + querySelectorAll(selectors: "fespotlight"): NodeListOf; + querySelectorAll(selectors: "fetile"): NodeListOf; + querySelectorAll(selectors: "feturbulence"): NodeListOf; + querySelectorAll(selectors: "fieldset"): NodeListOf; + querySelectorAll(selectors: "figcaption"): NodeListOf; + querySelectorAll(selectors: "figure"): NodeListOf; + querySelectorAll(selectors: "filter"): NodeListOf; + querySelectorAll(selectors: "font"): NodeListOf; + querySelectorAll(selectors: "footer"): NodeListOf; + querySelectorAll(selectors: "foreignobject"): NodeListOf; + querySelectorAll(selectors: "form"): NodeListOf; + querySelectorAll(selectors: "frame"): NodeListOf; + querySelectorAll(selectors: "frameset"): NodeListOf; + querySelectorAll(selectors: "g"): NodeListOf; + querySelectorAll(selectors: "h1"): NodeListOf; + querySelectorAll(selectors: "h2"): NodeListOf; + querySelectorAll(selectors: "h3"): NodeListOf; + querySelectorAll(selectors: "h4"): NodeListOf; + querySelectorAll(selectors: "h5"): NodeListOf; + querySelectorAll(selectors: "h6"): NodeListOf; + querySelectorAll(selectors: "head"): NodeListOf; + querySelectorAll(selectors: "header"): NodeListOf; + querySelectorAll(selectors: "hgroup"): NodeListOf; + querySelectorAll(selectors: "hr"): NodeListOf; + querySelectorAll(selectors: "html"): NodeListOf; + querySelectorAll(selectors: "i"): NodeListOf; + querySelectorAll(selectors: "iframe"): NodeListOf; + querySelectorAll(selectors: "image"): NodeListOf; + querySelectorAll(selectors: "img"): NodeListOf; + querySelectorAll(selectors: "input"): NodeListOf; + querySelectorAll(selectors: "ins"): NodeListOf; + querySelectorAll(selectors: "isindex"): NodeListOf; + querySelectorAll(selectors: "kbd"): NodeListOf; + querySelectorAll(selectors: "keygen"): NodeListOf; + querySelectorAll(selectors: "label"): NodeListOf; + querySelectorAll(selectors: "legend"): NodeListOf; + querySelectorAll(selectors: "li"): NodeListOf; + querySelectorAll(selectors: "line"): NodeListOf; + querySelectorAll(selectors: "lineargradient"): NodeListOf; + querySelectorAll(selectors: "link"): NodeListOf; + querySelectorAll(selectors: "listing"): NodeListOf; + querySelectorAll(selectors: "map"): NodeListOf; + querySelectorAll(selectors: "mark"): NodeListOf; + querySelectorAll(selectors: "marker"): NodeListOf; + querySelectorAll(selectors: "marquee"): NodeListOf; + querySelectorAll(selectors: "mask"): NodeListOf; + querySelectorAll(selectors: "menu"): NodeListOf; + querySelectorAll(selectors: "meta"): NodeListOf; + querySelectorAll(selectors: "metadata"): NodeListOf; + querySelectorAll(selectors: "meter"): NodeListOf; + querySelectorAll(selectors: "nav"): NodeListOf; + querySelectorAll(selectors: "nextid"): NodeListOf; + querySelectorAll(selectors: "nobr"): NodeListOf; + querySelectorAll(selectors: "noframes"): NodeListOf; + querySelectorAll(selectors: "noscript"): NodeListOf; + querySelectorAll(selectors: "object"): NodeListOf; + querySelectorAll(selectors: "ol"): NodeListOf; + querySelectorAll(selectors: "optgroup"): NodeListOf; + querySelectorAll(selectors: "option"): NodeListOf; + querySelectorAll(selectors: "p"): NodeListOf; + querySelectorAll(selectors: "param"): NodeListOf; + querySelectorAll(selectors: "path"): NodeListOf; + querySelectorAll(selectors: "pattern"): NodeListOf; + querySelectorAll(selectors: "picture"): NodeListOf; + querySelectorAll(selectors: "plaintext"): NodeListOf; + querySelectorAll(selectors: "polygon"): NodeListOf; + querySelectorAll(selectors: "polyline"): NodeListOf; + querySelectorAll(selectors: "pre"): NodeListOf; + querySelectorAll(selectors: "progress"): NodeListOf; + querySelectorAll(selectors: "q"): NodeListOf; + querySelectorAll(selectors: "radialgradient"): NodeListOf; + querySelectorAll(selectors: "rect"): NodeListOf; + querySelectorAll(selectors: "rt"): NodeListOf; + querySelectorAll(selectors: "ruby"): NodeListOf; + querySelectorAll(selectors: "s"): NodeListOf; + querySelectorAll(selectors: "samp"): NodeListOf; + querySelectorAll(selectors: "script"): NodeListOf; + querySelectorAll(selectors: "section"): NodeListOf; + querySelectorAll(selectors: "select"): NodeListOf; + querySelectorAll(selectors: "small"): NodeListOf; + querySelectorAll(selectors: "source"): NodeListOf; + querySelectorAll(selectors: "span"): NodeListOf; + querySelectorAll(selectors: "stop"): NodeListOf; + querySelectorAll(selectors: "strike"): NodeListOf; + querySelectorAll(selectors: "strong"): NodeListOf; + querySelectorAll(selectors: "style"): NodeListOf; + querySelectorAll(selectors: "sub"): NodeListOf; + querySelectorAll(selectors: "sup"): NodeListOf; + querySelectorAll(selectors: "svg"): NodeListOf; + querySelectorAll(selectors: "switch"): NodeListOf; + querySelectorAll(selectors: "symbol"): NodeListOf; + querySelectorAll(selectors: "table"): NodeListOf; + querySelectorAll(selectors: "tbody"): NodeListOf; + querySelectorAll(selectors: "td"): NodeListOf; + querySelectorAll(selectors: "template"): NodeListOf; + querySelectorAll(selectors: "text"): NodeListOf; + querySelectorAll(selectors: "textpath"): NodeListOf; + querySelectorAll(selectors: "textarea"): NodeListOf; + querySelectorAll(selectors: "tfoot"): NodeListOf; + querySelectorAll(selectors: "th"): NodeListOf; + querySelectorAll(selectors: "thead"): NodeListOf; + querySelectorAll(selectors: "title"): NodeListOf; + querySelectorAll(selectors: "tr"): NodeListOf; + querySelectorAll(selectors: "track"): NodeListOf; + querySelectorAll(selectors: "tspan"): NodeListOf; + querySelectorAll(selectors: "tt"): NodeListOf; + querySelectorAll(selectors: "u"): NodeListOf; + querySelectorAll(selectors: "ul"): NodeListOf; + querySelectorAll(selectors: "use"): NodeListOf; + querySelectorAll(selectors: "var"): NodeListOf; + querySelectorAll(selectors: "video"): NodeListOf; + querySelectorAll(selectors: "view"): NodeListOf; + querySelectorAll(selectors: "wbr"): NodeListOf; + querySelectorAll(selectors: "x-ms-webview"): NodeListOf; + querySelectorAll(selectors: "xmp"): NodeListOf; querySelectorAll(selectors: string): NodeListOf; } @@ -13589,18 +13943,21 @@ interface WindowSessionStorage { interface WindowTimers extends Object, WindowTimersExtension { clearInterval(handle: number): void; clearTimeout(handle: number): void; + 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; } interface WindowTimersExtension { clearImmediate(handle: number): void; - setImmediate(expression: any, ...args: any[]): number; + setImmediate(handler: (...args: any[]) => void): number; + setImmediate(handler: any, ...args: any[]): number; } 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; @@ -13624,6 +13981,13 @@ interface StorageEventInit extends EventInit { storageArea?: Storage; } +interface Canvas2DContextAttributes { + alpha?: boolean; + willReadFrequently?: boolean; + storage?: boolean; + [attribute: string]: boolean | string | undefined; +} + interface NodeListOf extends NodeList { length: number; item(index: number): TNode; @@ -13673,6 +14037,177 @@ interface ClipboardEventInit extends EventInit { interface IDBArrayKey extends Array { } +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 { @@ -13746,7 +14281,7 @@ declare var msCredentials: MSCredentials; declare var name: string; declare var navigator: Navigator; declare var offscreenBuffering: string | boolean; -declare var onabort: (ev: Event) => any; +declare var onabort: (ev: UIEvent) => any; declare var onafterprint: (ev: Event) => any; declare var onbeforeprint: (ev: Event) => any; declare var onbeforeunload: (ev: BeforeUnloadEvent) => any; @@ -13896,10 +14431,13 @@ declare function dispatchEvent(evt: Event): boolean; declare function removeEventListener(type: string, listener?: EventListenerOrEventListenerObject, useCapture?: boolean): void; declare function clearInterval(handle: number): void; declare function clearTimeout(handle: number): void; +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 clearImmediate(handle: number): void; -declare function setImmediate(expression: any, ...args: any[]): number; +declare function setImmediate(handler: (...args: any[]) => void): number; +declare function setImmediate(handler: any, ...args: any[]): number; declare var sessionStorage: Storage; declare var localStorage: Storage; declare var console: Console; @@ -14042,4 +14580,6 @@ type MSOutboundPayload = MSVideoSendPayload | MSAudioSendPayload; type RTCIceGatherCandidate = RTCIceCandidate | RTCIceCandidateComplete; type RTCTransport = RTCDtlsTransport | RTCSrtpSdesTransport; type payloadtype = number; -type IDBValidKey = number | string | Date | IDBArrayKey; \ No newline at end of file +type IDBValidKey = number | string | Date | IDBArrayKey; +type BufferSource = ArrayBuffer | ArrayBufferView; +type MouseWheelEvent = WheelEvent; \ No newline at end of file diff --git a/src/lib/webworker.generated.d.ts b/src/lib/webworker.generated.d.ts index f5c77b8594d11..56c8cc84367a8 100644 --- a/src/lib/webworker.generated.d.ts +++ b/src/lib/webworker.generated.d.ts @@ -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 { } +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; \ No newline at end of file +type IDBValidKey = number | string | Date | IDBArrayKey; +type BufferSource = ArrayBuffer | ArrayBufferView; \ No newline at end of file diff --git a/src/server/client.ts b/src/server/client.ts index 864dac9fdaaa1..09cfa2ac739fc 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -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(CommandNames.NavBar, args); const response = this.processResponse(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 { diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 346b2e00a109a..9c0662e5534a5 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -359,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; compilerOptions?: ts.CompilerOptions; } @@ -379,6 +384,7 @@ namespace ts.server { projectFilename: string; projectFileWatcher: FileWatcher; directoryWatcher: FileWatcher; + directoriesWatchedForWildcards: Map; // Used to keep track of what directories are watched for this project directoriesWatchedForTsconfig: string[] = []; program: ts.Program; @@ -848,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 { @@ -1340,7 +1348,8 @@ namespace ts.server { else { const projectOptions: ProjectOptions = { files: parsedCommandLine.fileNames, - compilerOptions: parsedCommandLine.options + wildcardDirectories: parsedCommandLine.wildcardDirectories, + compilerOptions: parsedCommandLine.options, }; return { succeeded: true, projectOptions }; } @@ -1397,12 +1406,30 @@ 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; + }, >{}); + return { success: true, project: project, errors }; } } @@ -1452,7 +1479,7 @@ namespace ts.server { } // 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 + // 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)); diff --git a/src/server/session.ts b/src/server/session.ts index 65540082f6068..aafc02a2b0b6d 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -863,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; } @@ -875,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 })); } @@ -896,7 +896,7 @@ 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[] { diff --git a/src/services/jsTyping.ts b/src/services/jsTyping.ts index 943693bf52e4d..3b013a4a924ac 100644 --- a/src/services/jsTyping.ts +++ b/src/services/jsTyping.ts @@ -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") { diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index 920faf58e2454..60fe70cdbde2b 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -2,860 +2,660 @@ /* @internal */ namespace ts.NavigationBar { - export function getNavigationBarItems(sourceFile: SourceFile, compilerOptions: CompilerOptions): ts.NavigationBarItem[] { - // TODO: Handle JS files differently in 'navbar' calls for now, but ideally we should unify - // the 'navbar' and 'navto' logic for TypeScript and JavaScript. - if (isSourceFileJavaScript(sourceFile)) { - return getJsNavigationBarItems(sourceFile, compilerOptions); - } - - return getItemsWorker(getTopLevelNodes(sourceFile), createTopLevelItem); - - function getIndent(node: Node): number { - let indent = 1; // Global node is the only one with indent 0. - - let current = node.parent; - while (current) { - switch (current.kind) { - case SyntaxKind.ModuleDeclaration: - // If we have a module declared as A.B.C, it is more "intuitive" - // to say it only has a single layer of depth - do { - current = current.parent; - } - while (current.kind === SyntaxKind.ModuleDeclaration); - - // fall through - case SyntaxKind.ClassDeclaration: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.FunctionDeclaration: - indent++; - } - - current = current.parent; - } + /** + * Represents a navigation bar item and its children. + * The returned NavigationBarItem is more complicated and doesn't include 'parent', so we use these to do work before converting. + */ + interface NavigationBarNode { + node: Node; + additionalNodes: Node[] | undefined; + parent: NavigationBarNode | undefined; // Present for all but root node + children: NavigationBarNode[] | undefined; + indent: number; // # of parents + } - return indent; - } + export function getNavigationBarItems(sourceFile: SourceFile): NavigationBarItem[] { + curSourceFile = sourceFile; + const result = map(topLevelItems(rootNavigationBarNode(sourceFile)), convertToTopLevelItem); + curSourceFile = undefined; + return result; + } - function getChildNodes(nodes: Node[]): Node[] { - const childNodes: Node[] = []; + // Keep sourceFile handy so we don't have to search for it every time we need to call `getText`. + let curSourceFile: SourceFile; + function nodeText(node: Node): string { + return node.getText(curSourceFile); + } - function visit(node: Node) { - switch (node.kind) { - case SyntaxKind.VariableStatement: - forEach((node).declarationList.declarations, visit); - break; - case SyntaxKind.ObjectBindingPattern: - case SyntaxKind.ArrayBindingPattern: - forEach((node).elements, visit); - break; + function navigationBarNodeKind(n: NavigationBarNode): SyntaxKind { + return n.node.kind; + } - case SyntaxKind.ExportDeclaration: - // Handle named exports case e.g.: - // export {a, b as B} from "mod"; - if ((node).exportClause) { - forEach((node).exportClause.elements, visit); - } - break; - - case SyntaxKind.ImportDeclaration: - let importClause = (node).importClause; - if (importClause) { - // Handle default import case e.g.: - // import d from "mod"; - if (importClause.name) { - childNodes.push(importClause); - } + function pushChild(parent: NavigationBarNode, child: NavigationBarNode): void { + if (parent.children) { + parent.children.push(child); + } + else { + parent.children = [child]; + } + } - // Handle named bindings in imports e.g.: - // import * as NS from "mod"; - // import {a, b as B} from "mod"; - if (importClause.namedBindings) { - if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { - childNodes.push(importClause.namedBindings); - } - else { - forEach((importClause.namedBindings).elements, visit); - } - } - } - break; + /* + For performance, we keep navigation bar parents on a stack rather than passing them through each recursion. + `parent` is the current parent and is *not* stored in parentsStack. + `startNode` sets a new parent and `endNode` returns to the previous parent. + */ + const parentsStack: NavigationBarNode[] = []; + let parent: NavigationBarNode; + + function rootNavigationBarNode(sourceFile: SourceFile): NavigationBarNode { + Debug.assert(!parentsStack.length); + const root: NavigationBarNode = { node: sourceFile, additionalNodes: undefined, parent: undefined, children: undefined, indent: 0 }; + parent = root; + for (const statement of sourceFile.statements) { + addChildrenRecursively(statement); + } + endNode(); + Debug.assert(!parent && !parentsStack.length); + return root; + } - case SyntaxKind.BindingElement: - case SyntaxKind.VariableDeclaration: - if (isBindingPattern((node).name)) { - visit((node).name); - break; - } - // Fall through - case SyntaxKind.ClassDeclaration: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.ModuleDeclaration: - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.ImportEqualsDeclaration: - case SyntaxKind.ImportSpecifier: - case SyntaxKind.ExportSpecifier: - case SyntaxKind.TypeAliasDeclaration: - childNodes.push(node); - break; - } - } + function addLeafNode(node: Node): void { + pushChild(parent, emptyNavigationBarNode(node)); + } - // for (let i = 0, n = nodes.length; i < n; i++) { - // let node = nodes[i]; + function emptyNavigationBarNode(node: Node): NavigationBarNode { + return { + node, + additionalNodes: undefined, + parent, + children: undefined, + indent: parent.indent + 1 + }; + } - // if (node.kind === SyntaxKind.ClassDeclaration || - // node.kind === SyntaxKind.EnumDeclaration || - // node.kind === SyntaxKind.InterfaceDeclaration || - // node.kind === SyntaxKind.ModuleDeclaration || - // node.kind === SyntaxKind.FunctionDeclaration) { + /** + * Add a new level of NavigationBarNodes. + * This pushes to the stack, so you must call `endNode` when you are done adding to this node. + */ + function startNode(node: Node): void { + const navNode: NavigationBarNode = emptyNavigationBarNode(node); + pushChild(parent, navNode); + + // Save the old parent + parentsStack.push(parent); + parent = navNode; + } - // childNodes.push(node); - // } - // else if (node.kind === SyntaxKind.VariableStatement) { - // childNodes.push.apply(childNodes, (node).declarations); - // } - // } - forEach(nodes, visit); - return sortNodes(childNodes); + /** Call after calling `startNode` and adding children to it. */ + function endNode(): void { + if (parent.children) { + mergeChildren(parent.children); + sortChildren(parent.children); } + parent = parentsStack.pop(); + } - function getTopLevelNodes(node: SourceFile): Node[] { - const topLevelNodes: Node[] = []; - topLevelNodes.push(node); - - addTopLevelNodes(node.statements, topLevelNodes); + function addNodeWithRecursiveChild(node: Node, child: Node): void { + startNode(node); + addChildrenRecursively(child); + endNode(); + } - return topLevelNodes; + /** Look for navigation bar items in node's subtree, adding them to the current `parent`. */ + function addChildrenRecursively(node: Node): void { + if (!node || isToken(node)) { + return; } - function sortNodes(nodes: Node[]): Node[] { - return nodes.slice(0).sort((n1: Declaration, n2: Declaration) => { - if (n1.name && n2.name) { - return localeCompareFix(getPropertyNameForPropertyNameNode(n1.name), getPropertyNameForPropertyNameNode(n2.name)); - } - else if (n1.name) { - return 1; - } - else if (n2.name) { - return -1; + switch (node.kind) { + case SyntaxKind.Constructor: + // Get parameter properties, and treat them as being on the *same* level as the constructor, not under it. + const ctr = node; + addNodeWithRecursiveChild(ctr, ctr.body); + + // Parameter properties are children of the class, not the constructor. + for (const param of ctr.parameters) { + if (isParameterPropertyDeclaration(param)) { + addLeafNode(param); + } } - else { - return n1.kind - n2.kind; + break; + + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.MethodSignature: + if (!hasDynamicName((node))) { + addNodeWithRecursiveChild(node, (node).body); } - }); - - // node 0.10 treats "a" as greater than "B". - // For consistency, sort alphabetically, falling back to which is lower-case. - function localeCompareFix(a: string, b: string) { - const cmp = a.toLowerCase().localeCompare(b.toLowerCase()); - if (cmp !== 0) - return cmp; - // Return the *opposite* of the `<` operator, which works the same in node 0.10 and 6.0. - return a < b ? 1 : a > b ? -1 : 0; - } - } - - function addTopLevelNodes(nodes: Node[], topLevelNodes: Node[]): void { - nodes = sortNodes(nodes); - - for (const node of nodes) { - switch (node.kind) { - case SyntaxKind.ClassDeclaration: - topLevelNodes.push(node); - for (const member of (node).members) { - if (member.kind === SyntaxKind.MethodDeclaration || member.kind === SyntaxKind.Constructor) { - type FunctionLikeMember = MethodDeclaration | ConstructorDeclaration; - if ((member).body) { - // We do not include methods that does not have child functions in it, because of duplications. - if (hasNamedFunctionDeclarations(((member).body).statements)) { - topLevelNodes.push(member); - } - addTopLevelNodes(((member).body).statements, topLevelNodes); - } - } - } - break; - case SyntaxKind.EnumDeclaration: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.TypeAliasDeclaration: - topLevelNodes.push(node); - break; - - case SyntaxKind.ModuleDeclaration: - let moduleDeclaration = node; - topLevelNodes.push(node); - const inner = getInnermostModule(moduleDeclaration); - if (inner.body) { - addTopLevelNodes((inner.body).statements, topLevelNodes); - } - break; + break; - case SyntaxKind.FunctionDeclaration: - let functionDeclaration = node; - if (isTopLevelFunctionDeclaration(functionDeclaration)) { - topLevelNodes.push(node); - addTopLevelNodes((functionDeclaration.body).statements, topLevelNodes); - } - break; + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + if (!hasDynamicName((node))) { + addLeafNode(node); } - } - } - - function hasNamedFunctionDeclarations(nodes: NodeArray): boolean { - for (const s of nodes) { - if (s.kind === SyntaxKind.FunctionDeclaration && !isEmpty((s).name.text)) { - return true; + break; + + case SyntaxKind.ImportClause: + let importClause = node; + // Handle default import case e.g.: + // import d from "mod"; + if (importClause.name) { + addLeafNode(importClause); } - } - return false; - } - function isTopLevelFunctionDeclaration(functionDeclaration: FunctionLikeDeclaration): boolean { - if (functionDeclaration.kind === SyntaxKind.FunctionDeclaration) { - // A function declaration is 'top level' if it contains any function declarations - // within it. - if (functionDeclaration.body && functionDeclaration.body.kind === SyntaxKind.Block) { - // Proper function declarations can only have identifier names - if (hasNamedFunctionDeclarations((functionDeclaration.body).statements)) { - return true; + // Handle named bindings in imports e.g.: + // import * as NS from "mod"; + // import {a, b as B} from "mod"; + const {namedBindings} = importClause; + if (namedBindings) { + if (namedBindings.kind === SyntaxKind.NamespaceImport) { + addLeafNode(namedBindings); } - - // Or if it is not parented by another function. I.e all functions at module scope are 'top level'. - if (!isFunctionBlock(functionDeclaration.parent)) { - return true; - } - - // Or if it is nested inside class methods and constructors. else { - // We have made sure that a grand parent node exists with 'isFunctionBlock()' above. - const grandParentKind = functionDeclaration.parent.parent.kind; - if (grandParentKind === SyntaxKind.MethodDeclaration || - grandParentKind === SyntaxKind.Constructor) { - - return true; + for (const element of (namedBindings).elements) { + addLeafNode(element); } } } - } - - return false; - } - - function getItemsWorker(nodes: Node[], createItem: (n: Node) => ts.NavigationBarItem): ts.NavigationBarItem[] { - const items: ts.NavigationBarItem[] = []; - - const keyToItem: Map = {}; - - for (const child of nodes) { - const item = createItem(child); - if (item !== undefined) { - if (item.text.length > 0) { - const key = item.text + "-" + item.kind + "-" + item.indent; - - const itemWithSameName = keyToItem[key]; - if (itemWithSameName) { - // We had an item with the same name. Merge these items together. - merge(itemWithSameName, item); - } - else { - keyToItem[key] = item; - items.push(item); - } - } + break; + + case SyntaxKind.BindingElement: + case SyntaxKind.VariableDeclaration: + const decl = node; + const name = decl.name; + if (isBindingPattern(name)) { + addChildrenRecursively(name); } - } - - return items; - } - - function merge(target: ts.NavigationBarItem, source: ts.NavigationBarItem) { - // First, add any spans in the source to the target. - addRange(target.spans, source.spans); - - if (source.childItems) { - if (!target.childItems) { - target.childItems = []; + else if (decl.initializer && isFunctionOrClassExpression(decl.initializer)) { + // For `const x = function() {}`, just use the function node, not the const. + addChildrenRecursively(decl.initializer); } - - // Next, recursively merge or add any children in the source as appropriate. - outer: - for (const sourceChild of source.childItems) { - for (const targetChild of target.childItems) { - if (targetChild.text === sourceChild.text && targetChild.kind === sourceChild.kind) { - // Found a match. merge them. - merge(targetChild, sourceChild); - continue outer; - } - } - - // Didn't find a match, just add this child to the list. - target.childItems.push(sourceChild); + else { + addNodeWithRecursiveChild(decl, decl.initializer); } - } - } - - function createChildItem(node: Node): ts.NavigationBarItem { - switch (node.kind) { - case SyntaxKind.Parameter: - if (isBindingPattern((node).name)) { - break; - } - if (!hasModifiers(node)) { - return undefined; + break; + + case SyntaxKind.ArrowFunction: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + addNodeWithRecursiveChild(node, (node).body); + break; + + case SyntaxKind.EnumDeclaration: + startNode(node); + for (const member of (node).members) { + if (!isComputedProperty(member)) { + addLeafNode(member); } - return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.memberVariableElement); - - case SyntaxKind.MethodDeclaration: - case SyntaxKind.MethodSignature: - return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.memberFunctionElement); - - case SyntaxKind.GetAccessor: - return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.memberGetAccessorElement); - - case SyntaxKind.SetAccessor: - return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.memberSetAccessorElement); - - case SyntaxKind.IndexSignature: - return createItem(node, "[]", ts.ScriptElementKind.indexSignatureElement); - - case SyntaxKind.EnumDeclaration: - return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.enumElement); - - case SyntaxKind.EnumMember: - return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.memberVariableElement); - - case SyntaxKind.ModuleDeclaration: - return createItem(node, getModuleName(node), ts.ScriptElementKind.moduleElement); - - case SyntaxKind.InterfaceDeclaration: - return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.interfaceElement); - - case SyntaxKind.TypeAliasDeclaration: - return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.typeElement); - - case SyntaxKind.CallSignature: - return createItem(node, "()", ts.ScriptElementKind.callSignatureElement); - - case SyntaxKind.ConstructSignature: - return createItem(node, "new()", ts.ScriptElementKind.constructSignatureElement); - - case SyntaxKind.PropertyDeclaration: - case SyntaxKind.PropertySignature: - return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.memberVariableElement); - - case SyntaxKind.ClassDeclaration: - return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.classElement); - - case SyntaxKind.FunctionDeclaration: - return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.functionElement); - - case SyntaxKind.VariableDeclaration: - case SyntaxKind.BindingElement: - let variableDeclarationNode: Node; - let name: Node; - - if (node.kind === SyntaxKind.BindingElement) { - name = (node).name; - variableDeclarationNode = node; - // binding elements are added only for variable declarations - // bubble up to the containing variable declaration - while (variableDeclarationNode && variableDeclarationNode.kind !== SyntaxKind.VariableDeclaration) { - variableDeclarationNode = variableDeclarationNode.parent; + } + endNode(); + break; + + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + case SyntaxKind.InterfaceDeclaration: + startNode(node); + for (const member of (node).members) { + addChildrenRecursively(member); + } + endNode(); + break; + + case SyntaxKind.ModuleDeclaration: + addNodeWithRecursiveChild(node, getInteriorModule(node).body); + break; + + case SyntaxKind.ExportSpecifier: + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.IndexSignature: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.TypeAliasDeclaration: + addLeafNode(node); + break; + + default: + if (node.jsDocComments) { + for (const jsDocComment of node.jsDocComments) { + for (const tag of jsDocComment.tags) { + if (tag.kind === SyntaxKind.JSDocTypedefTag) { + addLeafNode(tag); + } } - Debug.assert(variableDeclarationNode !== undefined); - } - else { - Debug.assert(!isBindingPattern((node).name)); - variableDeclarationNode = node; - name = (node).name; } + } - if (isConst(variableDeclarationNode)) { - return createItem(node, getTextOfNode(name), ts.ScriptElementKind.constElement); - } - else if (isLet(variableDeclarationNode)) { - return createItem(node, getTextOfNode(name), ts.ScriptElementKind.letElement); - } - else { - return createItem(node, getTextOfNode(name), ts.ScriptElementKind.variableElement); - } - - case SyntaxKind.Constructor: - return createItem(node, "constructor", ts.ScriptElementKind.constructorImplementationElement); - - case SyntaxKind.ExportSpecifier: - case SyntaxKind.ImportSpecifier: - case SyntaxKind.ImportEqualsDeclaration: - case SyntaxKind.ImportClause: - case SyntaxKind.NamespaceImport: - return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.alias); - } - - return undefined; - - function createItem(node: Node, name: string, scriptElementKind: string): NavigationBarItem { - return getNavigationBarItem(name, scriptElementKind, getNodeModifiers(node), [getNodeSpan(node)]); - } - } - - function isEmpty(text: string) { - return !text || text.trim() === ""; + forEachChild(node, addChildrenRecursively); } + } - function getNavigationBarItem(text: string, kind: string, kindModifiers: string, spans: TextSpan[], childItems: NavigationBarItem[] = [], indent = 0): NavigationBarItem { - if (isEmpty(text)) { - return undefined; - } - - return { - text, - kind, - kindModifiers, - spans, - childItems, - indent, - bolded: false, - grayed: false - }; - } - - function createTopLevelItem(node: Node): ts.NavigationBarItem { - switch (node.kind) { - case SyntaxKind.SourceFile: - return createSourceFileItem(node); - - case SyntaxKind.ClassDeclaration: - return createClassItem(node); - - case SyntaxKind.MethodDeclaration: - case SyntaxKind.Constructor: - return createMemberFunctionLikeItem(node); - - case SyntaxKind.EnumDeclaration: - return createEnumItem(node); - - case SyntaxKind.InterfaceDeclaration: - return createInterfaceItem(node); - - case SyntaxKind.ModuleDeclaration: - return createModuleItem(node); - - case SyntaxKind.FunctionDeclaration: - return createFunctionItem(node); - - case SyntaxKind.TypeAliasDeclaration: - return createTypeAliasItem(node); + /** Merge declarations of the same kind. */ + function mergeChildren(children: NavigationBarNode[]): void { + const nameToItems: Map = {}; + filterMutate(children, child => { + const decl = child.node; + const name = decl.name && nodeText(decl.name); + if (!name) { + // Anonymous items are never merged. + return true; } - return undefined; - - function createModuleItem(node: ModuleDeclaration): NavigationBarItem { - const moduleName = getModuleName(node); - - const body = getInnermostModule(node).body; - const childItems = body ? getItemsWorker(getChildNodes(body.statements), createChildItem) : []; - - return getNavigationBarItem(moduleName, - ts.ScriptElementKind.moduleElement, - getNodeModifiers(node), - [getNodeSpan(node)], - childItems, - getIndent(node)); + const itemsWithSameName = getProperty(nameToItems, name); + if (!itemsWithSameName) { + nameToItems[name] = child; + return true; } - function createFunctionItem(node: FunctionDeclaration): ts.NavigationBarItem { - if (node.body && node.body.kind === SyntaxKind.Block) { - const childItems = getItemsWorker(sortNodes((node.body).statements), createChildItem); - - return getNavigationBarItem(!node.name ? "default" : node.name.text, - ts.ScriptElementKind.functionElement, - getNodeModifiers(node), - [getNodeSpan(node)], - childItems, - getIndent(node)); + if (itemsWithSameName instanceof Array) { + for (const itemWithSameName of itemsWithSameName) { + if (tryMerge(itemWithSameName, child)) { + return false; + } } - - return undefined; + itemsWithSameName.push(child); + return true; } - - function createTypeAliasItem(node: TypeAliasDeclaration): ts.NavigationBarItem { - return getNavigationBarItem(node.name.text, - ts.ScriptElementKind.typeElement, - getNodeModifiers(node), - [getNodeSpan(node)], - [], - getIndent(node)); - } - - function createMemberFunctionLikeItem(node: MethodDeclaration | ConstructorDeclaration): ts.NavigationBarItem { - if (node.body && node.body.kind === SyntaxKind.Block) { - const childItems = getItemsWorker(sortNodes((node.body).statements), createChildItem); - let scriptElementKind: string; - let memberFunctionName: string; - if (node.kind === SyntaxKind.MethodDeclaration) { - memberFunctionName = getPropertyNameForPropertyNameNode(node.name); - scriptElementKind = ts.ScriptElementKind.memberFunctionElement; - } - else { - memberFunctionName = "constructor"; - scriptElementKind = ts.ScriptElementKind.constructorImplementationElement; - } - - return getNavigationBarItem(memberFunctionName, - scriptElementKind, - getNodeModifiers(node), - [getNodeSpan(node)], - childItems, - getIndent(node)); + else { + const itemWithSameName = itemsWithSameName; + if (tryMerge(itemWithSameName, child)) { + return false; } - - return undefined; + nameToItems[name] = [itemWithSameName, child]; + return true; } - function createSourceFileItem(node: SourceFile): ts.NavigationBarItem { - const childItems = getItemsWorker(getChildNodes(node.statements), createChildItem); - - const rootName = isExternalModule(node) - ? "\"" + escapeString(getBaseFileName(removeFileExtension(normalizePath(node.fileName)))) + "\"" - : ""; - - return getNavigationBarItem(rootName, - ts.ScriptElementKind.moduleElement, - ts.ScriptElementKindModifier.none, - [getNodeSpan(node)], - childItems); + function tryMerge(a: NavigationBarNode, b: NavigationBarNode): boolean { + if (shouldReallyMerge(a.node, b.node)) { + merge(a, b); + return true; + } + return false; } + }); - function createClassItem(node: ClassDeclaration): ts.NavigationBarItem { - let childItems: NavigationBarItem[]; + /** a and b have the same name, but they may not be mergeable. */ + function shouldReallyMerge(a: Node, b: Node): boolean { + return a.kind === b.kind && (a.kind !== SyntaxKind.ModuleDeclaration || areSameModule(a, b)); - if (node.members) { - const constructor = forEach(node.members, member => { - return member.kind === SyntaxKind.Constructor && member; - }); - - // Add the constructor parameters in as children of the class (for property parameters). - // Note that *all non-binding pattern named* parameters will be added to the nodes array, but parameters that - // are not properties will be filtered out later by createChildItem. - const nodes: Node[] = removeDynamicallyNamedProperties(node); - if (constructor) { - addRange(nodes, filter(constructor.parameters, p => !isBindingPattern(p.name))); - } - - childItems = getItemsWorker(sortNodes(nodes), createChildItem); + // We use 1 NavNode to represent 'A.B.C', but there are multiple source nodes. + // Only merge module nodes that have the same chain. Don't merge 'A.B.C' with 'A'! + function areSameModule(a: ModuleDeclaration, b: ModuleDeclaration): boolean { + if (a.body.kind !== b.body.kind) { + return false; } - - const nodeName = !node.name ? "default" : node.name.text; - - return getNavigationBarItem( - nodeName, - ts.ScriptElementKind.classElement, - getNodeModifiers(node), - [getNodeSpan(node)], - childItems, - getIndent(node)); + if (a.body.kind !== SyntaxKind.ModuleDeclaration) { + return true; + } + return areSameModule(a.body, b.body); } + } - function createEnumItem(node: EnumDeclaration): ts.NavigationBarItem { - const childItems = getItemsWorker(sortNodes(removeComputedProperties(node)), createChildItem); - return getNavigationBarItem( - node.name.text, - ts.ScriptElementKind.enumElement, - getNodeModifiers(node), - [getNodeSpan(node)], - childItems, - getIndent(node)); + /** Merge source into target. Source should be thrown away after this is called. */ + function merge(target: NavigationBarNode, source: NavigationBarNode): void { + target.additionalNodes = target.additionalNodes || []; + target.additionalNodes.push(source.node); + if (source.additionalNodes) { + target.additionalNodes.push(...source.additionalNodes); } - function createInterfaceItem(node: InterfaceDeclaration): ts.NavigationBarItem { - const childItems = getItemsWorker(sortNodes(removeDynamicallyNamedProperties(node)), createChildItem); - return getNavigationBarItem( - node.name.text, - ts.ScriptElementKind.interfaceElement, - getNodeModifiers(node), - [getNodeSpan(node)], - childItems, - getIndent(node)); + target.children = concatenate(target.children, source.children); + if (target.children) { + mergeChildren(target.children); + sortChildren(target.children); } } + } - function getModuleName(moduleDeclaration: ModuleDeclaration): string { - // We want to maintain quotation marks. - if (isAmbientModule(moduleDeclaration)) { - return getTextOfNode(moduleDeclaration.name); - } - - // Otherwise, we need to aggregate each identifier to build up the qualified name. - const result: string[] = []; - - result.push(moduleDeclaration.name.text); + /** Recursively ensure that each NavNode's children are in sorted order. */ + function sortChildren(children: NavigationBarNode[]): void { + children.sort(compareChildren); + } - while (moduleDeclaration.body && moduleDeclaration.body.kind === SyntaxKind.ModuleDeclaration) { - moduleDeclaration = moduleDeclaration.body; + function compareChildren(child1: NavigationBarNode, child2: NavigationBarNode): number { + const name1 = tryGetName(child1.node), name2 = tryGetName(child2.node); + if (name1 && name2) { + const cmp = localeCompareFix(name1, name2); + return cmp !== 0 ? cmp : navigationBarNodeKind(child1) - navigationBarNodeKind(child2); + } + else { + return name1 ? 1 : name2 ? -1 : navigationBarNodeKind(child1) - navigationBarNodeKind(child2); + } + } - result.push(moduleDeclaration.name.text); + // More efficient to create a collator once and use its `compare` than to call `a.localeCompare(b)` many times. + const collator: { compare(a: string, b: string): number } = typeof Intl === "undefined" ? undefined : new Intl.Collator(); + // Intl is missing in Safari, and node 0.10 treats "a" as greater than "B". + const localeCompareIsCorrect = collator && collator.compare("a", "B") < 0; + const localeCompareFix: (a: string, b: string) => number = localeCompareIsCorrect ? collator.compare : function(a, b) { + // This isn't perfect, but it passes all of our tests. + for (let i = 0; i < Math.min(a.length, b.length); i++) { + const chA = a.charAt(i), chB = b.charAt(i); + if (chA === "\"" && chB === "'") { + return 1; + } + if (chA === "'" && chB === "\"") { + return -1; + } + const cmp = chA.toLocaleLowerCase().localeCompare(chB.toLocaleLowerCase()); + if (cmp !== 0) { + return cmp; } - - return result.join("."); } - - function removeComputedProperties(node: EnumDeclaration): Declaration[] { - return filter(node.members, member => member.name === undefined || member.name.kind !== SyntaxKind.ComputedPropertyName); + return a.length - b.length; + }; + + /** + * This differs from getItemName because this is just used for sorting. + * We only sort nodes by name that have a more-or-less "direct" name, as opposed to `new()` and the like. + * So `new()` can still come before an `aardvark` method. + */ + function tryGetName(node: Node): string | undefined { + if (node.kind === SyntaxKind.ModuleDeclaration) { + return getModuleName(node); } - /** - * Like removeComputedProperties, but retains the properties with well known symbol names - */ - function removeDynamicallyNamedProperties(node: ClassDeclaration | InterfaceDeclaration): Declaration[] { - return filter(node.members, member => !hasDynamicName(member)); + const decl = node; + if (decl.name) { + return getPropertyNameForPropertyNameNode(decl.name); } + switch (node.kind) { + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.ClassExpression: + return getFunctionOrClassName(node); + case SyntaxKind.JSDocTypedefTag: + return getJSDocTypedefTagName(node); + default: + return undefined; + } + } - function getInnermostModule(node: ModuleDeclaration): ModuleDeclaration { - while (node.body && node.body.kind === SyntaxKind.ModuleDeclaration) { - node = node.body; - } - - return node; + function getItemName(node: Node): string { + if (node.kind === SyntaxKind.ModuleDeclaration) { + return getModuleName(node); } - function getNodeSpan(node: Node) { - return node.kind === SyntaxKind.SourceFile - ? createTextSpanFromBounds(node.getFullStart(), node.getEnd()) - : createTextSpanFromBounds(node.getStart(), node.getEnd()); + const name = (node).name; + if (name) { + const text = nodeText(name); + if (text.length > 0) { + return text; + } } - function getTextOfNode(node: Node): string { - return getTextOfNodeFromSourceText(sourceFile.text, node); + switch (node.kind) { + case SyntaxKind.SourceFile: + const sourceFile = node; + return isExternalModule(sourceFile) + ? `"${escapeString(getBaseFileName(removeFileExtension(normalizePath(sourceFile.fileName))))}"` + : ""; + case SyntaxKind.ArrowFunction: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + if (getModifierFlags(node) & ModifierFlags.Default) { + return "default"; + } + return getFunctionOrClassName(node); + case SyntaxKind.Constructor: + return "constructor"; + case SyntaxKind.ConstructSignature: + return "new()"; + case SyntaxKind.CallSignature: + return "()"; + case SyntaxKind.IndexSignature: + return "[]"; + case SyntaxKind.JSDocTypedefTag: + return getJSDocTypedefTagName(node); + default: + Debug.fail(); + return ""; } } - export function getJsNavigationBarItems(sourceFile: SourceFile, compilerOptions: CompilerOptions): NavigationBarItem[] { - const anonFnText = ""; - const anonClassText = ""; - let indent = 0; - - const rootName = isExternalModule(sourceFile) ? - "\"" + escapeString(getBaseFileName(removeFileExtension(normalizePath(sourceFile.fileName)))) + "\"" - : ""; - - const sourceFileItem = getNavBarItem(rootName, ScriptElementKind.moduleElement, [getNodeSpan(sourceFile)]); - let topItem = sourceFileItem; - - // Walk the whole file, because we want to also find function expressions - which may be in variable initializer, - // call arguments, expressions, etc... - forEachChild(sourceFile, visitNode); - - function visitNode(node: Node) { - const newItem = createNavBarItem(node); - - if (newItem) { - topItem.childItems.push(newItem); - } - - if (node.jsDocComments && node.jsDocComments.length > 0) { - for (const jsDocComment of node.jsDocComments) { - visitNode(jsDocComment); + function getJSDocTypedefTagName(node: JSDocTypedefTag): string { + if (node.name) { + return node.name.text; + } + else { + const parentNode = node.parent && node.parent.parent; + if (parentNode && parentNode.kind === SyntaxKind.VariableStatement) { + if ((parentNode).declarationList.declarations.length > 0) { + const nameIdentifier = (parentNode).declarationList.declarations[0].name; + if (nameIdentifier.kind === SyntaxKind.Identifier) { + return (nameIdentifier).text; + } } } + return ""; + } + } - // Add a level if traversing into a container - if (newItem && (isFunctionLike(node) || isClassLike(node))) { - const lastTop = topItem; - indent++; - topItem = newItem; - forEachChild(node, visitNode); - topItem = lastTop; - indent--; - - // If the last item added was an anonymous function expression, and it had no children, discard it. - if (newItem && newItem.text === anonFnText && newItem.childItems.length === 0) { - topItem.childItems.pop(); + /** Flattens the NavNode tree to a list, keeping only the top-level items. */ + function topLevelItems(root: NavigationBarNode): NavigationBarNode[] { + const topLevel: NavigationBarNode[] = []; + function recur(item: NavigationBarNode) { + if (isTopLevel(item)) { + topLevel.push(item); + if (item.children) { + for (const child of item.children) { + recur(child); + } } } - else { - forEachChild(node, visitNode); - } } + recur(root); + return topLevel; - function createNavBarItem(node: Node): NavigationBarItem { - switch (node.kind) { - case SyntaxKind.VariableDeclaration: - // Only add to the navbar if at the top-level of the file - // Note: "const" and "let" are also SyntaxKind.VariableDeclarations - if (node.parent/*VariableDeclarationList*/.parent/*VariableStatement*/ - .parent/*SourceFile*/.kind !== SyntaxKind.SourceFile) { - return undefined; - } - // If it is initialized with a function expression, handle it when we reach the function expression node - const varDecl = node as VariableDeclaration; - if (varDecl.initializer && (varDecl.initializer.kind === SyntaxKind.FunctionExpression || - varDecl.initializer.kind === SyntaxKind.ArrowFunction || - varDecl.initializer.kind === SyntaxKind.ClassExpression)) { - return undefined; - } - // Fall through - case SyntaxKind.FunctionDeclaration: + function isTopLevel(item: NavigationBarNode): boolean { + switch (navigationBarNodeKind(item)) { case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.SourceFile: + case SyntaxKind.TypeAliasDeclaration: + case SyntaxKind.JSDocTypedefTag: + return true; + case SyntaxKind.Constructor: + case SyntaxKind.MethodDeclaration: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - // "export default function().." looks just like a regular function/class declaration, except with the 'default' flag - const name = hasModifier(node, ModifierFlags.Default) && !(node as (Declaration)).name ? "default" : - node.kind === SyntaxKind.Constructor ? "constructor" : - declarationNameToString((node as (Declaration)).name); - return getNavBarItem(name, getScriptKindForElementKind(node.kind), [getNodeSpan(node)]); - case SyntaxKind.FunctionExpression: + return hasSomeImportantChild(item); + case SyntaxKind.ArrowFunction: - case SyntaxKind.ClassExpression: - return getDefineModuleItem(node) || getFunctionOrClassExpressionItem(node); - case SyntaxKind.MethodDeclaration: - const methodDecl = node as MethodDeclaration; - return getNavBarItem(declarationNameToString(methodDecl.name), - ScriptElementKind.memberFunctionElement, - [getNodeSpan(node)]); - case SyntaxKind.ExportAssignment: - // e.g. "export default " - return getNavBarItem("default", ScriptElementKind.variableElement, [getNodeSpan(node)]); - case SyntaxKind.ImportClause: // e.g. 'def' in: import def from 'mod' (in ImportDeclaration) - if (!(node as ImportClause).name) { - // No default import (this node is still a parent of named & namespace imports, which are handled below) - return undefined; - } - // fall through - case SyntaxKind.ImportSpecifier: // e.g. 'id' in: import {id} from 'mod' (in NamedImports, in ImportClause) - case SyntaxKind.NamespaceImport: // e.g. '* as ns' in: import * as ns from 'mod' (in ImportClause) - case SyntaxKind.ExportSpecifier: // e.g. 'a' or 'b' in: export {a, foo as b} from 'mod' - // Export specifiers are only interesting if they are reexports from another module, or renamed, else they are already globals - if (node.kind === SyntaxKind.ExportSpecifier) { - if (!(node.parent.parent as ExportDeclaration).moduleSpecifier && !(node as ExportSpecifier).propertyName) { - return undefined; - } - } - const decl = node as (ImportSpecifier | ImportClause | NamespaceImport | ExportSpecifier); - if (!decl.name) { - return undefined; - } - const declName = declarationNameToString(decl.name); - return getNavBarItem(declName, ScriptElementKind.constElement, [getNodeSpan(node)]); - case SyntaxKind.JSDocTypedefTag: - if ((node).name) { - return getNavBarItem( - (node).name.text, - ScriptElementKind.typeElement, - [getNodeSpan(node)]); - } - else { - const parentNode = node.parent && node.parent.parent; - if (parentNode && parentNode.kind === SyntaxKind.VariableStatement) { - if ((parentNode).declarationList.declarations.length > 0) { - const nameIdentifier = (parentNode).declarationList.declarations[0].name; - if (nameIdentifier.kind === SyntaxKind.Identifier) { - return getNavBarItem( - (nameIdentifier).text, - ScriptElementKind.typeElement, - [getNodeSpan(node)]); - } - } - } - } + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + return isTopLevelFunctionDeclaration(item); + default: - return undefined; + return false; + } + function isTopLevelFunctionDeclaration(item: NavigationBarNode): boolean { + if (!(item.node).body) { + return false; + } + + switch (navigationBarNodeKind(item.parent)) { + case SyntaxKind.ModuleBlock: + case SyntaxKind.SourceFile: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.Constructor: + return true; + default: + return hasSomeImportantChild(item); + } + } + function hasSomeImportantChild(item: NavigationBarNode) { + return forEach(item.children, child => { + const childKind = navigationBarNodeKind(child); + return childKind !== SyntaxKind.VariableDeclaration && childKind !== SyntaxKind.BindingElement; + }); } } + } - function getNavBarItem(text: string, kind: string, spans: TextSpan[], kindModifiers = ScriptElementKindModifier.none): NavigationBarItem { + // NavigationBarItem requires an array, but will not mutate it, so just give it this for performance. + const emptyChildItemArray: NavigationBarItem[] = []; + + function convertToTopLevelItem(n: NavigationBarNode): NavigationBarItem { + return { + text: getItemName(n.node), + kind: nodeKind(n.node), + kindModifiers: getNodeModifiers(n.node), + spans: getSpans(n), + childItems: map(n.children, convertToChildItem) || emptyChildItemArray, + indent: n.indent, + bolded: false, + grayed: false + }; + + function convertToChildItem(n: NavigationBarNode): NavigationBarItem { return { - text, kind, kindModifiers, spans, childItems: [], indent, bolded: false, grayed: false + text: getItemName(n.node), + kind: nodeKind(n.node), + kindModifiers: getNodeModifiers(n.node), + spans: getSpans(n), + childItems: emptyChildItemArray, + indent: 0, + bolded: false, + grayed: false }; } - function getDefineModuleItem(node: Node): NavigationBarItem { - if (node.kind !== SyntaxKind.FunctionExpression && node.kind !== SyntaxKind.ArrowFunction) { - return undefined; - } - - // No match if this is not a call expression to an identifier named 'define' - if (node.parent.kind !== SyntaxKind.CallExpression) { - return undefined; - } - const callExpr = node.parent as CallExpression; - if (callExpr.expression.kind !== SyntaxKind.Identifier || callExpr.expression.getText() !== "define") { - return undefined; - } - - // Return a module of either the given text in the first argument, or of the source file path - let defaultName = node.getSourceFile().fileName; - if (callExpr.arguments[0].kind === SyntaxKind.StringLiteral) { - defaultName = ((callExpr.arguments[0]) as StringLiteral).text; + function getSpans(n: NavigationBarNode): TextSpan[] { + const spans = [getNodeSpan(n.node)]; + if (n.additionalNodes) { + for (const node of n.additionalNodes) { + spans.push(getNodeSpan(node)); + } } - return getNavBarItem(defaultName, ScriptElementKind.moduleElement, [getNodeSpan(node.parent)]); + return spans; } + } - function getFunctionOrClassExpressionItem(node: Node): NavigationBarItem { - if (node.kind !== SyntaxKind.FunctionExpression && - node.kind !== SyntaxKind.ArrowFunction && - node.kind !== SyntaxKind.ClassExpression) { - return undefined; - } - - const fnExpr = node as FunctionExpression | ArrowFunction | ClassExpression; - let fnName: string; - if (fnExpr.name && getFullWidth(fnExpr.name) > 0) { - // The expression has an identifier, so use that as the name - fnName = declarationNameToString(fnExpr.name); - } - else { - // See if it is a var initializer. If so, use the var name. - if (fnExpr.parent.kind === SyntaxKind.VariableDeclaration) { - fnName = declarationNameToString((fnExpr.parent as VariableDeclaration).name); + // TODO: GH#9145: We should just use getNodeKind. No reason why navigationBar and navigateTo should have different behaviors. + function nodeKind(node: Node): string { + switch (node.kind) { + case SyntaxKind.SourceFile: + return ScriptElementKind.moduleElement; + + case SyntaxKind.EnumMember: + return ScriptElementKind.memberVariableElement; + + case SyntaxKind.VariableDeclaration: + case SyntaxKind.BindingElement: + let variableDeclarationNode: Node; + let name: Node; + + if (node.kind === SyntaxKind.BindingElement) { + name = (node).name; + variableDeclarationNode = node; + // binding elements are added only for variable declarations + // bubble up to the containing variable declaration + while (variableDeclarationNode && variableDeclarationNode.kind !== SyntaxKind.VariableDeclaration) { + variableDeclarationNode = variableDeclarationNode.parent; + } + Debug.assert(!!variableDeclarationNode); } - // See if it is of the form " = function(){...}". If so, use the text from the left-hand side. - else if (fnExpr.parent.kind === SyntaxKind.BinaryExpression && - (fnExpr.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { - fnName = (fnExpr.parent as BinaryExpression).left.getText(); + else { + Debug.assert(!isBindingPattern((node).name)); + variableDeclarationNode = node; + name = (node).name; + } + + if (isConst(variableDeclarationNode)) { + return ts.ScriptElementKind.constElement; } - // See if it is a property assignment, and if so use the property name - else if (fnExpr.parent.kind === SyntaxKind.PropertyAssignment && - (fnExpr.parent as PropertyAssignment).name) { - fnName = (fnExpr.parent as PropertyAssignment).name.getText(); + else if (isLet(variableDeclarationNode)) { + return ts.ScriptElementKind.letElement; } else { - fnName = node.kind === SyntaxKind.ClassExpression ? anonClassText : anonFnText; + return ts.ScriptElementKind.variableElement; } - } - const scriptKind = node.kind === SyntaxKind.ClassExpression ? ScriptElementKind.classElement : ScriptElementKind.functionElement; - return getNavBarItem(fnName, scriptKind, [getNodeSpan(node)]); + + case SyntaxKind.ArrowFunction: + return ts.ScriptElementKind.functionElement; + + case SyntaxKind.JSDocTypedefTag: + return ScriptElementKind.typeElement; + + default: + return getNodeKind(node); } + } - function getNodeSpan(node: Node) { - return node.kind === SyntaxKind.SourceFile - ? createTextSpanFromBounds(node.getFullStart(), node.getEnd()) - : createTextSpanFromBounds(node.getStart(), node.getEnd()); + function getModuleName(moduleDeclaration: ModuleDeclaration): string { + // We want to maintain quotation marks. + if (isAmbientModule(moduleDeclaration)) { + return getTextOfNode(moduleDeclaration.name); } - function getScriptKindForElementKind(kind: SyntaxKind) { - switch (kind) { - case SyntaxKind.VariableDeclaration: - return ScriptElementKind.variableElement; - case SyntaxKind.FunctionDeclaration: - return ScriptElementKind.functionElement; - case SyntaxKind.ClassDeclaration: - return ScriptElementKind.classElement; - case SyntaxKind.Constructor: - return ScriptElementKind.constructorImplementationElement; - case SyntaxKind.GetAccessor: - return ScriptElementKind.memberGetAccessorElement; - case SyntaxKind.SetAccessor: - return ScriptElementKind.memberSetAccessorElement; - default: - return "unknown"; - } + // Otherwise, we need to aggregate each identifier to build up the qualified name. + const result: string[] = []; + + result.push(moduleDeclaration.name.text); + + while (moduleDeclaration.body && moduleDeclaration.body.kind === SyntaxKind.ModuleDeclaration) { + moduleDeclaration = moduleDeclaration.body; + + result.push(moduleDeclaration.name.text); + } + + return result.join("."); + } + + /** + * For 'module A.B.C', we want to get the node for 'C'. + * We store 'A' as associated with a NavNode, and use getModuleName to traverse down again. + */ + function getInteriorModule(decl: ModuleDeclaration): ModuleDeclaration { + return decl.body.kind === SyntaxKind.ModuleDeclaration ? getInteriorModule(decl.body) : decl; + } + + function isComputedProperty(member: EnumMember): boolean { + return !member.name || member.name.kind === SyntaxKind.ComputedPropertyName; + } + + function getNodeSpan(node: Node): TextSpan { + return node.kind === SyntaxKind.SourceFile + ? createTextSpanFromBounds(node.getFullStart(), node.getEnd()) + : createTextSpanFromBounds(node.getStart(curSourceFile), node.getEnd()); + } + + function getFunctionOrClassName(node: FunctionExpression | FunctionDeclaration | ArrowFunction | ClassLikeDeclaration): string { + if (node.name && getFullWidth(node.name) > 0) { + return declarationNameToString(node.name); + } + // See if it is a var initializer. If so, use the var name. + else if (node.parent.kind === SyntaxKind.VariableDeclaration) { + return declarationNameToString((node.parent as VariableDeclaration).name); + } + // See if it is of the form " = function(){...}". If so, use the text from the left-hand side. + else if (node.parent.kind === SyntaxKind.BinaryExpression && + (node.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { + return nodeText((node.parent as BinaryExpression).left); } + // See if it is a property assignment, and if so use the property name + else if (node.parent.kind === SyntaxKind.PropertyAssignment && (node.parent as PropertyAssignment).name) { + return nodeText((node.parent as PropertyAssignment).name); + } + // Default exports are named "default" + else if (getModifierFlags(node) & ModifierFlags.Default) { + return "default"; + } + else { + return isClassLike(node) ? "" : ""; + } + } - return sourceFileItem.childItems; + function isFunctionOrClassExpression(node: Node): boolean { + return node.kind === SyntaxKind.FunctionExpression || node.kind === SyntaxKind.ArrowFunction || node.kind === SyntaxKind.ClassExpression; } } diff --git a/src/services/services.ts b/src/services/services.ts index c625fcb08fff6..72749eb5e4ca5 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2008,9 +2008,17 @@ namespace ts { // so pass --noLib to avoid reporting a file not found error. options.noLib = true; - // Clear out the lib and types option as well + // 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. @@ -7050,7 +7058,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[] { @@ -7544,7 +7552,8 @@ namespace ts { return; case SyntaxKind.Parameter: if ((token.parent).name === token) { - return ClassificationType.parameterName; + const isThis = token.kind === SyntaxKind.Identifier && (token).originalKeywordKind === SyntaxKind.ThisKeyword; + return isThis ? ClassificationType.keyword : ClassificationType.parameterName; } return; } diff --git a/src/services/shims.ts b/src/services/shims.ts index 96392ca42bebd..ac74ee0975019 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -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 { diff --git a/tests/baselines/reference/classExtendingClassLikeType.errors.txt b/tests/baselines/reference/classExtendingClassLikeType.errors.txt index 6f9aef927ead8..5edefd78ec514 100644 --- a/tests/baselines/reference/classExtendingClassLikeType.errors.txt +++ b/tests/baselines/reference/classExtendingClassLikeType.errors.txt @@ -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 { ~~~~ -!!! error TS2304: Cannot find name 'Base'. +!!! error TS2689: Cannot extend an interface 'Base'. Did you mean 'implements'? } interface BaseConstructor { diff --git a/tests/baselines/reference/classExtendsEveryObjectType.errors.txt b/tests/baselines/reference/classExtendsEveryObjectType.errors.txt index 0339dfad13a44..e1c5137e3a918 100644 --- a/tests/baselines/reference/classExtendsEveryObjectType.errors.txt +++ b/tests/baselines/reference/classExtendsEveryObjectType.errors.txt @@ -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 ~~~~~~~~~~~~~~~~ diff --git a/tests/baselines/reference/classExtendsInterface.errors.txt b/tests/baselines/reference/classExtendsInterface.errors.txt index 2ecca6cf2cf2e..72b8466105c07 100644 --- a/tests/baselines/reference/classExtendsInterface.errors.txt +++ b/tests/baselines/reference/classExtendsInterface.errors.txt @@ -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 {} class A2 extends Comparable2 {} ~~~~~~~~~~~ -!!! error TS2304: Cannot find name 'Comparable2'. +!!! error TS2689: Cannot extend an interface 'Comparable2'. Did you mean 'implements'? class B2 implements Comparable2 {} \ No newline at end of file diff --git a/tests/baselines/reference/classExtendsInterface.js b/tests/baselines/reference/classExtendsInterface.js index c06c4e66d8b69..b324f7382d820 100644 --- a/tests/baselines/reference/classExtendsInterface.js +++ b/tests/baselines/reference/classExtendsInterface.js @@ -2,7 +2,7 @@ interface Comparable {} class A extends Comparable {} class B implements Comparable {} - + interface Comparable2 {} class A2 extends Comparable2 {} class B2 implements Comparable2 {} diff --git a/tests/baselines/reference/classExtendsInterfaceInExpression.errors.txt b/tests/baselines/reference/classExtendsInterfaceInExpression.errors.txt new file mode 100644 index 0000000000000..64b160ea76653 --- /dev/null +++ b/tests/baselines/reference/classExtendsInterfaceInExpression.errors.txt @@ -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'. + \ No newline at end of file diff --git a/tests/baselines/reference/classExtendsInterfaceInExpression.js b/tests/baselines/reference/classExtendsInterfaceInExpression.js new file mode 100644 index 0000000000000..69e63f925707c --- /dev/null +++ b/tests/baselines/reference/classExtendsInterfaceInExpression.js @@ -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))); diff --git a/tests/baselines/reference/classExtendsInterfaceInModule.errors.txt b/tests/baselines/reference/classExtendsInterfaceInModule.errors.txt new file mode 100644 index 0000000000000..9a87ddf51b673 --- /dev/null +++ b/tests/baselines/reference/classExtendsInterfaceInModule.errors.txt @@ -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 {} + } + class C1 extends M.I1 {} + ~ +!!! error TS2689: Cannot extend an interface 'M.I1'. Did you mean 'implements'? + class C2 extends M.I2 {} + ~ +!!! 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'? + \ No newline at end of file diff --git a/tests/baselines/reference/classExtendsInterfaceInModule.js b/tests/baselines/reference/classExtendsInterfaceInModule.js new file mode 100644 index 0000000000000..454154887003f --- /dev/null +++ b/tests/baselines/reference/classExtendsInterfaceInModule.js @@ -0,0 +1,44 @@ +//// [classExtendsInterfaceInModule.ts] +module M { + export interface I1 {} + export interface I2 {} +} +class C1 extends M.I1 {} +class C2 extends M.I2 {} + +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)); diff --git a/tests/baselines/reference/constDeclarations-useBeforeDefinition2.symbols b/tests/baselines/reference/constDeclarations-useBeforeDefinition2.symbols deleted file mode 100644 index 281ce4277337f..0000000000000 --- a/tests/baselines/reference/constDeclarations-useBeforeDefinition2.symbols +++ /dev/null @@ -1,9 +0,0 @@ -=== tests/cases/compiler/file1.ts === - -c; ->c : Symbol(c, Decl(file2.ts, 0, 5)) - -=== tests/cases/compiler/file2.ts === -const c = 0; ->c : Symbol(c, Decl(file2.ts, 0, 5)) - diff --git a/tests/baselines/reference/constDeclarations-useBeforeDefinition2.types b/tests/baselines/reference/constDeclarations-useBeforeDefinition2.types deleted file mode 100644 index ae60fdfa47728..0000000000000 --- a/tests/baselines/reference/constDeclarations-useBeforeDefinition2.types +++ /dev/null @@ -1,10 +0,0 @@ -=== tests/cases/compiler/file1.ts === - -c; ->c : number - -=== tests/cases/compiler/file2.ts === -const c = 0; ->c : number ->0 : number - diff --git a/tests/baselines/reference/discriminatedUnionTypes1.js b/tests/baselines/reference/discriminatedUnionTypes1.js new file mode 100644 index 0000000000000..8679689569a02 --- /dev/null +++ b/tests/baselines/reference/discriminatedUnionTypes1.js @@ -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 } +} diff --git a/tests/baselines/reference/discriminatedUnionTypes1.symbols b/tests/baselines/reference/discriminatedUnionTypes1.symbols new file mode 100644 index 0000000000000..380694474239a --- /dev/null +++ b/tests/baselines/reference/discriminatedUnionTypes1.symbols @@ -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)) +} diff --git a/tests/baselines/reference/discriminatedUnionTypes1.types b/tests/baselines/reference/discriminatedUnionTypes1.types new file mode 100644 index 0000000000000..234de28eabae5 --- /dev/null +++ b/tests/baselines/reference/discriminatedUnionTypes1.types @@ -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; } +} diff --git a/tests/baselines/reference/genericTypeReferenceWithoutTypeArgument2.errors.txt b/tests/baselines/reference/genericTypeReferenceWithoutTypeArgument2.errors.txt index e590ad42a7ddd..b6767a3b9388b 100644 --- a/tests/baselines/reference/genericTypeReferenceWithoutTypeArgument2.errors.txt +++ b/tests/baselines/reference/genericTypeReferenceWithoutTypeArgument2.errors.txt @@ -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' requires 1 type argument(s). tests/cases/conformance/types/specifyingTypes/typeReferences/genericTypeReferenceWithoutTypeArgument2.ts(18,27): error TS2314: Generic type 'I' requires 1 type argument(s). tests/cases/conformance/types/specifyingTypes/typeReferences/genericTypeReferenceWithoutTypeArgument2.ts(18,38): error TS2314: Generic type 'I' 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' 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' 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 {} diff --git a/tests/baselines/reference/letDeclarations-useBeforeDefinition2.symbols b/tests/baselines/reference/letDeclarations-useBeforeDefinition2.symbols deleted file mode 100644 index c5a067ede4dd2..0000000000000 --- a/tests/baselines/reference/letDeclarations-useBeforeDefinition2.symbols +++ /dev/null @@ -1,9 +0,0 @@ -=== tests/cases/compiler/file1.ts === - -l; ->l : Symbol(l, Decl(file2.ts, 0, 5)) - -=== tests/cases/compiler/file2.ts === -const l = 0; ->l : Symbol(l, Decl(file2.ts, 0, 5)) - diff --git a/tests/baselines/reference/letDeclarations-useBeforeDefinition2.types b/tests/baselines/reference/letDeclarations-useBeforeDefinition2.types deleted file mode 100644 index 793a7a78ba71e..0000000000000 --- a/tests/baselines/reference/letDeclarations-useBeforeDefinition2.types +++ /dev/null @@ -1,10 +0,0 @@ -=== tests/cases/compiler/file1.ts === - -l; ->l : number - -=== tests/cases/compiler/file2.ts === -const l = 0; ->l : number ->0 : number - diff --git a/tests/baselines/reference/transpile/Supports setting allowJs.js b/tests/baselines/reference/transpile/Supports setting allowJs.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting allowJs.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting allowSyntheticDefaultImports.js b/tests/baselines/reference/transpile/Supports setting allowSyntheticDefaultImports.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting allowSyntheticDefaultImports.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting allowUnreachableCode.js b/tests/baselines/reference/transpile/Supports setting allowUnreachableCode.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting allowUnreachableCode.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting allowUnusedLabels.js b/tests/baselines/reference/transpile/Supports setting allowUnusedLabels.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting allowUnusedLabels.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting baseUrl.js b/tests/baselines/reference/transpile/Supports setting baseUrl.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting baseUrl.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting charset.js b/tests/baselines/reference/transpile/Supports setting charset.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting charset.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting declaration.js b/tests/baselines/reference/transpile/Supports setting declaration.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting declaration.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting declarationDir.js b/tests/baselines/reference/transpile/Supports setting declarationDir.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting declarationDir.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting emitBOM.js b/tests/baselines/reference/transpile/Supports setting emitBOM.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting emitBOM.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting emitDecoratorMetadata.js b/tests/baselines/reference/transpile/Supports setting emitDecoratorMetadata.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting emitDecoratorMetadata.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting experimentalDecorators.js b/tests/baselines/reference/transpile/Supports setting experimentalDecorators.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting experimentalDecorators.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting forceConsistentCasingInFileNames.js b/tests/baselines/reference/transpile/Supports setting forceConsistentCasingInFileNames.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting forceConsistentCasingInFileNames.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting isolatedModules.js b/tests/baselines/reference/transpile/Supports setting isolatedModules.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting isolatedModules.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting jsx.js b/tests/baselines/reference/transpile/Supports setting jsx.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting jsx.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting lib.js b/tests/baselines/reference/transpile/Supports setting lib.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting lib.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting locale.js b/tests/baselines/reference/transpile/Supports setting locale.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting locale.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting module.js b/tests/baselines/reference/transpile/Supports setting module.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting module.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting moduleResolution.js b/tests/baselines/reference/transpile/Supports setting moduleResolution.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting moduleResolution.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting newLine.js b/tests/baselines/reference/transpile/Supports setting newLine.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting newLine.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting noEmit.js b/tests/baselines/reference/transpile/Supports setting noEmit.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting noEmit.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting noEmitHelpers.js b/tests/baselines/reference/transpile/Supports setting noEmitHelpers.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting noEmitHelpers.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting noEmitOnError.js b/tests/baselines/reference/transpile/Supports setting noEmitOnError.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting noEmitOnError.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting noErrorTruncation.js b/tests/baselines/reference/transpile/Supports setting noErrorTruncation.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting noErrorTruncation.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting noFallthroughCasesInSwitch.js b/tests/baselines/reference/transpile/Supports setting noFallthroughCasesInSwitch.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting noFallthroughCasesInSwitch.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting noImplicitAny.js b/tests/baselines/reference/transpile/Supports setting noImplicitAny.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting noImplicitAny.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting noImplicitReturns.js b/tests/baselines/reference/transpile/Supports setting noImplicitReturns.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting noImplicitReturns.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting noImplicitThis.js b/tests/baselines/reference/transpile/Supports setting noImplicitThis.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting noImplicitThis.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting noImplicitUseStrict.js b/tests/baselines/reference/transpile/Supports setting noImplicitUseStrict.js new file mode 100644 index 0000000000000..8394371f9081a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting noImplicitUseStrict.js @@ -0,0 +1,2 @@ +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting noLib.js b/tests/baselines/reference/transpile/Supports setting noLib.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting noLib.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting noResolve.js b/tests/baselines/reference/transpile/Supports setting noResolve.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting noResolve.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting out.js b/tests/baselines/reference/transpile/Supports setting out.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting out.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting outDir.js b/tests/baselines/reference/transpile/Supports setting outDir.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting outDir.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting outFile.js b/tests/baselines/reference/transpile/Supports setting outFile.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting outFile.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting paths.js b/tests/baselines/reference/transpile/Supports setting paths.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting paths.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting preserveConstEnums.js b/tests/baselines/reference/transpile/Supports setting preserveConstEnums.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting preserveConstEnums.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting reactNamespace.js b/tests/baselines/reference/transpile/Supports setting reactNamespace.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting reactNamespace.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting removeComments.js b/tests/baselines/reference/transpile/Supports setting removeComments.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting removeComments.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting rootDir.js b/tests/baselines/reference/transpile/Supports setting rootDir.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting rootDir.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting rootDirs.js b/tests/baselines/reference/transpile/Supports setting rootDirs.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting rootDirs.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting skipDefaultLibCheck.js b/tests/baselines/reference/transpile/Supports setting skipDefaultLibCheck.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting skipDefaultLibCheck.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting skipLibCheck.js b/tests/baselines/reference/transpile/Supports setting skipLibCheck.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting skipLibCheck.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting strictNullChecks.js b/tests/baselines/reference/transpile/Supports setting strictNullChecks.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting strictNullChecks.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting stripInternal.js b/tests/baselines/reference/transpile/Supports setting stripInternal.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting stripInternal.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting suppressExcessPropertyErrors.js b/tests/baselines/reference/transpile/Supports setting suppressExcessPropertyErrors.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting suppressExcessPropertyErrors.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting suppressImplicitAnyIndexErrors.js b/tests/baselines/reference/transpile/Supports setting suppressImplicitAnyIndexErrors.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting suppressImplicitAnyIndexErrors.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting target.js b/tests/baselines/reference/transpile/Supports setting target.js new file mode 100644 index 0000000000000..8394371f9081a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting target.js @@ -0,0 +1,2 @@ +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting typeRoots.js b/tests/baselines/reference/transpile/Supports setting typeRoots.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting typeRoots.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Supports setting types.js b/tests/baselines/reference/transpile/Supports setting types.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting types.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/verifyDefaultLib_dom.js b/tests/baselines/reference/verifyDefaultLib_dom.js new file mode 100644 index 0000000000000..b65e133572ab7 --- /dev/null +++ b/tests/baselines/reference/verifyDefaultLib_dom.js @@ -0,0 +1,6 @@ +//// [verifyDefaultLib_dom.ts] + +var x: HTMLElement; + +//// [verifyDefaultLib_dom.js] +var x; diff --git a/tests/baselines/reference/verifyDefaultLib_dom.symbols b/tests/baselines/reference/verifyDefaultLib_dom.symbols new file mode 100644 index 0000000000000..53502b040c3bc --- /dev/null +++ b/tests/baselines/reference/verifyDefaultLib_dom.symbols @@ -0,0 +1,6 @@ +=== tests/cases/compiler/verifyDefaultLib_dom.ts === + +var x: HTMLElement; +>x : Symbol(x, Decl(verifyDefaultLib_dom.ts, 1, 3)) +>HTMLElement : Symbol(HTMLElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) + diff --git a/tests/baselines/reference/verifyDefaultLib_dom.types b/tests/baselines/reference/verifyDefaultLib_dom.types new file mode 100644 index 0000000000000..aafd063846d81 --- /dev/null +++ b/tests/baselines/reference/verifyDefaultLib_dom.types @@ -0,0 +1,6 @@ +=== tests/cases/compiler/verifyDefaultLib_dom.ts === + +var x: HTMLElement; +>x : HTMLElement +>HTMLElement : HTMLElement + diff --git a/tests/baselines/reference/verifyDefaultLib_webworker.js b/tests/baselines/reference/verifyDefaultLib_webworker.js new file mode 100644 index 0000000000000..515b5d9632fc5 --- /dev/null +++ b/tests/baselines/reference/verifyDefaultLib_webworker.js @@ -0,0 +1,6 @@ +//// [verifyDefaultLib_webworker.ts] + +var x: Worker; + +//// [verifyDefaultLib_webworker.js] +var x; diff --git a/tests/baselines/reference/verifyDefaultLib_webworker.symbols b/tests/baselines/reference/verifyDefaultLib_webworker.symbols new file mode 100644 index 0000000000000..ac27e7c83dcec --- /dev/null +++ b/tests/baselines/reference/verifyDefaultLib_webworker.symbols @@ -0,0 +1,6 @@ +=== tests/cases/compiler/verifyDefaultLib_webworker.ts === + +var x: Worker; +>x : Symbol(x, Decl(verifyDefaultLib_webworker.ts, 1, 3)) +>Worker : Symbol(Worker, Decl(lib.webworker.d.ts, --, --), Decl(lib.webworker.d.ts, --, --)) + diff --git a/tests/baselines/reference/verifyDefaultLib_webworker.types b/tests/baselines/reference/verifyDefaultLib_webworker.types new file mode 100644 index 0000000000000..38accb398421f --- /dev/null +++ b/tests/baselines/reference/verifyDefaultLib_webworker.types @@ -0,0 +1,6 @@ +=== tests/cases/compiler/verifyDefaultLib_webworker.ts === + +var x: Worker; +>x : Worker +>Worker : Worker + diff --git a/tests/cases/compiler/classExtendsInterface.ts b/tests/cases/compiler/classExtendsInterface.ts index 36f42167d1a29..eaab1d60fc408 100644 --- a/tests/cases/compiler/classExtendsInterface.ts +++ b/tests/cases/compiler/classExtendsInterface.ts @@ -1,7 +1,7 @@ interface Comparable {} class A extends Comparable {} class B implements Comparable {} - + interface Comparable2 {} class A2 extends Comparable2 {} class B2 implements Comparable2 {} diff --git a/tests/cases/compiler/classExtendsInterfaceInExpression.ts b/tests/cases/compiler/classExtendsInterfaceInExpression.ts new file mode 100644 index 0000000000000..002631afedf12 --- /dev/null +++ b/tests/cases/compiler/classExtendsInterfaceInExpression.ts @@ -0,0 +1,7 @@ +interface A {} + +function factory(a: any): {new(): Object} { + return null; +} + +class C extends factory(A) {} diff --git a/tests/cases/compiler/classExtendsInterfaceInModule.ts b/tests/cases/compiler/classExtendsInterfaceInModule.ts new file mode 100644 index 0000000000000..4ea24e5dd7d8d --- /dev/null +++ b/tests/cases/compiler/classExtendsInterfaceInModule.ts @@ -0,0 +1,14 @@ +module M { + export interface I1 {} + export interface I2 {} +} +class C1 extends M.I1 {} +class C2 extends M.I2 {} + +module Mod { + export namespace Nested { + export interface I {} + } +} + +class D extends Mod.Nested.I {} diff --git a/tests/cases/compiler/verifyDefaultLib_dom.ts b/tests/cases/compiler/verifyDefaultLib_dom.ts new file mode 100644 index 0000000000000..519485320ae4e --- /dev/null +++ b/tests/cases/compiler/verifyDefaultLib_dom.ts @@ -0,0 +1,7 @@ +// @strictNullChecks: true +// @noImplicitAny: true +// @noImplicitThis: true +// @skipDefaultLibCheck: false +// @lib: es2015,es2016,es2017,dom,scripthost + +var x: HTMLElement; \ No newline at end of file diff --git a/tests/cases/compiler/verifyDefaultLib_webworker.ts b/tests/cases/compiler/verifyDefaultLib_webworker.ts new file mode 100644 index 0000000000000..7da62387d2fde --- /dev/null +++ b/tests/cases/compiler/verifyDefaultLib_webworker.ts @@ -0,0 +1,7 @@ +// @strictNullChecks: true +// @noImplicitAny: true +// @noImplicitThis: true +// @skipDefaultLibCheck: false +// @lib: es2015,es2016,es2017,webworker + +var x: Worker; \ No newline at end of file diff --git a/tests/cases/conformance/types/union/discriminatedUnionTypes1.ts b/tests/cases/conformance/types/union/discriminatedUnionTypes1.ts new file mode 100644 index 0000000000000..404162308b97d --- /dev/null +++ b/tests/cases/conformance/types/union/discriminatedUnionTypes1.ts @@ -0,0 +1,142 @@ +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 } +} \ No newline at end of file diff --git a/tests/cases/fourslash/classifyThisParameter.ts b/tests/cases/fourslash/classifyThisParameter.ts new file mode 100644 index 0000000000000..5e0c9a9d4b666 --- /dev/null +++ b/tests/cases/fourslash/classifyThisParameter.ts @@ -0,0 +1,13 @@ +/// + +////function f(this){} + +var c = classification; +verify.syntacticClassificationsAre( + c.keyword("function"), + c.identifier("f"), + c.punctuation("("), + c.keyword("this"), + c.punctuation(")"), + c.punctuation("{"), + c.punctuation("}")); diff --git a/tests/cases/fourslash/navbar_contains-no-duplicates.ts b/tests/cases/fourslash/navbar_contains-no-duplicates.ts index e259a7bef901f..10e4027ff84c7 100644 --- a/tests/cases/fourslash/navbar_contains-no-duplicates.ts +++ b/tests/cases/fourslash/navbar_contains-no-duplicates.ts @@ -7,7 +7,7 @@ //// } //// } //// } -//// +//// //// declare module Windows { //// export module Foundation { //// export var B; @@ -16,13 +16,13 @@ //// } //// } //// } -//// +//// //// class ABC { //// public foo() { //// return 3; //// } //// } -//// +//// //// module ABC { //// export var x = 3; //// } @@ -95,13 +95,13 @@ verify.navigationBar([ "kindModifiers": "export,declare" }, { - "text": "Test", - "kind": "class", + "text": "B", + "kind": "var", "kindModifiers": "export,declare" }, { - "text": "B", - "kind": "var", + "text": "Test", + "kind": "class", "kindModifiers": "export,declare" }, { diff --git a/tests/cases/fourslash/navbar_exportDefault.ts b/tests/cases/fourslash/navbar_exportDefault.ts index dc99cff7d649c..e547c9129a69d 100644 --- a/tests/cases/fourslash/navbar_exportDefault.ts +++ b/tests/cases/fourslash/navbar_exportDefault.ts @@ -16,7 +16,14 @@ goTo.file("a.ts"); verify.navigationBar([ { "text": "\"a\"", - "kind": "module" + "kind": "module", + "childItems": [ + { + "text": "default", + "kind": "class", + "kindModifiers": "export" + } + ] }, { "text": "default", @@ -52,6 +59,13 @@ verify.navigationBar([ { "text": "\"c\"", "kind": "module", + "childItems": [ + { + "text": "default", + "kind": "function", + "kindModifiers": "export" + } + ] }, { "text": "default", diff --git a/tests/cases/fourslash/navigationBarAnonymousClassAndFunctionExpressions.ts b/tests/cases/fourslash/navigationBarAnonymousClassAndFunctionExpressions.ts new file mode 100644 index 0000000000000..f15959812fc06 --- /dev/null +++ b/tests/cases/fourslash/navigationBarAnonymousClassAndFunctionExpressions.ts @@ -0,0 +1,147 @@ +/// + +////global.cls = class { }; +////(function() { +//// const x = () => { +//// // Presence of inner function causes x to be a top-level function. +//// function xx() {} +//// }; +//// const y = { +//// // This is not a top-level function (contains nothing, but shows up in childItems of its parent.) +//// foo: function() {} +//// }; +//// (function nest() { +//// function moreNest() {} +//// })(); +////})(); +////(function() { // Different anonymous functions are not merged +//// // These will only show up as childItems. +//// function z() {} +//// console.log(function() {}) +////}) +////(function classes() { +//// // Classes show up in top-level regardless of whether they have names or inner declarations. +//// const cls2 = class { }; +//// console.log(class cls3 {}); +//// (class { }); +////}) + +verify.navigationBar([ + { + "text": "", + "kind": "module", + "childItems": [ + { + "text": "", + "kind": "function" + }, + { + "text": "", + "kind": "function" + }, + { + "text": "classes", + "kind": "function" + }, + { + "text": "global.cls", + "kind": "class" + } + ] + }, + { + "text": "", + "kind": "function", + "childItems": [ + { + "text": "nest", + "kind": "function" + }, + { + "text": "x", + "kind": "function" + }, + { + "text": "y", + "kind": "const" + } + ], + "indent": 1 + }, + { + "text": "nest", + "kind": "function", + "childItems": [ + { + "text": "moreNest", + "kind": "function" + } + ], + "indent": 2 + }, + { + "text": "x", + "kind": "function", + "childItems": [ + { + "text": "xx", + "kind": "function" + } + ], + "indent": 2 + }, + { + "text": "", + "kind": "function", + "childItems": [ + { + "text": "", + "kind": "function" + }, + { + "text": "z", + "kind": "function" + } + ], + "indent": 1 + }, + { + "text": "classes", + "kind": "function", + "childItems": [ + { + "text": "", + "kind": "class" + }, + { + "text": "cls2", + "kind": "class" + }, + { + "text": "cls3", + "kind": "class" + } + ], + "indent": 1 + }, + { + "text": "", + "kind": "class", + "indent": 2 + }, + { + "text": "cls2", + "kind": "class", + "indent": 2 + }, + { + "text": "cls3", + "kind": "class", + "indent": 2 + }, + { + "text": "global.cls", + "kind": "class", + "indent": 1 + } +]); diff --git a/tests/cases/fourslash/navigationBarAnonymousClassAndFunctionExpressions2.ts b/tests/cases/fourslash/navigationBarAnonymousClassAndFunctionExpressions2.ts new file mode 100644 index 0000000000000..214a14949ac5e --- /dev/null +++ b/tests/cases/fourslash/navigationBarAnonymousClassAndFunctionExpressions2.ts @@ -0,0 +1,64 @@ +/// + +////console.log(console.log(class Y {}, class X {}), console.log(class B {}, class A {})); +////console.log(class Cls { meth() {} }); + +verify.navigationBar([ + { + "text": "", + "kind": "module", + "childItems": [ + { + "text": "A", + "kind": "class" + }, + { + "text": "B", + "kind": "class" + }, + { + "text": "Cls", + "kind": "class" + }, + { + "text": "X", + "kind": "class" + }, + { + "text": "Y", + "kind": "class" + } + ] + }, + { + "text": "A", + "kind": "class", + "indent": 1 + }, + { + "text": "B", + "kind": "class", + "indent": 1 + }, + { + "text": "Cls", + "kind": "class", + "childItems": [ + { + "text": "meth", + "kind": "method" + } + ], + "indent": 1 + }, + { + "text": "X", + "kind": "class", + "indent": 1 + }, + { + "text": "Y", + "kind": "class", + "indent": 1 + } +]); diff --git a/tests/cases/fourslash/navigationBarGetterAndSetter.ts b/tests/cases/fourslash/navigationBarGetterAndSetter.ts new file mode 100644 index 0000000000000..48105e4e9af3a --- /dev/null +++ b/tests/cases/fourslash/navigationBarGetterAndSetter.ts @@ -0,0 +1,48 @@ +/// + +////class X { +//// get x() {} +//// set x(value) { +//// // Inner declaration should make the setter top-level. +//// function f() {} +//// } +////} + +verify.navigationBar([ + { + "text": "", + "kind": "module", + "childItems": [ + { + "text": "X", + "kind": "class" + } + ] + }, + { + "text": "X", + "kind": "class", + "childItems": [ + { + "text": "x", + "kind": "getter" + }, + { + "text": "x", + "kind": "setter" + } + ], + "indent": 1 + }, + { + "text": "x", + "kind": "setter", + "childItems": [ + { + "text": "f", + "kind": "function" + } + ], + "indent": 2 + } +]); diff --git a/tests/cases/fourslash/navigationBarImports.ts b/tests/cases/fourslash/navigationBarImports.ts new file mode 100644 index 0000000000000..43cb99c556a7e --- /dev/null +++ b/tests/cases/fourslash/navigationBarImports.ts @@ -0,0 +1,30 @@ +/// + +////import a, {b} from "m"; +////import c = require("m"); +////import * as d from "m"; + +verify.navigationBar([ + { + "text": "\"navigationBarImports\"", + "kind": "module", + "childItems": [ + { + "text": "a", + "kind": "alias" + }, + { + "text": "b", + "kind": "alias" + }, + { + "text": "c", + "kind": "alias" + }, + { + "text": "d", + "kind": "alias" + } + ] + } +]); diff --git a/tests/cases/fourslash/navigationBarItemsFunctions.ts b/tests/cases/fourslash/navigationBarItemsFunctions.ts index 91546462a2572..f5aa3fb681dd5 100644 --- a/tests/cases/fourslash/navigationBarItemsFunctions.ts +++ b/tests/cases/fourslash/navigationBarItemsFunctions.ts @@ -32,6 +32,12 @@ verify.navigationBar([ { "text": "baz", "kind": "function", + "childItems": [ + { + "text": "v", + "kind": "var" + } + ], "indent": 1 }, { @@ -41,6 +47,10 @@ verify.navigationBar([ { "text": "bar", "kind": "function" + }, + { + "text": "x", + "kind": "var" } ], "indent": 1 @@ -52,6 +62,10 @@ verify.navigationBar([ { "text": "biz", "kind": "function" + }, + { + "text": "y", + "kind": "var" } ], "indent": 2 diff --git a/tests/cases/fourslash/navigationBarItemsFunctionsBroken.ts b/tests/cases/fourslash/navigationBarItemsFunctionsBroken.ts index 96dcbb944ae07..2f17a5006ff5f 100644 --- a/tests/cases/fourslash/navigationBarItemsFunctionsBroken.ts +++ b/tests/cases/fourslash/navigationBarItemsFunctionsBroken.ts @@ -18,6 +18,12 @@ verify.navigationBar([ { "text": "f", "kind": "function", + "childItems": [ + { + "text": "", + "kind": "function" + } + ], "indent": 1 } ]); diff --git a/tests/cases/fourslash/navigationBarItemsFunctionsBroken2.ts b/tests/cases/fourslash/navigationBarItemsFunctionsBroken2.ts index 127bde8c9e71d..f907bdad06719 100644 --- a/tests/cases/fourslash/navigationBarItemsFunctionsBroken2.ts +++ b/tests/cases/fourslash/navigationBarItemsFunctionsBroken2.ts @@ -10,6 +10,10 @@ verify.navigationBar([ "text": "", "kind": "module", "childItems": [ + { + "text": "", + "kind": "function" + }, { "text": "f", "kind": "function" @@ -19,6 +23,12 @@ verify.navigationBar([ { "text": "f", "kind": "function", + "childItems": [ + { + "text": "", + "kind": "function" + } + ], "indent": 1 } ]); diff --git a/tests/cases/fourslash/navigationBarItemsInsideMethodsAndConstructors.ts b/tests/cases/fourslash/navigationBarItemsInsideMethodsAndConstructors.ts index 28ec25c6f1dd2..3af3b351114b1 100644 --- a/tests/cases/fourslash/navigationBarItemsInsideMethodsAndConstructors.ts +++ b/tests/cases/fourslash/navigationBarItemsInsideMethodsAndConstructors.ts @@ -76,17 +76,17 @@ verify.navigationBar([ "kind": "property" } ], - "indent": 2 + "indent": 3 }, { "text": "LocalFunctionInConstructor", "kind": "function", - "indent": 2 + "indent": 3 }, { "text": "LocalInterfaceInConstrcutor", "kind": "interface", - "indent": 2 + "indent": 3 }, { "text": "method", @@ -116,7 +116,7 @@ verify.navigationBar([ "kind": "property" } ], - "indent": 2 + "indent": 3 }, { "text": "LocalFunctionInMethod", @@ -127,11 +127,11 @@ verify.navigationBar([ "kind": "function" } ], - "indent": 2 + "indent": 3 }, { "text": "LocalInterfaceInMethod", "kind": "interface", - "indent": 2 + "indent": 3 } ]); diff --git a/tests/cases/fourslash/navigationBarItemsItems2.ts b/tests/cases/fourslash/navigationBarItemsItems2.ts index 762531d8778b5..6ab0827e8f959 100644 --- a/tests/cases/fourslash/navigationBarItemsItems2.ts +++ b/tests/cases/fourslash/navigationBarItemsItems2.ts @@ -12,6 +12,11 @@ verify.navigationBar([ "text": "\"navigationBarItemsItems2\"", "kind": "module", "childItems": [ + { + "text": "", + "kind": "class", + "kindModifiers": "export" + }, { "text": "A", "kind": "module" @@ -19,7 +24,7 @@ verify.navigationBar([ ] }, { - "text": "default", + "text": "", "kind": "class", "kindModifiers": "export", "indent": 1 diff --git a/tests/cases/fourslash/navigationBarItemsItemsContainsNoAnonymousFunctions.ts b/tests/cases/fourslash/navigationBarItemsItemsContainsNoAnonymousFunctions.ts deleted file mode 100644 index 276e19624c92a..0000000000000 --- a/tests/cases/fourslash/navigationBarItemsItemsContainsNoAnonymousFunctions.ts +++ /dev/null @@ -1,80 +0,0 @@ -/// -// @Filename: scriptLexicalStructureItemsContainsNoAnonymouseFunctions_0.ts -/////*file1*/ -////(function() { -//// // this should not be included -//// var x = 0; -//// -//// // this should not be included either -//// function foo() { -//// -//// } -////})(); -//// -// @Filename: scriptLexicalStructureItemsContainsNoAnonymouseFunctions_1.ts -/////*file2*/ -////var x = function() { -//// // this should not be included -//// var x = 0; -//// -//// // this should not be included either -//// function foo() { -////}; -//// -// @Filename: scriptLexicalStructureItemsContainsNoAnonymouseFunctions_2.ts -////// Named functions should still show up -/////*file3*/ -////function foo() { -////} -////function bar() { -////} - -goTo.marker("file1"); -verify.navigationBar([ - { - "text": "", - "kind": "module" - } -]); - -goTo.marker("file2"); -verify.navigationBar([ - { - "text": "", - "kind": "module", - "childItems": [ - { - "text": "x", - "kind": "var" - } - ] - } -]); - -goTo.marker("file3"); -verify.navigationBar([ - { - "text": "", - "kind": "module", - "childItems": [ - { - "text": "bar", - "kind": "function" - }, - { - "text": "foo", - "kind": "function" - } - ] - }, - { - "text": "bar", - "kind": "function", - "indent": 1 - }, - { - "text": "foo", - "kind": "function", - "indent": 1 - } -]); diff --git a/tests/cases/fourslash/navigationBarItemsMissingName1.ts b/tests/cases/fourslash/navigationBarItemsMissingName1.ts index af0e89683bcfe..2a445a5e1ed61 100644 --- a/tests/cases/fourslash/navigationBarItemsMissingName1.ts +++ b/tests/cases/fourslash/navigationBarItemsMissingName1.ts @@ -8,6 +8,11 @@ verify.navigationBar([ "text": "\"navigationBarItemsMissingName1\"", "kind": "module", "childItems": [ + { + "text": "", + "kind": "function", + "kindModifiers": "export" + }, { "text": "C", "kind": "class" diff --git a/tests/cases/fourslash/navigationBarItemsMissingName2.ts b/tests/cases/fourslash/navigationBarItemsMissingName2.ts index 2eda3b07855c7..a878c5be8455b 100644 --- a/tests/cases/fourslash/navigationBarItemsMissingName2.ts +++ b/tests/cases/fourslash/navigationBarItemsMissingName2.ts @@ -9,10 +9,16 @@ verify.navigationBar([ { "text": "", - "kind": "module" + "kind": "module", + "childItems": [ + { + "text": "", + "kind": "class" + } + ] }, { - "text": "default", + "text": "", "kind": "class", "childItems": [ { diff --git a/tests/cases/fourslash/navigationBarItemsModules.ts b/tests/cases/fourslash/navigationBarItemsModules.ts index 979f22084e587..ec11cd52b942c 100644 --- a/tests/cases/fourslash/navigationBarItemsModules.ts +++ b/tests/cases/fourslash/navigationBarItemsModules.ts @@ -28,107 +28,107 @@ //The declarations of A.B.C.x do not get merged, so the 4 vars are independent. //The two 'A' modules, however, do get merged, so in reality we have 7 modules. verify.navigationBar([ - { - "text": "", - "kind": "module", - "childItems": [ - { - "text": "A.B.C", - "kind": "module" - }, - { - "text": "A.B", - "kind": "module" - }, - { - "text": "A", - "kind": "module" - }, - { - "text": "\"X.Y.Z\"", + { + "text": "", "kind": "module", - "kindModifiers": "declare" - }, - { + "childItems": [ + { + "text": "'X2.Y2.Z2'", + "kind": "module", + "kindModifiers": "declare" + }, + { + "text": "\"X.Y.Z\"", + "kind": "module", + "kindModifiers": "declare" + }, + { + "text": "A", + "kind": "module" + }, + { + "text": "A.B", + "kind": "module" + }, + { + "text": "A.B.C", + "kind": "module" + } + ] + }, + { "text": "'X2.Y2.Z2'", "kind": "module", - "kindModifiers": "declare" - } - ] - }, - { - "text": "A.B.C", - "kind": "module", - "childItems": [ - { - "text": "x", - "kind": "var", - "kindModifiers": "export" - } - ], - "indent": 1 - }, - { - "text": "A.B", - "kind": "module", - "childItems": [ - { - "text": "y", - "kind": "var", - "kindModifiers": "export" - } - ], - "indent": 1 - }, - { - "text": "A", - "kind": "module", - "childItems": [ - { - "text": "z", - "kind": "var", - "kindModifiers": "export" - }, - { + "kindModifiers": "declare", + "indent": 1 + }, + { + "text": "\"X.Y.Z\"", + "kind": "module", + "kindModifiers": "declare", + "indent": 1 + }, + { + "text": "A", + "kind": "module", + "childItems": [ + { + "text": "B", + "kind": "module" + }, + { + "text": "z", + "kind": "var", + "kindModifiers": "export" + } + ], + "indent": 1 + }, + { "text": "B", - "kind": "module" - } - ], - "indent": 1 - }, - { - "text": "B", - "kind": "module", - "childItems": [ - { + "kind": "module", + "childItems": [ + { + "text": "C", + "kind": "module" + } + ], + "indent": 2 + }, + { "text": "C", - "kind": "module" - } - ], - "indent": 2 - }, - { - "text": "C", - "kind": "module", - "childItems": [ - { - "text": "x", - "kind": "var", - "kindModifiers": "declare" - } - ], - "indent": 3 - }, - { - "text": "\"X.Y.Z\"", - "kind": "module", - "kindModifiers": "declare", - "indent": 1 - }, - { - "text": "'X2.Y2.Z2'", - "kind": "module", - "kindModifiers": "declare", - "indent": 1 - } + "kind": "module", + "childItems": [ + { + "text": "x", + "kind": "var", + "kindModifiers": "declare" + } + ], + "indent": 3 + }, + { + "text": "A.B", + "kind": "module", + "childItems": [ + { + "text": "y", + "kind": "var", + "kindModifiers": "export" + } + ], + "indent": 1 + }, + { + "text": "A.B.C", + "kind": "module", + "childItems": [ + { + "text": "x", + "kind": "var", + "kindModifiers": "export" + } + ], + "indent": 1 + } ]); diff --git a/tests/cases/fourslash/navigationBarItemsMultilineStringIdentifiers.ts b/tests/cases/fourslash/navigationBarItemsMultilineStringIdentifiers.ts index 2ee4c93a2f1fb..4a29d718f2e0a 100644 --- a/tests/cases/fourslash/navigationBarItemsMultilineStringIdentifiers.ts +++ b/tests/cases/fourslash/navigationBarItemsMultilineStringIdentifiers.ts @@ -30,20 +30,12 @@ verify.navigationBar([ "kind": "module", "childItems": [ { - "text": "Bar", - "kind": "class" - }, - { - "text": "Foo", - "kind": "interface" - }, - { - "text": "\"Multiline\\r\\nMadness\"", + "text": "\"Multiline\\\nMadness\"", "kind": "module", "kindModifiers": "declare" }, { - "text": "\"Multiline\\\nMadness\"", + "text": "\"Multiline\\r\\nMadness\"", "kind": "module", "kindModifiers": "declare" }, @@ -51,9 +43,35 @@ verify.navigationBar([ "text": "\"MultilineMadness\"", "kind": "module", "kindModifiers": "declare" + }, + { + "text": "Bar", + "kind": "class" + }, + { + "text": "Foo", + "kind": "interface" } ] }, + { + "text": "\"Multiline\\\nMadness\"", + "kind": "module", + "kindModifiers": "declare", + "indent": 1 + }, + { + "text": "\"Multiline\\r\\nMadness\"", + "kind": "module", + "kindModifiers": "declare", + "indent": 1 + }, + { + "text": "\"MultilineMadness\"", + "kind": "module", + "kindModifiers": "declare", + "indent": 1 + }, { "text": "Bar", "kind": "class", @@ -83,23 +101,5 @@ verify.navigationBar([ } ], "indent": 1 - }, - { - "text": "\"Multiline\\r\\nMadness\"", - "kind": "module", - "kindModifiers": "declare", - "indent": 1 - }, - { - "text": "\"Multiline\\\nMadness\"", - "kind": "module", - "kindModifiers": "declare", - "indent": 1 - }, - { - "text": "\"MultilineMadness\"", - "kind": "module", - "kindModifiers": "declare", - "indent": 1 } ]); diff --git a/tests/cases/fourslash/navigationBarJsDoc.ts b/tests/cases/fourslash/navigationBarJsDoc.ts index 20a235bce9505..a2d33e216bfb5 100644 --- a/tests/cases/fourslash/navigationBarJsDoc.ts +++ b/tests/cases/fourslash/navigationBarJsDoc.ts @@ -7,15 +7,31 @@ verify.navigationBar([ { - "text": "NumberLike", - "kind": "type" + "text": "", + "kind": "module", + "childItems": [ + { + "text": "NumberLike", + "kind": "type" + }, + { + "text": "x", + "kind": "const" + }, + { + "text": "x", + "kind": "type" + } + ] }, { - "text": "x", - "kind": "type" + "text": "NumberLike", + "kind": "type", + "indent": 1, }, { "text": "x", - "kind": "var" + "kind": "type", + "indent": 1 } ]); diff --git a/tests/cases/fourslash/navigationBarMerging.ts b/tests/cases/fourslash/navigationBarMerging.ts new file mode 100644 index 0000000000000..192efe5db44b5 --- /dev/null +++ b/tests/cases/fourslash/navigationBarMerging.ts @@ -0,0 +1,189 @@ +/// + +// @Filename: file1.ts +////module a { +//// function foo() {} +////} +////module b { +//// function foo() {} +////} +////module a { +//// function bar() {} +////} + +verify.navigationBar([ + { + "text": "", + "kind": "module", + "childItems": [ + { + "text": "a", + "kind": "module" + }, + { + "text": "b", + "kind": "module" + } + ] + }, + { + "text": "a", + "kind": "module", + "childItems": [ + { + "text": "bar", + "kind": "function" + }, + { + "text": "foo", + "kind": "function" + } + ], + "indent": 1 + }, + { + "text": "b", + "kind": "module", + "childItems": [ + { + "text": "foo", + "kind": "function" + } + ], + "indent": 1 + } +]); + +// Does not merge unlike declarations. +// @Filename: file2.ts +////module a {} +////function a() {} + +goTo.file("file2.ts"); +verify.navigationBar([ + { + "text": "", + "kind": "module", + "childItems": [ + { + "text": "a", + "kind": "function" + }, + { + "text": "a", + "kind": "module" + } + ] + }, + { + "text": "a", + "kind": "function", + "indent": 1 + }, + { + "text": "a", + "kind": "module", + "indent": 1 + } +]); + +// Merges recursively +// @Filename: file3.ts +////module a { +//// interface A { +//// foo: number; +//// } +////} +////module a { +//// interface A { +//// bar: number; +//// } +////} + +goTo.file("file3.ts"); +verify.navigationBar([ + { + "text": "", + "kind": "module", + "childItems": [ + { + "text": "a", + "kind": "module" + } + ] + }, + { + "text": "a", + "kind": "module", + "childItems": [ + { + "text": "A", + "kind": "interface" + } + ], + "indent": 1 + }, + { + "text": "A", + "kind": "interface", + "childItems": [ + { + "text": "bar", + "kind": "property" + }, + { + "text": "foo", + "kind": "property" + } + ], + "indent": 2 + } +]); + +// Does not merge 'module A' with 'module A.B' + +// @Filename: file4.ts +////module A { export var x; } +////module A.B { export var y; } + +goTo.file("file4.ts"); +verify.navigationBar([ + { + "text": "", + "kind": "module", + "childItems": [ + { + "text": "A", + "kind": "module" + }, + { + "text": "A.B", + "kind": "module" + } + ] + }, + { + "text": "A", + "kind": "module", + "childItems": [ + { + "text": "x", + "kind": "var", + "kindModifiers": "export" + } + ], + "indent": 1 + }, + { + "text": "A.B", + "kind": "module", + "childItems": [ + { + "text": "y", + "kind": "var", + "kindModifiers": "export" + } + ], + "indent": 1 + } +]); diff --git a/tests/cases/fourslash/navigationBarVariables.ts b/tests/cases/fourslash/navigationBarVariables.ts new file mode 100644 index 0000000000000..42344c96f73df --- /dev/null +++ b/tests/cases/fourslash/navigationBarVariables.ts @@ -0,0 +1,53 @@ +/// + +////var x = 0; +////let y = 1; +////const z = 2; + +verify.navigationBar([ + { + "text": "", + "kind": "module", + "childItems": [ + { + "text": "x", + "kind": "var" + }, + { + "text": "y", + "kind": "let" + }, + { + "text": "z", + "kind": "const" + } + ] + } +]); + +// @Filename: file2.ts +////var {a} = 0; +////let {a: b} = 0; +////const [c] = 0; + +goTo.file("file2.ts"); +verify.navigationBar([ + { + "text": "", + "kind": "module", + "childItems": [ + { + "text": "a", + "kind": "var" + }, + { + "text": "b", + "kind": "let" + }, + { + "text": "c", + "kind": "const" + } + ] + } +]); diff --git a/tests/cases/fourslash/server/jsdocTypedefTagNavigateTo.ts b/tests/cases/fourslash/server/jsdocTypedefTagNavigateTo.ts index 77cd75aa44c77..1c617091f4c27 100644 --- a/tests/cases/fourslash/server/jsdocTypedefTagNavigateTo.ts +++ b/tests/cases/fourslash/server/jsdocTypedefTagNavigateTo.ts @@ -11,20 +11,36 @@ //// var numberLike; verify.navigationBar([ - { - "text": "NumberLike", - "kind": "type" - }, - { - "text": "NumberLike2", - "kind": "type" - }, - { - "text": "NumberLike2", - "kind": "var" - }, - { - "text": "numberLike", - "kind": "var" - } + { + "text": "", + "kind": "module", + "childItems": [ + { + "text": "numberLike", + "kind": "var" + }, + { + "text": "NumberLike", + "kind": "type" + }, + { + "text": "NumberLike2", + "kind": "var" + }, + { + "text": "NumberLike2", + "kind": "type" + } + ] + }, + { + "text": "NumberLike", + "kind": "type", + "indent": 1, + }, + { + "text": "NumberLike2", + "kind": "type", + "indent": 1 + } ]); \ No newline at end of file diff --git a/tests/cases/unittests/cachingInServerLSHost.ts b/tests/cases/unittests/cachingInServerLSHost.ts index 08cd5366f11e5..2b19ee8da5b4f 100644 --- a/tests/cases/unittests/cachingInServerLSHost.ts +++ b/tests/cases/unittests/cachingInServerLSHost.ts @@ -48,7 +48,7 @@ namespace ts { }, getDirectories: (path: string) => [], getEnvironmentVariable: (name: string) => "", - readDirectory: (path: string, extension?: string, exclude?: string[]): string[] => { + readDirectory: (path: string, extension?: string[], exclude?: string[], include?: string[]): string[] => { throw new Error("NYI"); }, exit: (exitCode?: number) => { @@ -146,6 +146,7 @@ namespace ts { catch (e) { assert.isTrue(e.message.indexOf(`Could not find file: '${imported.name}'.`) === 0); } + assert.isTrue(fileExistsIsCalled); } { @@ -221,4 +222,4 @@ namespace ts { assert.isTrue(diags.length === 0); }); }); -} +} \ No newline at end of file diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 0988d51e11b26..741c9e54cada7 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -647,7 +647,7 @@ module m3 { }\ const oldText = ScriptSnapshot.fromString(source); const newTextAndChange = withInsert(oldText, 0, ""); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 8); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 7); }); it("Class to interface", () => { diff --git a/tests/cases/unittests/matchFiles.ts b/tests/cases/unittests/matchFiles.ts new file mode 100644 index 0000000000000..b9c538a9e14dd --- /dev/null +++ b/tests/cases/unittests/matchFiles.ts @@ -0,0 +1,956 @@ +/// +/// +/// + +namespace ts { + const caseInsensitiveBasePath = "c:/dev/"; + const caseInsensitiveHost = new Utils.MockParseConfigHost(caseInsensitiveBasePath, /*useCaseSensitiveFileNames*/ false, [ + "c:/dev/a.ts", + "c:/dev/a.d.ts", + "c:/dev/a.js", + "c:/dev/b.ts", + "c:/dev/b.js", + "c:/dev/c.d.ts", + "c:/dev/z/a.ts", + "c:/dev/z/abz.ts", + "c:/dev/z/aba.ts", + "c:/dev/z/b.ts", + "c:/dev/z/bbz.ts", + "c:/dev/z/bba.ts", + "c:/dev/x/a.ts", + "c:/dev/x/aa.ts", + "c:/dev/x/b.ts", + "c:/dev/x/y/a.ts", + "c:/dev/x/y/b.ts", + "c:/dev/js/a.js", + "c:/dev/js/b.js", + "c:/ext/ext.ts" + ]); + + const caseSensitiveBasePath = "/dev/"; + const caseSensitiveHost = new Utils.MockParseConfigHost(caseSensitiveBasePath, /*useCaseSensitiveFileNames*/ true, [ + "/dev/a.ts", + "/dev/a.d.ts", + "/dev/a.js", + "/dev/b.ts", + "/dev/b.js", + "/dev/A.ts", + "/dev/B.ts", + "/dev/c.d.ts", + "/dev/z/a.ts", + "/dev/z/abz.ts", + "/dev/z/aba.ts", + "/dev/z/b.ts", + "/dev/z/bbz.ts", + "/dev/z/bba.ts", + "/dev/x/a.ts", + "/dev/x/b.ts", + "/dev/x/y/a.ts", + "/dev/x/y/b.ts", + "/dev/js/a.js", + "/dev/js/b.js", + ]); + + const caseInsensitiveMixedExtensionHost = new Utils.MockParseConfigHost(caseInsensitiveBasePath, /*useCaseSensitiveFileNames*/ false, [ + "c:/dev/a.ts", + "c:/dev/a.d.ts", + "c:/dev/a.js", + "c:/dev/b.tsx", + "c:/dev/b.d.ts", + "c:/dev/b.jsx", + "c:/dev/c.tsx", + "c:/dev/c.js", + "c:/dev/d.js", + "c:/dev/e.jsx", + "c:/dev/f.other" + ]); + + const caseInsensitiveCommonFoldersHost = new Utils.MockParseConfigHost(caseInsensitiveBasePath, /*useCaseSensitiveFileNames*/ false, [ + "c:/dev/a.ts", + "c:/dev/a.d.ts", + "c:/dev/a.js", + "c:/dev/b.ts", + "c:/dev/node_modules/a.ts", + "c:/dev/bower_components/a.ts", + "c:/dev/jspm_packages/a.ts" + ]); + + describe("matchFiles", () => { + describe("with literal file list", () => { + it("without exclusions", () => { + const json = { + files: [ + "a.ts", + "b.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.ts" + ], + wildcardDirectories: {}, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("missing files are still present", () => { + const json = { + files: [ + "z.ts", + "x.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/z.ts", + "c:/dev/x.ts" + ], + wildcardDirectories: {}, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("are not removed due to excludes", () => { + const json = { + files: [ + "a.ts", + "b.ts" + ], + exclude: [ + "b.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.ts" + ], + wildcardDirectories: {}, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + }); + + describe("with literal include list", () => { + it("without exclusions", () => { + const json = { + include: [ + "a.ts", + "b.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.ts" + ], + wildcardDirectories: {}, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("with non .ts file extensions are excluded", () => { + const json = { + include: [ + "a.js", + "b.js" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [], + wildcardDirectories: {}, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("with missing files are excluded", () => { + const json = { + include: [ + "z.ts", + "x.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [], + wildcardDirectories: {}, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("with literal excludes", () => { + const json = { + include: [ + "a.ts", + "b.ts" + ], + exclude: [ + "b.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts" + ], + wildcardDirectories: {}, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("with wildcard excludes", () => { + const json = { + include: [ + "a.ts", + "b.ts", + "z/a.ts", + "z/abz.ts", + "z/aba.ts", + "x/b.ts" + ], + exclude: [ + "*.ts", + "z/??z.ts", + "*/b.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/z/a.ts", + "c:/dev/z/aba.ts" + ], + wildcardDirectories: {}, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("with recursive excludes", () => { + const json = { + include: [ + "a.ts", + "b.ts", + "x/a.ts", + "x/b.ts", + "x/y/a.ts", + "x/y/b.ts" + ], + exclude: [ + "**/b.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/x/a.ts", + "c:/dev/x/y/a.ts" + ], + wildcardDirectories: {}, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("with case sensitive exclude", () => { + const json = { + include: [ + "B.ts" + ], + exclude: [ + "**/b.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "/dev/B.ts" + ], + wildcardDirectories: {}, + }; + const actual = ts.parseJsonConfigFileContent(json, caseSensitiveHost, caseSensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("with common package folders and no exclusions", () => { + const json = { + include: [ + "a.ts", + "b.ts", + "node_modules/a.ts", + "bower_components/a.ts", + "jspm_packages/a.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.ts" + ], + wildcardDirectories: {}, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("with common package folders and exclusions", () => { + const json = { + include: [ + "a.ts", + "b.ts", + "node_modules/a.ts", + "bower_components/a.ts", + "jspm_packages/a.ts" + ], + exclude: [ + "a.ts", + "b.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/bower_components/a.ts", + "c:/dev/jspm_packages/a.ts", + "c:/dev/node_modules/a.ts" + ], + wildcardDirectories: {}, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("with common package folders and empty exclude", () => { + const json = { + include: [ + "a.ts", + "b.ts", + "node_modules/a.ts", + "bower_components/a.ts", + "jspm_packages/a.ts" + ], + exclude: [] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.ts", + "c:/dev/bower_components/a.ts", + "c:/dev/jspm_packages/a.ts", + "c:/dev/node_modules/a.ts" + ], + wildcardDirectories: {}, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + }); + + describe("with wildcard include list", () => { + it("same named declarations are excluded", () => { + const json = { + include: [ + "*.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.ts", + "c:/dev/c.d.ts" + ], + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.None + }, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("`*` matches only ts files", () => { + const json = { + include: [ + "*" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.ts", + "c:/dev/c.d.ts" + ], + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.None + }, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("`?` matches only a single character", () => { + const json = { + include: [ + "x/?.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/x/a.ts", + "c:/dev/x/b.ts" + ], + wildcardDirectories: { + "c:/dev/x": ts.WatchDirectoryFlags.None + }, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("with recursive directory", () => { + const json = { + include: [ + "**/a.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/x/a.ts", + "c:/dev/x/y/a.ts", + "c:/dev/z/a.ts" + ], + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.Recursive + }, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("with multiple recursive directories", () => { + const json = { + include: [ + "x/y/**/a.ts", + "x/**/a.ts", + "z/**/a.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/x/a.ts", + "c:/dev/x/y/a.ts", + "c:/dev/z/a.ts" + ], + wildcardDirectories: { + "c:/dev/x": ts.WatchDirectoryFlags.Recursive, + "c:/dev/z": ts.WatchDirectoryFlags.Recursive + }, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("case sensitive", () => { + const json = { + include: [ + "**/A.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "/dev/A.ts" + ], + wildcardDirectories: { + "/dev": ts.WatchDirectoryFlags.Recursive + }, + }; + const actual = ts.parseJsonConfigFileContent(json, caseSensitiveHost, caseSensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("with missing files are excluded", () => { + const json = { + include: [ + "*/z.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [], + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.Recursive + }, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("always include literal files", () => { + const json = { + files: [ + "a.ts" + ], + include: [ + "*/z.ts" + ], + exclude: [ + "**/a.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts" + ], + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.Recursive + }, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("exclude folders", () => { + const json = { + include: [ + "**/*" + ], + exclude: [ + "z", + "x" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.ts", + "c:/dev/c.d.ts" + ], + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.Recursive + } + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("with common package folders and no exclusions", () => { + const json = { + include: [ + "**/a.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts" + ], + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.Recursive + }, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("with common package folders and exclusions", () => { + const json = { + include: [ + "**/a.ts" + ], + exclude: [ + "a.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/bower_components/a.ts", + "c:/dev/jspm_packages/a.ts", + "c:/dev/node_modules/a.ts" + ], + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.Recursive + }, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("with common package folders and empty exclude", () => { + const json = { + include: [ + "**/a.ts" + ], + exclude: [] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/bower_components/a.ts", + "c:/dev/jspm_packages/a.ts", + "c:/dev/node_modules/a.ts" + ], + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.Recursive + }, + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("exclude .js files when allowJs=false", () => { + const json = { + compilerOptions: { + allowJs: false + }, + include: [ + "js/*" + ] + }; + const expected: ts.ParsedCommandLine = { + options: { + allowJs: false + }, + errors: [], + fileNames: [], + wildcardDirectories: { + "c:/dev/js": ts.WatchDirectoryFlags.None + } + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("include .js files when allowJs=true", () => { + const json = { + compilerOptions: { + allowJs: true + }, + include: [ + "js/*" + ] + }; + const expected: ts.ParsedCommandLine = { + options: { + allowJs: true + }, + errors: [], + fileNames: [ + "c:/dev/js/a.js", + "c:/dev/js/b.js" + ], + wildcardDirectories: { + "c:/dev/js": ts.WatchDirectoryFlags.None + } + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("include paths outside of the project", () => { + const json = { + include: [ + "*", + "c:/ext/*" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.ts", + "c:/dev/c.d.ts", + "c:/ext/ext.ts", + ], + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.None, + "c:/ext": ts.WatchDirectoryFlags.None + } + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("with jsx=none, allowJs=false", () => { + const json = { + compilerOptions: { + allowJs: false + } + }; + const expected: ts.ParsedCommandLine = { + options: { + allowJs: false + }, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.tsx", + "c:/dev/c.tsx", + ], + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.Recursive + } + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("with jsx=preserve, allowJs=false", () => { + const json = { + compilerOptions: { + jsx: "preserve", + allowJs: false + } + }; + const expected: ts.ParsedCommandLine = { + options: { + jsx: ts.JsxEmit.Preserve, + allowJs: false + }, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.tsx", + "c:/dev/c.tsx", + ], + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.Recursive + } + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("with jsx=none, allowJs=true", () => { + const json = { + compilerOptions: { + allowJs: true + } + }; + const expected: ts.ParsedCommandLine = { + options: { + allowJs: true + }, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.tsx", + "c:/dev/c.tsx", + "c:/dev/d.js", + "c:/dev/e.jsx", + ], + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.Recursive + } + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("with jsx=preserve, allowJs=true", () => { + const json = { + compilerOptions: { + jsx: "preserve", + allowJs: true + } + }; + const expected: ts.ParsedCommandLine = { + options: { + jsx: ts.JsxEmit.Preserve, + allowJs: true + }, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.tsx", + "c:/dev/c.tsx", + "c:/dev/d.js", + "c:/dev/e.jsx", + ], + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.Recursive + } + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + describe("with trailing recursive directory", () => { + it("in includes", () => { + const json = { + include: [ + "**" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [ + ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**") + ], + fileNames: [], + wildcardDirectories: {} + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("in excludes", () => { + const json = { + include: [ + "**/*" + ], + exclude: [ + "**" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [], + wildcardDirectories: {} + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + }); + describe("with multiple recursive directory patterns", () => { + it("in includes", () => { + const json = { + include: [ + "**/x/**/*" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [ + ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, "**/x/**/*") + ], + fileNames: [], + wildcardDirectories: {} + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + it("in excludes", () => { + const json = { + include: [ + "**/a.ts" + ], + exclude: [ + "**/x/**" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [ + ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, "**/x/**") + ], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/x/a.ts", + "c:/dev/x/y/a.ts", + "c:/dev/z/a.ts" + ], + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.Recursive + } + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + }); + }); + }); + }); +} \ No newline at end of file diff --git a/tests/cases/unittests/transpile.ts b/tests/cases/unittests/transpile.ts index e103416c9851c..b60a0aaf79321 100644 --- a/tests/cases/unittests/transpile.ts +++ b/tests/cases/unittests/transpile.ts @@ -118,8 +118,8 @@ namespace ts { transpilesCorrectly("Generates no diagnostics for missing file references", `/// var x = 0;`, { - options: { compilerOptions: { module: ModuleKind.CommonJS } } - }); + options: { compilerOptions: { module: ModuleKind.CommonJS } } + }); transpilesCorrectly("Generates no diagnostics for missing module imports", `import {a} from "module2";`, { options: { compilerOptions: { module: ModuleKind.CommonJS } } @@ -153,22 +153,22 @@ var x = 0;`, { `import {foo} from "SomeName";\n` + `declare function use(a: any);\n` + `use(foo);`, { - options: { compilerOptions: { module: ModuleKind.System, newLine: NewLineKind.LineFeed }, renamedDependencies: { "SomeName": "SomeOtherName" } } - }); + options: { compilerOptions: { module: ModuleKind.System, newLine: NewLineKind.LineFeed }, renamedDependencies: { "SomeName": "SomeOtherName" } } + }); transpilesCorrectly("Rename dependencies - AMD", `import {foo} from "SomeName";\n` + `declare function use(a: any);\n` + `use(foo);`, { - options: { compilerOptions: { module: ModuleKind.AMD, newLine: NewLineKind.LineFeed }, renamedDependencies: { "SomeName": "SomeOtherName" } } - }); + options: { compilerOptions: { module: ModuleKind.AMD, newLine: NewLineKind.LineFeed }, renamedDependencies: { "SomeName": "SomeOtherName" } } + }); transpilesCorrectly("Rename dependencies - UMD", `import {foo} from "SomeName";\n` + `declare function use(a: any);\n` + `use(foo);`, { - options: { compilerOptions: { module: ModuleKind.UMD, newLine: NewLineKind.LineFeed }, renamedDependencies: { "SomeName": "SomeOtherName" } } - }); + options: { compilerOptions: { module: ModuleKind.UMD, newLine: NewLineKind.LineFeed }, renamedDependencies: { "SomeName": "SomeOtherName" } } + }); transpilesCorrectly("Transpile with emit decorators and emit metadata", `import {db} from './db';\n` + @@ -184,17 +184,17 @@ var x = 0;`, { ` }\n` + `}\n` + `export {MyClass}; \n`, { - options: { - compilerOptions: { - module: ModuleKind.CommonJS, - newLine: NewLineKind.LineFeed, - noEmitHelpers: true, - emitDecoratorMetadata: true, - experimentalDecorators: true, - target: ScriptTarget.ES5, + options: { + compilerOptions: { + module: ModuleKind.CommonJS, + newLine: NewLineKind.LineFeed, + noEmitHelpers: true, + emitDecoratorMetadata: true, + experimentalDecorators: true, + target: ScriptTarget.ES5, + } } - } - }); + }); transpilesCorrectly("Supports backslashes in file name", "var x", { options: { fileName: "a\\b.ts" } @@ -213,15 +213,17 @@ var x = 0;`, { }); transpilesCorrectly("Accepts string as enum values for compile-options", "export const x = 0", { - options: { compilerOptions: { - module: "es6", - // Capitalization and spaces ignored - target: " Es6 " - }} + options: { + compilerOptions: { + module: "es6", + // Capitalization and spaces ignored + target: " Es6 " + } + } }); transpilesCorrectly("Report an error when compiler-options module-kind is out-of-range", "", { - options: { compilerOptions: { module: 123 }} + options: { compilerOptions: { module: 123 } } }); transpilesCorrectly("Report an error when compiler-options target-script is out-of-range", "", { @@ -244,5 +246,196 @@ var x = 0;`, { options: { compilerOptions: { types: ["jquery", "typescript"], module: ModuleKind.CommonJS }, fileName: "input.js", reportDiagnostics: true } }); - }); + transpilesCorrectly("Supports setting 'allowJs'", "x;", { + options: { compilerOptions: { allowJs: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'allowSyntheticDefaultImports'", "x;", { + options: { compilerOptions: { allowSyntheticDefaultImports: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'allowUnreachableCode'", "x;", { + options: { compilerOptions: { allowUnreachableCode: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'allowUnusedLabels'", "x;", { + options: { compilerOptions: { allowUnusedLabels: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'baseUrl'", "x;", { + options: { compilerOptions: { baseUrl: "./folder/baseUrl" }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'charset'", "x;", { + options: { compilerOptions: { charset: "en-us" }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'declaration'", "x;", { + options: { compilerOptions: { declaration: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'declarationDir'", "x;", { + options: { compilerOptions: { declarationDir: "out/declarations" }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'emitBOM'", "x;", { + options: { compilerOptions: { emitBOM: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'emitDecoratorMetadata'", "x;", { + options: { compilerOptions: { emitDecoratorMetadata: true, experimentalDecorators: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'experimentalDecorators'", "x;", { + options: { compilerOptions: { experimentalDecorators: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'forceConsistentCasingInFileNames'", "x;", { + options: { compilerOptions: { forceConsistentCasingInFileNames: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'isolatedModules'", "x;", { + options: { compilerOptions: { isolatedModules: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'jsx'", "x;", { + options: { compilerOptions: { jsx: 1 }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'lib'", "x;", { + options: { compilerOptions: { lib: ["es2015", "dom"] }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'locale'", "x;", { + options: { compilerOptions: { locale: "en-us" }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'module'", "x;", { + options: { compilerOptions: { module: ModuleKind.CommonJS }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'moduleResolution'", "x;", { + options: { compilerOptions: { moduleResolution: ModuleResolutionKind.NodeJs }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'newLine'", "x;", { + options: { compilerOptions: { newLine: NewLineKind.CarriageReturnLineFeed }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'noEmit'", "x;", { + options: { compilerOptions: { noEmit: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'noEmitHelpers'", "x;", { + options: { compilerOptions: { noEmitHelpers: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'noEmitOnError'", "x;", { + options: { compilerOptions: { noEmitOnError: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'noErrorTruncation'", "x;", { + options: { compilerOptions: { noErrorTruncation: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'noFallthroughCasesInSwitch'", "x;", { + options: { compilerOptions: { noFallthroughCasesInSwitch: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'noImplicitAny'", "x;", { + options: { compilerOptions: { noImplicitAny: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'noImplicitReturns'", "x;", { + options: { compilerOptions: { noImplicitReturns: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'noImplicitThis'", "x;", { + options: { compilerOptions: { noImplicitThis: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'noImplicitUseStrict'", "x;", { + options: { compilerOptions: { noImplicitUseStrict: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'noLib'", "x;", { + options: { compilerOptions: { noLib: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'noResolve'", "x;", { + options: { compilerOptions: { noResolve: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'out'", "x;", { + options: { compilerOptions: { out: "./out" }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'outDir'", "x;", { + options: { compilerOptions: { outDir: "./outDir" }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'outFile'", "x;", { + options: { compilerOptions: { outFile: "./outFile" }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'paths'", "x;", { + options: { compilerOptions: { paths: { "*": ["./generated*"] } }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'preserveConstEnums'", "x;", { + options: { compilerOptions: { preserveConstEnums: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'reactNamespace'", "x;", { + options: { compilerOptions: { reactNamespace: "react" }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'removeComments'", "x;", { + options: { compilerOptions: { removeComments: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'rootDir'", "x;", { + options: { compilerOptions: { rootDir: "./rootDir" }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'rootDirs'", "x;", { + options: { compilerOptions: { rootDirs: ["./a", "./b"] }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'skipLibCheck'", "x;", { + options: { compilerOptions: { skipLibCheck: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'skipDefaultLibCheck'", "x;", { + options: { compilerOptions: { skipDefaultLibCheck: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'strictNullChecks'", "x;", { + options: { compilerOptions: { strictNullChecks: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'stripInternal'", "x;", { + options: { compilerOptions: { stripInternal: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'suppressExcessPropertyErrors'", "x;", { + options: { compilerOptions: { suppressExcessPropertyErrors: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'suppressImplicitAnyIndexErrors'", "x;", { + options: { compilerOptions: { suppressImplicitAnyIndexErrors: true }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'target'", "x;", { + options: { compilerOptions: { target: 2 }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'types'", "x;", { + options: { compilerOptions: { types: ["jquery", "jasmine"] }, fileName: "input.js", reportDiagnostics: true } + }); + + transpilesCorrectly("Supports setting 'typeRoots'", "x;", { + options: { compilerOptions: { typeRoots: ["./folder"] }, fileName: "input.js", reportDiagnostics: true } + }); + }); } diff --git a/tests/cases/unittests/tsconfigParsing.ts b/tests/cases/unittests/tsconfigParsing.ts index 31600a38e51ce..17ccf6bff891c 100644 --- a/tests/cases/unittests/tsconfigParsing.ts +++ b/tests/cases/unittests/tsconfigParsing.ts @@ -16,36 +16,16 @@ namespace ts { function assertParseErrorWithExcludesKeyword(jsonText: string) { const parsed = ts.parseConfigFileTextToJson("/apath/tsconfig.json", jsonText); - const parsedCommand = ts.parseJsonConfigFileContent(parsed, ts.sys, "tests/cases/unittests"); - assert.isTrue(undefined !== parsedCommand.errors); + const parsedCommand = ts.parseJsonConfigFileContent(parsed.config, ts.sys, "tests/cases/unittests"); + assert.isTrue(parsedCommand.errors && parsedCommand.errors.length === 1 && + parsedCommand.errors[0].code === ts.Diagnostics.Unknown_option_excludes_Did_you_mean_exclude.code); } function assertParseFileList(jsonText: string, configFileName: string, basePath: string, allFileList: string[], expectedFileList: string[]) { const json = JSON.parse(jsonText); - const host: ParseConfigHost = { readDirectory: mockReadDirectory }; + const host: ParseConfigHost = new Utils.MockParseConfigHost(basePath, true, allFileList); const parsed = ts.parseJsonConfigFileContent(json, host, basePath, /*existingOptions*/ undefined, configFileName); assert.isTrue(arrayIsEqualTo(parsed.fileNames.sort(), expectedFileList.sort())); - - function mockReadDirectory(rootDir: string, extension: string, exclude: string[]): string[] { - const result: string[] = []; - const fullExcludeDirectories = ts.map(exclude, directory => combinePaths(rootDir, directory)); - for (const file of allFileList) { - let shouldExclude = false; - for (const fullExcludeDirectorie of fullExcludeDirectories) { - if (file.indexOf(fullExcludeDirectorie) >= 0) { - shouldExclude = true; - break; - } - } - if (shouldExclude) { - continue; - } - if (fileExtensionIs(file, extension)) { - result.push(file); - } - } - return result; - } } it("returns empty config for file with only whitespaces", () => { @@ -121,19 +101,19 @@ namespace ts { assertParseResult( `{ "compilerOptions": { - "lib": "es5" + "lib": ["es5"] } }`, { - config: { compilerOptions: { lib: "es5" } } + config: { compilerOptions: { lib: ["es5"] } } }); assertParseResult( `{ "compilerOptions": { - "lib": "es5,es6" + "lib": ["es5", "es6"] } }`, { - config: { compilerOptions: { lib: "es5,es6" } } + config: { compilerOptions: { lib: ["es5", "es6"] } } }); }); @@ -141,7 +121,7 @@ namespace ts { assertParseErrorWithExcludesKeyword( `{ "compilerOptions": { - "lib": "es5" + "lib": ["es5"] }, "excludes": [ "foge.ts" diff --git a/tests/cases/unittests/tsserverProjectSystem.ts b/tests/cases/unittests/tsserverProjectSystem.ts index 790730160e282..7e40b2d17198f 100644 --- a/tests/cases/unittests/tsserverProjectSystem.ts +++ b/tests/cases/unittests/tsserverProjectSystem.ts @@ -92,23 +92,6 @@ namespace ts { } } - function readDirectory(folder: FSEntry, ext: string, excludes: Path[], result: string[]): void { - if (!folder || !isFolder(folder) || contains(excludes, folder.path)) { - return; - } - for (const entry of folder.entries) { - if (contains(excludes, entry.path)) { - continue; - } - if (isFolder(entry)) { - readDirectory(entry, ext, excludes, result); - } - else if (fileExtensionIs(entry.path, ext)) { - result.push(entry.fullPath); - } - } - } - function checkNumberOfConfiguredProjects(projectService: server.ProjectService, expected: number) { assert.equal(projectService.configuredProjects.length, expected, `expected ${expected} configured project(s)`); } @@ -201,10 +184,26 @@ namespace ts { } } - readDirectory(path: string, ext: string, excludes: string[]): string[] { - const result: string[] = []; - readDirectory(this.fs.get(this.toPath(path)), ext, map(excludes, e => toPath(e, path, this.getCanonicalFileName)), result); - return result; + readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[]): string[] { + const that = this; + return ts.matchFiles(path, extensions, exclude, include, this.useCaseSensitiveFileNames, this.getCurrentDirectory(), (dir) => { + const result: FileSystemEntries = { + directories: [], + files : [] + }; + const dirEntry = that.fs.get(that.toPath(dir)); + if (isFolder(dirEntry)) { + dirEntry.entries.forEach((entry) => { + if (isFolder(entry)) { + result.directories.push(entry.fullPath); + } + else if (isFile(entry)) { + result.files.push(entry.fullPath); + } + }); + } + return result; + }); } watchDirectory(directoryName: string, callback: DirectoryWatcherCallback, recursive: boolean): DirectoryWatcher {