Merge remote-tracking branch 'origin/master' into tsserverVS-WIP
This commit is contained in:
commit
8e6f36258e
|
@ -154,7 +154,8 @@ var harnessSources = harnessCoreSources.concat([
|
|||
"tsconfigParsing.ts",
|
||||
"commandLineParsing.ts",
|
||||
"convertCompilerOptionsFromJson.ts",
|
||||
"convertTypingOptionsFromJson.ts"
|
||||
"convertTypingOptionsFromJson.ts",
|
||||
"tsserverProjectSystem.ts"
|
||||
].map(function (f) {
|
||||
return path.join(unittestsDirectory, f);
|
||||
})).concat([
|
||||
|
|
|
@ -77,12 +77,14 @@ namespace ts {
|
|||
// Blocks (when not parented by functions), Catch clauses, For/For-in/For-of statements...
|
||||
IsBlockScopedContainer = 1 << 1,
|
||||
|
||||
HasLocals = 1 << 2,
|
||||
// The current node is the container of a control flow path. The current control flow should
|
||||
// be saved and restored, and a new control flow initialized within the container.
|
||||
IsControlFlowContainer = 1 << 2,
|
||||
|
||||
// If the current node is a container that also container that also contains locals. Examples:
|
||||
//
|
||||
// Functions, Methods, Modules, Source-files.
|
||||
IsContainerWithLocals = IsContainer | HasLocals
|
||||
IsFunctionLike = 1 << 3,
|
||||
IsFunctionExpression = 1 << 4,
|
||||
HasLocals = 1 << 5,
|
||||
IsInterface = 1 << 6,
|
||||
}
|
||||
|
||||
const binder = createBinder();
|
||||
|
@ -103,22 +105,19 @@ namespace ts {
|
|||
let lastContainer: Node;
|
||||
let seenThisKeyword: boolean;
|
||||
|
||||
// state used by reachability checks
|
||||
let hasExplicitReturn: boolean;
|
||||
// state used by control flow analysis
|
||||
let currentFlow: FlowNode;
|
||||
let currentBreakTarget: FlowLabel;
|
||||
let currentContinueTarget: FlowLabel;
|
||||
let currentReturnTarget: FlowLabel;
|
||||
let currentTrueTarget: FlowLabel;
|
||||
let currentFalseTarget: FlowLabel;
|
||||
let preSwitchCaseFlow: FlowNode;
|
||||
let activeLabels: ActiveLabel[];
|
||||
let hasExplicitReturn: boolean;
|
||||
|
||||
// state used for emit helpers
|
||||
let hasClassExtends: boolean;
|
||||
let hasAsyncFunctions: boolean;
|
||||
let hasDecorators: boolean;
|
||||
let hasParameterDecorators: boolean;
|
||||
let hasJsxSpreadAttribute: boolean;
|
||||
let emitFlags: NodeFlags;
|
||||
|
||||
// If this file is an external module, then it is automatically in strict-mode according to
|
||||
// ES6. If it is not an external module, then we'll determine if it is in strict mode or
|
||||
|
@ -156,18 +155,15 @@ namespace ts {
|
|||
blockScopeContainer = undefined;
|
||||
lastContainer = undefined;
|
||||
seenThisKeyword = false;
|
||||
hasExplicitReturn = false;
|
||||
currentFlow = undefined;
|
||||
currentBreakTarget = undefined;
|
||||
currentContinueTarget = undefined;
|
||||
currentReturnTarget = undefined;
|
||||
currentTrueTarget = undefined;
|
||||
currentFalseTarget = undefined;
|
||||
activeLabels = undefined;
|
||||
hasClassExtends = false;
|
||||
hasAsyncFunctions = false;
|
||||
hasDecorators = false;
|
||||
hasParameterDecorators = false;
|
||||
hasJsxSpreadAttribute = false;
|
||||
hasExplicitReturn = false;
|
||||
emitFlags = NodeFlags.None;
|
||||
}
|
||||
|
||||
return bindSourceFile;
|
||||
|
@ -267,6 +263,18 @@ namespace ts {
|
|||
let functionType = <JSDocFunctionType>node.parent;
|
||||
let index = indexOf(functionType.parameters, node);
|
||||
return "p" + index;
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
const parentNode = node.parent && node.parent.parent;
|
||||
let nameFromParentNode: string;
|
||||
if (parentNode && parentNode.kind === SyntaxKind.VariableStatement) {
|
||||
if ((<VariableStatement>parentNode).declarationList.declarations.length > 0) {
|
||||
const nameIdentifier = (<VariableStatement>parentNode).declarationList.declarations[0].name;
|
||||
if (nameIdentifier.kind === SyntaxKind.Identifier) {
|
||||
nameFromParentNode = (<Identifier>nameIdentifier).text;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nameFromParentNode;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -400,17 +408,13 @@ namespace ts {
|
|||
// All container nodes are kept on a linked list in declaration order. This list is used by
|
||||
// the getLocalNameOfContainer function in the type checker to validate that the local name
|
||||
// used for a container is unique.
|
||||
function bindChildren(node: Node) {
|
||||
function bindContainer(node: Node, containerFlags: ContainerFlags) {
|
||||
// Before we recurse into a node's children, we first save the existing parent, container
|
||||
// and block-container. Then after we pop out of processing the children, we restore
|
||||
// these saved values.
|
||||
const saveParent = parent;
|
||||
const saveContainer = container;
|
||||
const savedBlockScopeContainer = blockScopeContainer;
|
||||
|
||||
// This node will now be set as the parent of all of its children as we recurse into them.
|
||||
parent = node;
|
||||
|
||||
// Depending on what kind of node this is, we may have to adjust the current container
|
||||
// and block-container. If the current node is a container, then it is automatically
|
||||
// considered the current block-container as well. Also, for containers that we know
|
||||
|
@ -428,115 +432,90 @@ namespace ts {
|
|||
// reusing a node from a previous compilation, that node may have had 'locals' created
|
||||
// for it. We must clear this so we don't accidentally move any stale data forward from
|
||||
// a previous compilation.
|
||||
const containerFlags = getContainerFlags(node);
|
||||
if (containerFlags & ContainerFlags.IsContainer) {
|
||||
container = blockScopeContainer = node;
|
||||
|
||||
if (containerFlags & ContainerFlags.HasLocals) {
|
||||
container.locals = {};
|
||||
}
|
||||
|
||||
addToContainerChain(container);
|
||||
}
|
||||
else if (containerFlags & ContainerFlags.IsBlockScopedContainer) {
|
||||
blockScopeContainer = node;
|
||||
blockScopeContainer.locals = undefined;
|
||||
}
|
||||
|
||||
let savedHasExplicitReturn: boolean;
|
||||
let savedCurrentFlow: FlowNode;
|
||||
let savedBreakTarget: FlowLabel;
|
||||
let savedContinueTarget: FlowLabel;
|
||||
let savedActiveLabels: ActiveLabel[];
|
||||
|
||||
const kind = node.kind;
|
||||
let flags = node.flags;
|
||||
|
||||
// reset all reachability check related flags on node (for incremental scenarios)
|
||||
flags &= ~NodeFlags.ReachabilityCheckFlags;
|
||||
|
||||
// reset all emit helper flags on node (for incremental scenarios)
|
||||
flags &= ~NodeFlags.EmitHelperFlags;
|
||||
|
||||
if (kind === SyntaxKind.InterfaceDeclaration) {
|
||||
seenThisKeyword = false;
|
||||
}
|
||||
|
||||
const saveState = kind === SyntaxKind.SourceFile || kind === SyntaxKind.ModuleBlock || isFunctionLikeKind(kind);
|
||||
if (saveState) {
|
||||
savedHasExplicitReturn = hasExplicitReturn;
|
||||
savedCurrentFlow = currentFlow;
|
||||
savedBreakTarget = currentBreakTarget;
|
||||
savedContinueTarget = currentContinueTarget;
|
||||
savedActiveLabels = activeLabels;
|
||||
|
||||
hasExplicitReturn = false;
|
||||
currentFlow = { flags: FlowFlags.Start };
|
||||
if (containerFlags & ContainerFlags.IsControlFlowContainer) {
|
||||
const saveCurrentFlow = currentFlow;
|
||||
const saveBreakTarget = currentBreakTarget;
|
||||
const saveContinueTarget = currentContinueTarget;
|
||||
const saveReturnTarget = currentReturnTarget;
|
||||
const saveActiveLabels = activeLabels;
|
||||
const saveHasExplicitReturn = hasExplicitReturn;
|
||||
const isIIFE = containerFlags & ContainerFlags.IsFunctionExpression && !!getImmediatelyInvokedFunctionExpression(node);
|
||||
// An IIFE is considered part of the containing control flow. Return statements behave
|
||||
// similarly to break statements that exit to a label just past the statement body.
|
||||
if (isIIFE) {
|
||||
currentReturnTarget = createBranchLabel();
|
||||
}
|
||||
else {
|
||||
currentFlow = { flags: FlowFlags.Start };
|
||||
if (containerFlags & ContainerFlags.IsFunctionExpression) {
|
||||
(<FlowStart>currentFlow).container = <FunctionExpression | ArrowFunction>node;
|
||||
}
|
||||
currentReturnTarget = undefined;
|
||||
}
|
||||
currentBreakTarget = undefined;
|
||||
currentContinueTarget = undefined;
|
||||
activeLabels = undefined;
|
||||
}
|
||||
|
||||
if (isInJavaScriptFile(node) && node.jsDocComment) {
|
||||
bind(node.jsDocComment);
|
||||
}
|
||||
|
||||
bindReachableStatement(node);
|
||||
|
||||
if (!(currentFlow.flags & FlowFlags.Unreachable) && isFunctionLikeKind(kind) && nodeIsPresent((<FunctionLikeDeclaration>node).body)) {
|
||||
flags |= NodeFlags.HasImplicitReturn;
|
||||
if (hasExplicitReturn) {
|
||||
flags |= NodeFlags.HasExplicitReturn;
|
||||
hasExplicitReturn = false;
|
||||
bindChildren(node);
|
||||
// Reset all reachability check related flags on node (for incremental scenarios)
|
||||
// Reset all emit helper flags on node (for incremental scenarios)
|
||||
node.flags &= ~NodeFlags.ReachabilityAndEmitFlags;
|
||||
if (!(currentFlow.flags & FlowFlags.Unreachable) && containerFlags & ContainerFlags.IsFunctionLike && nodeIsPresent((<FunctionLikeDeclaration>node).body)) {
|
||||
node.flags |= NodeFlags.HasImplicitReturn;
|
||||
if (hasExplicitReturn) node.flags |= NodeFlags.HasExplicitReturn;
|
||||
}
|
||||
if (node.kind === SyntaxKind.SourceFile) {
|
||||
node.flags |= emitFlags;
|
||||
}
|
||||
if (isIIFE) {
|
||||
addAntecedent(currentReturnTarget, currentFlow);
|
||||
currentFlow = finishFlowLabel(currentReturnTarget);
|
||||
}
|
||||
else {
|
||||
currentFlow = saveCurrentFlow;
|
||||
}
|
||||
currentBreakTarget = saveBreakTarget;
|
||||
currentContinueTarget = saveContinueTarget;
|
||||
currentReturnTarget = saveReturnTarget;
|
||||
activeLabels = saveActiveLabels;
|
||||
hasExplicitReturn = saveHasExplicitReturn;
|
||||
}
|
||||
|
||||
if (kind === SyntaxKind.InterfaceDeclaration) {
|
||||
flags = seenThisKeyword ? flags | NodeFlags.ContainsThis : flags & ~NodeFlags.ContainsThis;
|
||||
else if (containerFlags & ContainerFlags.IsInterface) {
|
||||
seenThisKeyword = false;
|
||||
bindChildren(node);
|
||||
node.flags = seenThisKeyword ? node.flags | NodeFlags.ContainsThis : node.flags & ~NodeFlags.ContainsThis;
|
||||
}
|
||||
|
||||
if (kind === SyntaxKind.SourceFile) {
|
||||
if (hasClassExtends) {
|
||||
flags |= NodeFlags.HasClassExtends;
|
||||
}
|
||||
if (hasDecorators) {
|
||||
flags |= NodeFlags.HasDecorators;
|
||||
}
|
||||
if (hasParameterDecorators) {
|
||||
flags |= NodeFlags.HasParamDecorators;
|
||||
}
|
||||
if (hasAsyncFunctions) {
|
||||
flags |= NodeFlags.HasAsyncFunctions;
|
||||
}
|
||||
if (hasJsxSpreadAttribute) {
|
||||
flags |= NodeFlags.HasJsxSpreadAttribute;
|
||||
}
|
||||
else {
|
||||
bindChildren(node);
|
||||
}
|
||||
|
||||
node.flags = flags;
|
||||
|
||||
if (saveState) {
|
||||
hasExplicitReturn = savedHasExplicitReturn;
|
||||
currentFlow = savedCurrentFlow;
|
||||
currentBreakTarget = savedBreakTarget;
|
||||
currentContinueTarget = savedContinueTarget;
|
||||
activeLabels = savedActiveLabels;
|
||||
}
|
||||
|
||||
container = saveContainer;
|
||||
parent = saveParent;
|
||||
blockScopeContainer = savedBlockScopeContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if node and its subnodes were successfully traversed.
|
||||
* Returning false means that node was not examined and caller needs to dive into the node himself.
|
||||
*/
|
||||
function bindReachableStatement(node: Node): void {
|
||||
function bindChildren(node: Node): void {
|
||||
// Binding of JsDocComment should be done before the current block scope container changes.
|
||||
// because the scope of JsDocComment should not be affected by whether the current node is a
|
||||
// container or not.
|
||||
if (isInJavaScriptFile(node) && node.jsDocComments) {
|
||||
for (const jsDocComment of node.jsDocComments) {
|
||||
bind(jsDocComment);
|
||||
}
|
||||
}
|
||||
if (checkUnreachable(node)) {
|
||||
forEachChild(node, bind);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.WhileStatement:
|
||||
bindWhileStatement(<WhileStatement>node);
|
||||
|
@ -589,6 +568,9 @@ namespace ts {
|
|||
case SyntaxKind.VariableDeclaration:
|
||||
bindVariableDeclarationFlow(<VariableDeclaration>node);
|
||||
break;
|
||||
case SyntaxKind.CallExpression:
|
||||
bindCallExpressionFlow(<CallExpression>node);
|
||||
break;
|
||||
default:
|
||||
forEachChild(node, bind);
|
||||
break;
|
||||
|
@ -848,6 +830,9 @@ namespace ts {
|
|||
bind(node.expression);
|
||||
if (node.kind === SyntaxKind.ReturnStatement) {
|
||||
hasExplicitReturn = true;
|
||||
if (currentReturnTarget) {
|
||||
addAntecedent(currentReturnTarget, currentFlow);
|
||||
}
|
||||
}
|
||||
currentFlow = unreachableFlow;
|
||||
}
|
||||
|
@ -1098,35 +1083,67 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function bindCallExpressionFlow(node: CallExpression) {
|
||||
// If the target of the call expression is a function expression or arrow function we have
|
||||
// an immediately invoked function expression (IIFE). Initialize the flowNode property to
|
||||
// the current control flow (which includes evaluation of the IIFE arguments).
|
||||
let expr: Expression = node.expression;
|
||||
while (expr.kind === SyntaxKind.ParenthesizedExpression) {
|
||||
expr = (<ParenthesizedExpression>expr).expression;
|
||||
}
|
||||
if (expr.kind === SyntaxKind.FunctionExpression || expr.kind === SyntaxKind.ArrowFunction) {
|
||||
forEach(node.typeArguments, bind);
|
||||
forEach(node.arguments, bind);
|
||||
bind(node.expression);
|
||||
}
|
||||
else {
|
||||
forEachChild(node, bind);
|
||||
}
|
||||
}
|
||||
|
||||
function getContainerFlags(node: Node): ContainerFlags {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ClassExpression:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
case SyntaxKind.TypeLiteral:
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
case SyntaxKind.JSDocRecordType:
|
||||
return ContainerFlags.IsContainer;
|
||||
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
return ContainerFlags.IsContainer | ContainerFlags.IsInterface;
|
||||
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
return ContainerFlags.IsContainer | ContainerFlags.HasLocals;
|
||||
|
||||
case SyntaxKind.SourceFile:
|
||||
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals;
|
||||
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.IndexSignature:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike;
|
||||
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.SourceFile:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
return ContainerFlags.IsContainerWithLocals;
|
||||
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike | ContainerFlags.IsFunctionExpression;
|
||||
|
||||
case SyntaxKind.ModuleBlock:
|
||||
return ContainerFlags.IsControlFlowContainer;
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
return (<PropertyDeclaration>node).initializer ? ContainerFlags.IsControlFlowContainer : 0;
|
||||
|
||||
case SyntaxKind.CatchClause:
|
||||
case SyntaxKind.ForStatement:
|
||||
|
@ -1194,6 +1211,7 @@ namespace ts {
|
|||
case SyntaxKind.ObjectLiteralExpression:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.JSDocRecordType:
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
// Interface/Object-types always have their children added to the 'members' of
|
||||
// their container. They are only accessible through an instance of their
|
||||
// container, and are never in scope otherwise (even inside the body of the
|
||||
|
@ -1222,7 +1240,7 @@ namespace ts {
|
|||
// their container in the tree. To accomplish this, we simply add their declared
|
||||
// symbol to the 'locals' of the container. These symbols can then be found as
|
||||
// the type checker walks up the containers, checking them for matching names.
|
||||
return declareSymbol(container.locals, undefined, node, symbolFlags, symbolExcludes);
|
||||
return declareSymbol(container.locals, /*parent*/ undefined, node, symbolFlags, symbolExcludes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1560,15 +1578,9 @@ namespace ts {
|
|||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
node.parent = parent;
|
||||
|
||||
const savedInStrictMode = inStrictMode;
|
||||
if (!savedInStrictMode) {
|
||||
updateStrictMode(node);
|
||||
}
|
||||
|
||||
// First we bind declaration nodes to a symbol if possible. We'll both create a symbol
|
||||
const saveInStrictMode = inStrictMode;
|
||||
// First we bind declaration nodes to a symbol if possible. We'll both create a symbol
|
||||
// and then potentially add the symbol to an appropriate symbol table. Possible
|
||||
// destination symbol tables are:
|
||||
//
|
||||
|
@ -1576,47 +1588,40 @@ namespace ts {
|
|||
// 2) The 'members' table of the current container's symbol.
|
||||
// 3) The 'locals' table of the current container.
|
||||
//
|
||||
// However, not all symbols will end up in any of these tables. 'Anonymous' symbols
|
||||
// However, not all symbols will end up in any of these tables. 'Anonymous' symbols
|
||||
// (like TypeLiterals for example) will not be put in any table.
|
||||
bindWorker(node);
|
||||
|
||||
// Then we recurse into the children of the node to bind them as well. For certain
|
||||
// symbols we do specialized work when we recurse. For example, we'll keep track of
|
||||
// the current 'container' node when it changes. This helps us know which symbol table
|
||||
// a local should go into for example.
|
||||
bindChildren(node);
|
||||
|
||||
inStrictMode = savedInStrictMode;
|
||||
}
|
||||
|
||||
function updateStrictMode(node: Node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.SourceFile:
|
||||
case SyntaxKind.ModuleBlock:
|
||||
updateStrictModeStatementList((<SourceFile | ModuleBlock>node).statements);
|
||||
return;
|
||||
case SyntaxKind.Block:
|
||||
if (isFunctionLike(node.parent)) {
|
||||
updateStrictModeStatementList((<Block>node).statements);
|
||||
}
|
||||
return;
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ClassExpression:
|
||||
// All classes are automatically in strict mode in ES6.
|
||||
inStrictMode = true;
|
||||
return;
|
||||
// Then we recurse into the children of the node to bind them as well. For certain
|
||||
// symbols we do specialized work when we recurse. For example, we'll keep track of
|
||||
// the current 'container' node when it changes. This helps us know which symbol table
|
||||
// a local should go into for example. Since terminal nodes are known not to have
|
||||
// children, as an optimization we don't process those.
|
||||
if (node.kind > SyntaxKind.LastToken) {
|
||||
const saveParent = parent;
|
||||
parent = node;
|
||||
const containerFlags = getContainerFlags(node);
|
||||
if (containerFlags === ContainerFlags.None) {
|
||||
bindChildren(node);
|
||||
}
|
||||
else {
|
||||
bindContainer(node, containerFlags);
|
||||
}
|
||||
parent = saveParent;
|
||||
}
|
||||
inStrictMode = saveInStrictMode;
|
||||
}
|
||||
|
||||
function updateStrictModeStatementList(statements: NodeArray<Statement>) {
|
||||
for (const statement of statements) {
|
||||
if (!isPrologueDirective(statement)) {
|
||||
return;
|
||||
}
|
||||
if (!inStrictMode) {
|
||||
for (const statement of statements) {
|
||||
if (!isPrologueDirective(statement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isUseStrictPrologueDirective(<ExpressionStatement>statement)) {
|
||||
inStrictMode = true;
|
||||
return;
|
||||
if (isUseStrictPrologueDirective(<ExpressionStatement>statement)) {
|
||||
inStrictMode = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1696,6 +1701,8 @@ namespace ts {
|
|||
case SyntaxKind.PropertySignature:
|
||||
case SyntaxKind.JSDocRecordMember:
|
||||
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.Property | ((<PropertyDeclaration>node).questionToken ? SymbolFlags.Optional : SymbolFlags.None), SymbolFlags.PropertyExcludes);
|
||||
case SyntaxKind.JSDocPropertyTag:
|
||||
return bindJSDocProperty(<JSDocPropertyTag>node);
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
|
||||
|
@ -1703,7 +1710,7 @@ namespace ts {
|
|||
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes);
|
||||
|
||||
case SyntaxKind.JsxSpreadAttribute:
|
||||
hasJsxSpreadAttribute = true;
|
||||
emitFlags |= NodeFlags.HasJsxSpreadAttribute;
|
||||
return;
|
||||
|
||||
case SyntaxKind.CallSignature:
|
||||
|
@ -1731,6 +1738,7 @@ namespace ts {
|
|||
case SyntaxKind.JSDocFunctionType:
|
||||
return bindFunctionOrConstructorType(<SignatureDeclaration>node);
|
||||
case SyntaxKind.TypeLiteral:
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
case SyntaxKind.JSDocRecordType:
|
||||
return bindAnonymousDeclaration(<TypeLiteralNode>node, SymbolFlags.TypeLiteral, "__type");
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
|
@ -1748,9 +1756,12 @@ namespace ts {
|
|||
// Members of classes, interfaces, and modules
|
||||
case SyntaxKind.ClassExpression:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
// All classes are automatically in strict mode in ES6.
|
||||
inStrictMode = true;
|
||||
return bindClassLikeDeclaration(<ClassLikeDeclaration>node);
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
return bindBlockScopedDeclaration(<Declaration>node, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes);
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
return bindBlockScopedDeclaration(<Declaration>node, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
|
@ -1773,7 +1784,15 @@ namespace ts {
|
|||
case SyntaxKind.ExportAssignment:
|
||||
return bindExportAssignment(<ExportAssignment>node);
|
||||
case SyntaxKind.SourceFile:
|
||||
updateStrictModeStatementList((<SourceFile>node).statements);
|
||||
return bindSourceFileIfExternalModule();
|
||||
case SyntaxKind.Block:
|
||||
if (!isFunctionLike(node.parent)) {
|
||||
return;
|
||||
}
|
||||
// Fall through
|
||||
case SyntaxKind.ModuleBlock:
|
||||
return updateStrictModeStatementList((<Block | ModuleBlock>node).statements);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1935,10 +1954,10 @@ namespace ts {
|
|||
function bindClassLikeDeclaration(node: ClassLikeDeclaration) {
|
||||
if (!isDeclarationFile(file) && !isInAmbientContext(node)) {
|
||||
if (getClassExtendsHeritageClauseElement(node) !== undefined) {
|
||||
hasClassExtends = true;
|
||||
emitFlags |= NodeFlags.HasClassExtends;
|
||||
}
|
||||
if (nodeIsDecorated(node)) {
|
||||
hasDecorators = true;
|
||||
emitFlags |= NodeFlags.HasDecorators;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2014,8 +2033,7 @@ namespace ts {
|
|||
if (!isDeclarationFile(file) &&
|
||||
!isInAmbientContext(node) &&
|
||||
nodeIsDecorated(node)) {
|
||||
hasDecorators = true;
|
||||
hasParameterDecorators = true;
|
||||
emitFlags |= (NodeFlags.HasDecorators | NodeFlags.HasParamDecorators);
|
||||
}
|
||||
|
||||
if (inStrictMode) {
|
||||
|
@ -2042,7 +2060,7 @@ namespace ts {
|
|||
function bindFunctionDeclaration(node: FunctionDeclaration) {
|
||||
if (!isDeclarationFile(file) && !isInAmbientContext(node)) {
|
||||
if (isAsyncFunctionLike(node)) {
|
||||
hasAsyncFunctions = true;
|
||||
emitFlags |= NodeFlags.HasAsyncFunctions;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2059,10 +2077,12 @@ namespace ts {
|
|||
function bindFunctionExpression(node: FunctionExpression) {
|
||||
if (!isDeclarationFile(file) && !isInAmbientContext(node)) {
|
||||
if (isAsyncFunctionLike(node)) {
|
||||
hasAsyncFunctions = true;
|
||||
emitFlags |= NodeFlags.HasAsyncFunctions;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentFlow) {
|
||||
node.flowNode = currentFlow;
|
||||
}
|
||||
checkStrictModeFunctionName(<FunctionExpression>node);
|
||||
const bindingName = (<FunctionExpression>node).name ? (<FunctionExpression>node).name.text : "__function";
|
||||
return bindAnonymousDeclaration(<FunctionExpression>node, SymbolFlags.Function, bindingName);
|
||||
|
@ -2071,10 +2091,10 @@ namespace ts {
|
|||
function bindPropertyOrMethodOrAccessor(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) {
|
||||
if (!isDeclarationFile(file) && !isInAmbientContext(node)) {
|
||||
if (isAsyncFunctionLike(node)) {
|
||||
hasAsyncFunctions = true;
|
||||
emitFlags |= NodeFlags.HasAsyncFunctions;
|
||||
}
|
||||
if (nodeIsDecorated(node)) {
|
||||
hasDecorators = true;
|
||||
emitFlags |= NodeFlags.HasDecorators;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2083,6 +2103,10 @@ namespace ts {
|
|||
: declareSymbolAndAddToSymbolTable(node, symbolFlags, symbolExcludes);
|
||||
}
|
||||
|
||||
function bindJSDocProperty(node: JSDocPropertyTag) {
|
||||
return declareSymbolAndAddToSymbolTable(node, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
|
||||
}
|
||||
|
||||
// reachability checks
|
||||
|
||||
function shouldReportErrorOnModuleDeclaration(node: ModuleDeclaration): boolean {
|
||||
|
|
|
@ -110,16 +110,16 @@ namespace ts {
|
|||
const unknownSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "unknown");
|
||||
const resolvingSymbol = createSymbol(SymbolFlags.Transient, "__resolving__");
|
||||
|
||||
const nullableWideningFlags = strictNullChecks ? 0 : TypeFlags.ContainsUndefinedOrNull;
|
||||
const anyType = createIntrinsicType(TypeFlags.Any, "any");
|
||||
const stringType = createIntrinsicType(TypeFlags.String, "string");
|
||||
const numberType = createIntrinsicType(TypeFlags.Number, "number");
|
||||
const booleanType = createIntrinsicType(TypeFlags.Boolean, "boolean");
|
||||
const esSymbolType = createIntrinsicType(TypeFlags.ESSymbol, "symbol");
|
||||
const voidType = createIntrinsicType(TypeFlags.Void, "void");
|
||||
const undefinedType = createIntrinsicType(TypeFlags.Undefined | nullableWideningFlags, "undefined");
|
||||
const nullType = createIntrinsicType(TypeFlags.Null | nullableWideningFlags, "null");
|
||||
const emptyArrayElementType = createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsUndefinedOrNull, "undefined");
|
||||
const undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined");
|
||||
const undefinedWideningType = strictNullChecks ? undefinedType : createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsWideningType, "undefined");
|
||||
const nullType = createIntrinsicType(TypeFlags.Null, "null");
|
||||
const nullWideningType = strictNullChecks ? nullType : createIntrinsicType(TypeFlags.Null | TypeFlags.ContainsWideningType, "null");
|
||||
const unknownType = createIntrinsicType(TypeFlags.Any, "unknown");
|
||||
const neverType = createIntrinsicType(TypeFlags.Never, "never");
|
||||
|
||||
|
@ -3405,7 +3405,7 @@ namespace ts {
|
|||
error(type.symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_base_expression, symbolToString(type.symbol));
|
||||
return type.resolvedBaseConstructorType = unknownType;
|
||||
}
|
||||
if (baseConstructorType !== unknownType && baseConstructorType !== nullType && !isConstructorType(baseConstructorType)) {
|
||||
if (baseConstructorType !== unknownType && baseConstructorType !== nullWideningType && !isConstructorType(baseConstructorType)) {
|
||||
error(baseTypeNode.expression, Diagnostics.Type_0_is_not_a_constructor_function_type, typeToString(baseConstructorType));
|
||||
return type.resolvedBaseConstructorType = unknownType;
|
||||
}
|
||||
|
@ -3581,8 +3581,22 @@ namespace ts {
|
|||
if (!pushTypeResolution(symbol, TypeSystemPropertyName.DeclaredType)) {
|
||||
return unknownType;
|
||||
}
|
||||
const declaration = <TypeAliasDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration);
|
||||
let type = getTypeFromTypeNode(declaration.type);
|
||||
|
||||
let type: Type;
|
||||
let declaration: JSDocTypedefTag | TypeAliasDeclaration = <JSDocTypedefTag>getDeclarationOfKind(symbol, SyntaxKind.JSDocTypedefTag);
|
||||
if (declaration) {
|
||||
if (declaration.jsDocTypeLiteral) {
|
||||
type = getTypeFromTypeNode(declaration.jsDocTypeLiteral);
|
||||
}
|
||||
else {
|
||||
type = getTypeFromTypeNode(declaration.typeExpression.type);
|
||||
}
|
||||
}
|
||||
else {
|
||||
declaration = <TypeAliasDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration);
|
||||
type = getTypeFromTypeNode(declaration.type);
|
||||
}
|
||||
|
||||
if (popTypeResolution()) {
|
||||
links.typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
|
||||
if (links.typeParameters) {
|
||||
|
@ -4997,6 +5011,7 @@ namespace ts {
|
|||
containsAny?: boolean;
|
||||
containsUndefined?: boolean;
|
||||
containsNull?: boolean;
|
||||
containsNonWideningType?: boolean;
|
||||
}
|
||||
|
||||
function addTypeToSet(typeSet: TypeSet, type: Type, typeSetKind: TypeFlags) {
|
||||
|
@ -5007,6 +5022,7 @@ namespace ts {
|
|||
if (type.flags & TypeFlags.Any) typeSet.containsAny = true;
|
||||
if (type.flags & TypeFlags.Undefined) typeSet.containsUndefined = true;
|
||||
if (type.flags & TypeFlags.Null) typeSet.containsNull = true;
|
||||
if (!(type.flags & TypeFlags.ContainsWideningType)) typeSet.containsNonWideningType = true;
|
||||
}
|
||||
else if (type !== neverType && !contains(typeSet, type)) {
|
||||
typeSet.push(type);
|
||||
|
@ -5067,8 +5083,8 @@ namespace ts {
|
|||
removeSubtypes(typeSet);
|
||||
}
|
||||
if (typeSet.length === 0) {
|
||||
return typeSet.containsNull ? nullType :
|
||||
typeSet.containsUndefined ? undefinedType :
|
||||
return typeSet.containsNull ? typeSet.containsNonWideningType ? nullType : nullWideningType :
|
||||
typeSet.containsUndefined ? typeSet.containsNonWideningType ? undefinedType : undefinedWideningType :
|
||||
neverType;
|
||||
}
|
||||
else if (typeSet.length === 1) {
|
||||
|
@ -5253,6 +5269,7 @@ namespace ts {
|
|||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.TypeLiteral:
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
case SyntaxKind.JSDocRecordType:
|
||||
return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node);
|
||||
|
@ -5867,7 +5884,7 @@ namespace ts {
|
|||
if (!(target.flags & TypeFlags.Never)) {
|
||||
if (target.flags & TypeFlags.Any || source.flags & TypeFlags.Never) return Ternary.True;
|
||||
if (source.flags & TypeFlags.Undefined) {
|
||||
if (!strictNullChecks || target.flags & (TypeFlags.Undefined | TypeFlags.Void) || source === emptyArrayElementType) return Ternary.True;
|
||||
if (!strictNullChecks || target.flags & (TypeFlags.Undefined | TypeFlags.Void)) return Ternary.True;
|
||||
}
|
||||
if (source.flags & TypeFlags.Null) {
|
||||
if (!strictNullChecks || target.flags & TypeFlags.Null) return Ternary.True;
|
||||
|
@ -6957,7 +6974,7 @@ namespace ts {
|
|||
if (type.flags & TypeFlags.ObjectLiteral) {
|
||||
for (const p of getPropertiesOfObjectType(type)) {
|
||||
const t = getTypeOfSymbol(p);
|
||||
if (t.flags & TypeFlags.ContainsUndefinedOrNull) {
|
||||
if (t.flags & TypeFlags.ContainsWideningType) {
|
||||
if (!reportWideningErrorsInType(t)) {
|
||||
error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, p.name, typeToString(getWidenedType(t)));
|
||||
}
|
||||
|
@ -7004,7 +7021,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
function reportErrorsFromWidening(declaration: Declaration, type: Type) {
|
||||
if (produceDiagnostics && compilerOptions.noImplicitAny && type.flags & TypeFlags.ContainsUndefinedOrNull) {
|
||||
if (produceDiagnostics && compilerOptions.noImplicitAny && type.flags & TypeFlags.ContainsWideningType) {
|
||||
// Report implicit any error within type if possible, otherwise report error on declaration
|
||||
if (!reportWideningErrorsInType(type)) {
|
||||
reportImplicitAnyError(declaration, type);
|
||||
|
@ -7645,7 +7662,7 @@ namespace ts {
|
|||
getInitialTypeOfBindingElement(<BindingElement>node);
|
||||
}
|
||||
|
||||
function getFlowTypeOfReference(reference: Node, declaredType: Type, assumeInitialized: boolean) {
|
||||
function getFlowTypeOfReference(reference: Node, declaredType: Type, assumeInitialized: boolean, includeOuterFunctions: boolean) {
|
||||
let key: string;
|
||||
if (!reference.flowNode || assumeInitialized && !(declaredType.flags & TypeFlags.Narrowable)) {
|
||||
return declaredType;
|
||||
|
@ -7691,15 +7708,21 @@ namespace ts {
|
|||
getTypeAtFlowBranchLabel(<FlowLabel>flow) :
|
||||
getTypeAtFlowLoopLabel(<FlowLabel>flow);
|
||||
}
|
||||
else if (flow.flags & FlowFlags.Unreachable) {
|
||||
else if (flow.flags & FlowFlags.Start) {
|
||||
// Check if we should continue with the control flow of the containing function.
|
||||
const container = (<FlowStart>flow).container;
|
||||
if (container && includeOuterFunctions) {
|
||||
flow = container.flowNode;
|
||||
continue;
|
||||
}
|
||||
// At the top of the flow we have the initial type.
|
||||
type = initialType;
|
||||
}
|
||||
else {
|
||||
// Unreachable code errors are reported in the binding phase. Here we
|
||||
// simply return the declared type to reduce follow-on errors.
|
||||
type = declaredType;
|
||||
}
|
||||
else {
|
||||
// At the top of the flow we have the initial type.
|
||||
type = initialType;
|
||||
}
|
||||
if (flow.flags & FlowFlags.Shared) {
|
||||
// Record visited node and the associated type in the cache.
|
||||
visitedFlowNodes[visitedFlowCount] = flow;
|
||||
|
@ -8068,6 +8091,17 @@ namespace ts {
|
|||
return expression;
|
||||
}
|
||||
|
||||
function isDeclarationIncludedInFlow(reference: Node, declaration: Declaration, includeOuterFunctions: boolean) {
|
||||
const declarationContainer = getContainingFunctionOrModule(declaration);
|
||||
let container = getContainingFunctionOrModule(reference);
|
||||
while (container !== declarationContainer &&
|
||||
(container.kind === SyntaxKind.FunctionExpression || container.kind === SyntaxKind.ArrowFunction) &&
|
||||
(includeOuterFunctions || getImmediatelyInvokedFunctionExpression(<FunctionExpression>container))) {
|
||||
container = getContainingFunctionOrModule(container);
|
||||
}
|
||||
return container === declarationContainer;
|
||||
}
|
||||
|
||||
function checkIdentifier(node: Identifier): Type {
|
||||
const symbol = getResolvedSymbol(node);
|
||||
|
||||
|
@ -8124,10 +8158,11 @@ namespace ts {
|
|||
return type;
|
||||
}
|
||||
const declaration = localOrExportSymbol.valueDeclaration;
|
||||
const includeOuterFunctions = isReadonlySymbol(localOrExportSymbol);
|
||||
const assumeInitialized = !strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || !declaration ||
|
||||
getRootDeclaration(declaration).kind === SyntaxKind.Parameter || isInAmbientContext(declaration) ||
|
||||
getContainingFunctionOrModule(declaration) !== getContainingFunctionOrModule(node);
|
||||
const flowType = getFlowTypeOfReference(node, type, assumeInitialized);
|
||||
!isDeclarationIncludedInFlow(node, declaration, includeOuterFunctions);
|
||||
const flowType = getFlowTypeOfReference(node, type, assumeInitialized, includeOuterFunctions);
|
||||
if (!assumeInitialized && !(getNullableKind(type) & TypeFlags.Undefined) && getNullableKind(flowType) & TypeFlags.Undefined) {
|
||||
error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol));
|
||||
// Return the declared type to reduce follow-on errors
|
||||
|
@ -8278,7 +8313,7 @@ namespace ts {
|
|||
const classInstanceType = <InterfaceType>getDeclaredTypeOfSymbol(classSymbol);
|
||||
const baseConstructorType = getBaseConstructorTypeOfClass(classInstanceType);
|
||||
|
||||
return baseConstructorType === nullType;
|
||||
return baseConstructorType === nullWideningType;
|
||||
}
|
||||
|
||||
function checkThisExpression(node: Node): Type {
|
||||
|
@ -8376,7 +8411,7 @@ namespace ts {
|
|||
if (isClassLike(container.parent)) {
|
||||
const symbol = getSymbolOfNode(container.parent);
|
||||
const type = container.flags & NodeFlags.Static ? getTypeOfSymbol(symbol) : (<InterfaceType>getDeclaredTypeOfSymbol(symbol)).thisType;
|
||||
return getFlowTypeOfReference(node, type, /*assumeInitialized*/ true);
|
||||
return getFlowTypeOfReference(node, type, /*assumeInitialized*/ true, /*includeOuterFunctions*/ true);
|
||||
}
|
||||
|
||||
if (isInJavaScriptFile(node)) {
|
||||
|
@ -8661,20 +8696,6 @@ namespace ts {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
function getImmediatelyInvokedFunctionExpression(func: FunctionExpression | MethodDeclaration) {
|
||||
if (isFunctionExpressionOrArrowFunction(func)) {
|
||||
let prev: Node = func;
|
||||
let parent: Node = func.parent;
|
||||
while (parent.kind === SyntaxKind.ParenthesizedExpression) {
|
||||
prev = parent;
|
||||
parent = parent.parent;
|
||||
}
|
||||
if (parent.kind === SyntaxKind.CallExpression && (parent as CallExpression).expression === prev) {
|
||||
return parent as CallExpression;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// In a variable, parameter or property declaration with a type annotation,
|
||||
// the contextual type of an initializer expression is the type of the variable, parameter or property.
|
||||
// Otherwise, in a parameter declaration of a contextually typed function expression,
|
||||
|
@ -9183,7 +9204,7 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
}
|
||||
return createArrayType(elementTypes.length ? getUnionType(elementTypes) : emptyArrayElementType);
|
||||
return createArrayType(elementTypes.length ? getUnionType(elementTypes) : strictNullChecks ? neverType : undefinedWideningType);
|
||||
}
|
||||
|
||||
function isNumericName(name: DeclarationName): boolean {
|
||||
|
@ -9988,7 +10009,7 @@ namespace ts {
|
|||
return propType;
|
||||
}
|
||||
}
|
||||
return getFlowTypeOfReference(node, propType, /*assumeInitialized*/ true);
|
||||
return getFlowTypeOfReference(node, propType, /*assumeInitialized*/ true, /*includeOuterFunctions*/ false);
|
||||
}
|
||||
|
||||
function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean {
|
||||
|
@ -11983,7 +12004,7 @@ namespace ts {
|
|||
|
||||
function checkVoidExpression(node: VoidExpression): Type {
|
||||
checkExpression(node.expression);
|
||||
return undefinedType;
|
||||
return undefinedWideningType;
|
||||
}
|
||||
|
||||
function checkAwaitExpression(node: AwaitExpression): Type {
|
||||
|
@ -12390,7 +12411,7 @@ namespace ts {
|
|||
case SyntaxKind.InKeyword:
|
||||
return checkInExpression(left, right, leftType, rightType);
|
||||
case SyntaxKind.AmpersandAmpersandToken:
|
||||
return addNullableKind(rightType, getNullableKind(leftType));
|
||||
return strictNullChecks ? addNullableKind(rightType, getNullableKind(leftType)) : rightType;
|
||||
case SyntaxKind.BarBarToken:
|
||||
return getUnionType([getNonNullableType(leftType), rightType]);
|
||||
case SyntaxKind.EqualsToken:
|
||||
|
@ -12657,7 +12678,7 @@ namespace ts {
|
|||
case SyntaxKind.SuperKeyword:
|
||||
return checkSuperExpression(node);
|
||||
case SyntaxKind.NullKeyword:
|
||||
return nullType;
|
||||
return nullWideningType;
|
||||
case SyntaxKind.TrueKeyword:
|
||||
case SyntaxKind.FalseKeyword:
|
||||
return booleanType;
|
||||
|
@ -12715,7 +12736,7 @@ namespace ts {
|
|||
case SyntaxKind.SpreadElementExpression:
|
||||
return checkSpreadElementExpression(<SpreadElementExpression>node, contextualMapper);
|
||||
case SyntaxKind.OmittedExpression:
|
||||
return undefinedType;
|
||||
return undefinedWideningType;
|
||||
case SyntaxKind.YieldExpression:
|
||||
return checkYieldExpression(<YieldExpression>node);
|
||||
case SyntaxKind.JsxExpression:
|
||||
|
@ -16724,7 +16745,7 @@ namespace ts {
|
|||
node = node.parent;
|
||||
}
|
||||
|
||||
return node.parent && node.parent.kind === SyntaxKind.TypeReference;
|
||||
return node.parent && (node.parent.kind === SyntaxKind.TypeReference || node.parent.kind === SyntaxKind.JSDocTypeReference) ;
|
||||
}
|
||||
|
||||
function isHeritageClauseElementIdentifier(entityName: Node): boolean {
|
||||
|
@ -16860,7 +16881,7 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
else if (isTypeReferenceIdentifier(<EntityName>entityName)) {
|
||||
let meaning = entityName.parent.kind === SyntaxKind.TypeReference ? SymbolFlags.Type : SymbolFlags.Namespace;
|
||||
let meaning = (entityName.parent.kind === SyntaxKind.TypeReference || entityName.parent.kind === SyntaxKind.JSDocTypeReference) ? SymbolFlags.Type : SymbolFlags.Namespace;
|
||||
// Include aliases in the meaning, this ensures that we do not follow aliases to where they point and instead
|
||||
// return the alias symbol.
|
||||
meaning |= SymbolFlags.Alias;
|
||||
|
@ -17629,7 +17650,7 @@ namespace ts {
|
|||
// Setup global builtins
|
||||
addToSymbolTable(globals, builtinGlobals, Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0);
|
||||
|
||||
getSymbolLinks(undefinedSymbol).type = undefinedType;
|
||||
getSymbolLinks(undefinedSymbol).type = undefinedWideningType;
|
||||
getSymbolLinks(argumentsSymbol).type = getGlobalType("IArguments");
|
||||
getSymbolLinks(unknownSymbol).type = unknownType;
|
||||
|
||||
|
|
|
@ -819,6 +819,10 @@
|
|||
"category": "Error",
|
||||
"code": 1252
|
||||
},
|
||||
"'{0}' tag cannot be used independently as a top level JSDoc tag.": {
|
||||
"category": "Error",
|
||||
"code": 1253
|
||||
},
|
||||
"'with' statements are not allowed in an async function block.": {
|
||||
"category": "Error",
|
||||
"code": 1300
|
||||
|
|
|
@ -401,6 +401,15 @@ namespace ts {
|
|||
return visitNode(cbNode, (<JSDocTypeTag>node).typeExpression);
|
||||
case SyntaxKind.JSDocTemplateTag:
|
||||
return visitNodes(cbNodes, (<JSDocTemplateTag>node).typeParameters);
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
return visitNode(cbNode, (<JSDocTypedefTag>node).typeExpression) ||
|
||||
visitNode(cbNode, (<JSDocTypedefTag>node).name) ||
|
||||
visitNode(cbNode, (<JSDocTypedefTag>node).jsDocTypeLiteral);
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
return visitNodes(cbNodes, (<JSDocTypeLiteral>node).jsDocPropertyTags);
|
||||
case SyntaxKind.JSDocPropertyTag:
|
||||
return visitNode(cbNode, (<JSDocPropertyTag>node).typeExpression) ||
|
||||
visitNode(cbNode, (<JSDocPropertyTag>node).name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -431,7 +440,14 @@ namespace ts {
|
|||
|
||||
/* @internal */
|
||||
export function parseIsolatedJSDocComment(content: string, start?: number, length?: number) {
|
||||
return Parser.JSDocParser.parseIsolatedJSDocComment(content, start, length);
|
||||
const result = Parser.JSDocParser.parseIsolatedJSDocComment(content, start, length);
|
||||
if (result && result.jsDocComment) {
|
||||
// because the jsDocComment was parsed out of the source file, it might
|
||||
// not be covered by the fixupParentReferences.
|
||||
Parser.fixupParentReferences(result.jsDocComment);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
@ -628,9 +644,14 @@ namespace ts {
|
|||
if (comments) {
|
||||
for (const comment of comments) {
|
||||
const jsDocComment = JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos);
|
||||
if (jsDocComment) {
|
||||
node.jsDocComment = jsDocComment;
|
||||
if (!jsDocComment) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!node.jsDocComments) {
|
||||
node.jsDocComments = [];
|
||||
}
|
||||
node.jsDocComments.push(jsDocComment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -638,14 +659,14 @@ namespace ts {
|
|||
return node;
|
||||
}
|
||||
|
||||
export function fixupParentReferences(sourceFile: Node) {
|
||||
export function fixupParentReferences(rootNode: Node) {
|
||||
// normally parent references are set during binding. However, for clients that only need
|
||||
// a syntax tree, and no semantic features, then the binding process is an unnecessary
|
||||
// overhead. This functions allows us to set all the parents, without all the expense of
|
||||
// binding.
|
||||
|
||||
let parent: Node = sourceFile;
|
||||
forEachChild(sourceFile, visitNode);
|
||||
let parent: Node = rootNode;
|
||||
forEachChild(rootNode, visitNode);
|
||||
return;
|
||||
|
||||
function visitNode(n: Node): void {
|
||||
|
@ -658,6 +679,13 @@ namespace ts {
|
|||
const saveParent = parent;
|
||||
parent = n;
|
||||
forEachChild(n, visitNode);
|
||||
if (n.jsDocComments) {
|
||||
for (const jsDocComment of n.jsDocComments) {
|
||||
jsDocComment.parent = n;
|
||||
parent = jsDocComment;
|
||||
forEachChild(jsDocComment, visitNode);
|
||||
}
|
||||
}
|
||||
parent = saveParent;
|
||||
}
|
||||
}
|
||||
|
@ -2704,7 +2732,7 @@ namespace ts {
|
|||
// 1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In]
|
||||
// 2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In]
|
||||
// Production (1) of AsyncArrowFunctionExpression is parsed in "tryParseAsyncSimpleArrowFunctionExpression".
|
||||
// And production (2) is parsed in "tryParseParenthesizedArrowFunctionExpression".
|
||||
// And production (2) is parsed in "tryParseParenthesizedArrowFunctionExpression".
|
||||
//
|
||||
// If we do successfully parse arrow-function, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is
|
||||
// not a LeftHandSideExpression, nor does it start a ConditionalExpression. So we are done
|
||||
|
@ -3396,8 +3424,8 @@ namespace ts {
|
|||
if (sourceFile.languageVariant !== LanguageVariant.JSX) {
|
||||
return false;
|
||||
}
|
||||
// We are in JSX context and the token is part of JSXElement.
|
||||
// Fall through
|
||||
// We are in JSX context and the token is part of JSXElement.
|
||||
// Fall through
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
@ -4099,9 +4127,9 @@ namespace ts {
|
|||
const isAsync = !!(node.flags & NodeFlags.Async);
|
||||
node.name =
|
||||
isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalIdentifier) :
|
||||
isGenerator ? doInYieldContext(parseOptionalIdentifier) :
|
||||
isAsync ? doInAwaitContext(parseOptionalIdentifier) :
|
||||
parseOptionalIdentifier();
|
||||
isGenerator ? doInYieldContext(parseOptionalIdentifier) :
|
||||
isAsync ? doInAwaitContext(parseOptionalIdentifier) :
|
||||
parseOptionalIdentifier();
|
||||
|
||||
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ isGenerator, /*awaitContext*/ isAsync, /*requireCompleteParameterList*/ false, node);
|
||||
node.body = parseFunctionBlock(/*allowYield*/ isGenerator, /*allowAwait*/ isAsync, /*ignoreMissingOpenBrace*/ false);
|
||||
|
@ -5891,7 +5919,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
function checkForEmptyTypeArgumentList(typeArguments: NodeArray<Node>) {
|
||||
if (parseDiagnostics.length === 0 && typeArguments && typeArguments.length === 0) {
|
||||
if (parseDiagnostics.length === 0 && typeArguments && typeArguments.length === 0) {
|
||||
const start = typeArguments.pos - "<".length;
|
||||
const end = skipTrivia(sourceText, typeArguments.end) + ">".length;
|
||||
return parseErrorAtPosition(start, end - start, Diagnostics.Type_argument_list_cannot_be_empty);
|
||||
|
@ -6052,7 +6080,6 @@ namespace ts {
|
|||
Debug.assert(end <= content.length);
|
||||
|
||||
let tags: NodeArray<JSDocTag>;
|
||||
|
||||
let result: JSDocComment;
|
||||
|
||||
// Check for /** (JSDoc opening part)
|
||||
|
@ -6159,6 +6186,8 @@ namespace ts {
|
|||
return handleTemplateTag(atToken, tagName);
|
||||
case "type":
|
||||
return handleTypeTag(atToken, tagName);
|
||||
case "typedef":
|
||||
return handleTypedefTag(atToken, tagName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6266,6 +6295,122 @@ namespace ts {
|
|||
return finishNode(result);
|
||||
}
|
||||
|
||||
function handlePropertyTag(atToken: Node, tagName: Identifier): JSDocPropertyTag {
|
||||
const typeExpression = tryParseTypeExpression();
|
||||
skipWhitespace();
|
||||
const name = parseJSDocIdentifierName();
|
||||
if (!name) {
|
||||
parseErrorAtPosition(scanner.getStartPos(), /*length*/ 0, Diagnostics.Identifier_expected);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const result = <JSDocPropertyTag>createNode(SyntaxKind.JSDocPropertyTag, atToken.pos);
|
||||
result.atToken = atToken;
|
||||
result.tagName = tagName;
|
||||
result.name = name;
|
||||
result.typeExpression = typeExpression;
|
||||
return finishNode(result);
|
||||
}
|
||||
|
||||
function handleTypedefTag(atToken: Node, tagName: Identifier): JSDocTypedefTag {
|
||||
const typeExpression = tryParseTypeExpression();
|
||||
skipWhitespace();
|
||||
|
||||
const typedefTag = <JSDocTypedefTag>createNode(SyntaxKind.JSDocTypedefTag, atToken.pos);
|
||||
typedefTag.atToken = atToken;
|
||||
typedefTag.tagName = tagName;
|
||||
typedefTag.name = parseJSDocIdentifierName();
|
||||
typedefTag.typeExpression = typeExpression;
|
||||
|
||||
if (typeExpression) {
|
||||
if (typeExpression.type.kind === SyntaxKind.JSDocTypeReference) {
|
||||
const jsDocTypeReference = <JSDocTypeReference>typeExpression.type;
|
||||
if (jsDocTypeReference.name.kind === SyntaxKind.Identifier) {
|
||||
const name = <Identifier>jsDocTypeReference.name;
|
||||
if (name.text === "Object") {
|
||||
typedefTag.jsDocTypeLiteral = scanChildTags();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!typedefTag.jsDocTypeLiteral) {
|
||||
typedefTag.jsDocTypeLiteral = typeExpression.type;
|
||||
}
|
||||
}
|
||||
else {
|
||||
typedefTag.jsDocTypeLiteral = scanChildTags();
|
||||
}
|
||||
|
||||
return finishNode(typedefTag);
|
||||
|
||||
function scanChildTags(): JSDocTypeLiteral {
|
||||
const jsDocTypeLiteral = <JSDocTypeLiteral>createNode(SyntaxKind.JSDocTypeLiteral, scanner.getStartPos());
|
||||
let resumePos = scanner.getStartPos();
|
||||
let canParseTag = true;
|
||||
let seenAsterisk = false;
|
||||
let parentTagTerminated = false;
|
||||
|
||||
while (token !== SyntaxKind.EndOfFileToken && !parentTagTerminated) {
|
||||
nextJSDocToken();
|
||||
switch (token) {
|
||||
case SyntaxKind.AtToken:
|
||||
if (canParseTag) {
|
||||
parentTagTerminated = !tryParseChildTag(jsDocTypeLiteral);
|
||||
}
|
||||
seenAsterisk = false;
|
||||
break;
|
||||
case SyntaxKind.NewLineTrivia:
|
||||
resumePos = scanner.getStartPos() - 1;
|
||||
canParseTag = true;
|
||||
seenAsterisk = false;
|
||||
break;
|
||||
case SyntaxKind.AsteriskToken:
|
||||
if (seenAsterisk) {
|
||||
canParseTag = false;
|
||||
}
|
||||
seenAsterisk = true;
|
||||
break;
|
||||
case SyntaxKind.Identifier:
|
||||
canParseTag = false;
|
||||
case SyntaxKind.EndOfFileToken:
|
||||
break;
|
||||
}
|
||||
}
|
||||
scanner.setTextPos(resumePos);
|
||||
return finishNode(jsDocTypeLiteral);
|
||||
}
|
||||
}
|
||||
|
||||
function tryParseChildTag(parentTag: JSDocTypeLiteral): boolean {
|
||||
Debug.assert(token === SyntaxKind.AtToken);
|
||||
const atToken = createNode(SyntaxKind.AtToken, scanner.getStartPos());
|
||||
atToken.end = scanner.getTextPos();
|
||||
nextJSDocToken();
|
||||
|
||||
const tagName = parseJSDocIdentifierName();
|
||||
if (!tagName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (tagName.text) {
|
||||
case "type":
|
||||
if (parentTag.jsDocTypeTag) {
|
||||
// already has a @type tag, terminate the parent tag now.
|
||||
return false;
|
||||
}
|
||||
parentTag.jsDocTypeTag = handleTypeTag(atToken, tagName);
|
||||
return true;
|
||||
case "prop":
|
||||
case "property":
|
||||
if (!parentTag.jsDocPropertyTags) {
|
||||
parentTag.jsDocPropertyTags = <NodeArray<JSDocPropertyTag>>[];
|
||||
}
|
||||
const propertyTag = handlePropertyTag(atToken, tagName);
|
||||
parentTag.jsDocPropertyTags.push(propertyTag);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function handleTemplateTag(atToken: Node, tagName: Identifier): JSDocTemplateTag {
|
||||
if (forEach(tags, t => t.kind === SyntaxKind.JSDocTemplateTag)) {
|
||||
parseErrorAtPosition(tagName.pos, scanner.getTokenPos() - tagName.pos, Diagnostics._0_tag_already_specified, tagName.text);
|
||||
|
@ -6435,10 +6580,6 @@ namespace ts {
|
|||
node._children = undefined;
|
||||
}
|
||||
|
||||
if (node.jsDocComment) {
|
||||
node.jsDocComment = undefined;
|
||||
}
|
||||
|
||||
node.pos += delta;
|
||||
node.end += delta;
|
||||
|
||||
|
@ -6447,6 +6588,11 @@ namespace ts {
|
|||
}
|
||||
|
||||
forEachChild(node, visitNode, visitArray);
|
||||
if (node.jsDocComments) {
|
||||
for (const jsDocComment of node.jsDocComments) {
|
||||
forEachChild(jsDocComment, visitNode, visitArray);
|
||||
}
|
||||
}
|
||||
checkNodePositions(node, aggressiveChecks);
|
||||
}
|
||||
|
||||
|
|
|
@ -434,7 +434,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
/* @internal */
|
||||
export function skipTrivia(text: string, pos: number, stopAfterLineBreak?: boolean): number {
|
||||
export function skipTrivia(text: string, pos: number, stopAfterLineBreak?: boolean, stopAtComments = false): number {
|
||||
// Using ! with a greater than test is a fast way of testing the following conditions:
|
||||
// pos === undefined || pos === null || isNaN(pos) || pos < 0;
|
||||
if (!(pos >= 0)) {
|
||||
|
@ -462,6 +462,9 @@ namespace ts {
|
|||
pos++;
|
||||
continue;
|
||||
case CharacterCodes.slash:
|
||||
if (stopAtComments) {
|
||||
break;
|
||||
}
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.slash) {
|
||||
pos += 2;
|
||||
while (pos < text.length) {
|
||||
|
|
|
@ -343,6 +343,9 @@ namespace ts {
|
|||
JSDocReturnTag,
|
||||
JSDocTypeTag,
|
||||
JSDocTemplateTag,
|
||||
JSDocTypedefTag,
|
||||
JSDocPropertyTag,
|
||||
JSDocTypeLiteral,
|
||||
|
||||
// Synthesized list
|
||||
SyntaxList,
|
||||
|
@ -372,6 +375,10 @@ namespace ts {
|
|||
FirstBinaryOperator = LessThanToken,
|
||||
LastBinaryOperator = CaretEqualsToken,
|
||||
FirstNode = QualifiedName,
|
||||
FirstJSDocNode = JSDocTypeExpression,
|
||||
LastJSDocNode = JSDocTypeLiteral,
|
||||
FirstJSDocTagNode = JSDocComment,
|
||||
LastJSDocTagNode = JSDocTypeLiteral
|
||||
}
|
||||
|
||||
export const enum NodeFlags {
|
||||
|
@ -416,6 +423,7 @@ namespace ts {
|
|||
|
||||
ReachabilityCheckFlags = HasImplicitReturn | HasExplicitReturn,
|
||||
EmitHelperFlags = HasClassExtends | HasDecorators | HasParamDecorators | HasAsyncFunctions,
|
||||
ReachabilityAndEmitFlags = ReachabilityCheckFlags | EmitHelperFlags,
|
||||
|
||||
// Parsing context flags
|
||||
ContextFlags = DisallowInContext | YieldContext | DecoratorContext | AwaitContext | JavaScriptFile,
|
||||
|
@ -448,7 +456,7 @@ namespace ts {
|
|||
modifiers?: ModifiersArray; // Array of modifiers
|
||||
/* @internal */ id?: number; // Unique id (used to look up NodeLinks)
|
||||
parent?: Node; // Parent node (initialized by binding
|
||||
/* @internal */ jsDocComment?: JSDocComment; // JSDoc for the node, if it has any. Only for .js files.
|
||||
/* @internal */ jsDocComments?: JSDocComment[]; // JSDoc for the node, if it has any. Only for .js files.
|
||||
/* @internal */ symbol?: Symbol; // Symbol declared by node (initialized by binding)
|
||||
/* @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding)
|
||||
/* @internal */ nextContainer?: Node; // Next container in declaration order (initialized by binding)
|
||||
|
@ -612,6 +620,7 @@ namespace ts {
|
|||
// SyntaxKind.PropertyAssignment
|
||||
// SyntaxKind.ShorthandPropertyAssignment
|
||||
// SyntaxKind.EnumMember
|
||||
// SyntaxKind.JSDocPropertyTag
|
||||
export interface VariableLikeDeclaration extends Declaration {
|
||||
propertyName?: PropertyName;
|
||||
dotDotDotToken?: Node;
|
||||
|
@ -1510,6 +1519,25 @@ namespace ts {
|
|||
typeExpression: JSDocTypeExpression;
|
||||
}
|
||||
|
||||
// @kind(SyntaxKind.JSDocTypedefTag)
|
||||
export interface JSDocTypedefTag extends JSDocTag, Declaration {
|
||||
name?: Identifier;
|
||||
typeExpression?: JSDocTypeExpression;
|
||||
jsDocTypeLiteral?: JSDocTypeLiteral;
|
||||
}
|
||||
|
||||
// @kind(SyntaxKind.JSDocPropertyTag)
|
||||
export interface JSDocPropertyTag extends JSDocTag, TypeElement {
|
||||
name: Identifier;
|
||||
typeExpression: JSDocTypeExpression;
|
||||
}
|
||||
|
||||
// @kind(SyntaxKind.JSDocTypeLiteral)
|
||||
export interface JSDocTypeLiteral extends JSDocType {
|
||||
jsDocPropertyTags?: NodeArray<JSDocPropertyTag>;
|
||||
jsDocTypeTag?: JSDocTypeTag;
|
||||
}
|
||||
|
||||
// @kind(SyntaxKind.JSDocParameterTag)
|
||||
export interface JSDocParameterTag extends JSDocTag {
|
||||
preParameterName?: Identifier;
|
||||
|
@ -1537,6 +1565,13 @@ namespace ts {
|
|||
id?: number; // Node id used by flow type cache in checker
|
||||
}
|
||||
|
||||
// FlowStart represents the start of a control flow. For a function expression or arrow
|
||||
// function, the container property references the function (which in turn has a flowNode
|
||||
// property for the containing control flow).
|
||||
export interface FlowStart extends FlowNode {
|
||||
container?: FunctionExpression | ArrowFunction;
|
||||
}
|
||||
|
||||
// FlowLabel represents a junction with multiple possible preceding control flows.
|
||||
export interface FlowLabel extends FlowNode {
|
||||
antecedents: FlowNode[];
|
||||
|
@ -2162,7 +2197,7 @@ namespace ts {
|
|||
/* @internal */
|
||||
FreshObjectLiteral = 0x00100000, // Fresh object literal type
|
||||
/* @internal */
|
||||
ContainsUndefinedOrNull = 0x00200000, // Type is or contains undefined or null type
|
||||
ContainsWideningType = 0x00200000, // Type is or contains undefined or null widening type
|
||||
/* @internal */
|
||||
ContainsObjectLiteral = 0x00400000, // Type is or contains object literal type
|
||||
/* @internal */
|
||||
|
@ -2185,9 +2220,9 @@ namespace ts {
|
|||
StructuredType = ObjectType | Union | Intersection,
|
||||
Narrowable = Any | ObjectType | Union | TypeParameter,
|
||||
/* @internal */
|
||||
RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral,
|
||||
RequiresWidening = ContainsWideningType | ContainsObjectLiteral,
|
||||
/* @internal */
|
||||
PropagatingFlags = ContainsUndefinedOrNull | ContainsObjectLiteral | ContainsAnyFunctionType
|
||||
PropagatingFlags = ContainsWideningType | ContainsObjectLiteral | ContainsAnyFunctionType
|
||||
}
|
||||
|
||||
export type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression;
|
||||
|
@ -2875,4 +2910,9 @@ namespace ts {
|
|||
|
||||
/* @internal */ reattachFileDiagnostics(newFile: SourceFile): void;
|
||||
}
|
||||
|
||||
// SyntaxKind.SyntaxList
|
||||
export interface SyntaxList extends Node {
|
||||
_children: Node[];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -287,16 +287,36 @@ namespace ts {
|
|||
return !nodeIsMissing(node);
|
||||
}
|
||||
|
||||
export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile): number {
|
||||
export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile, includeJsDocComment?: boolean): number {
|
||||
// With nodes that have no width (i.e. 'Missing' nodes), we actually *don't*
|
||||
// want to skip trivia because this will launch us forward to the next token.
|
||||
if (nodeIsMissing(node)) {
|
||||
return node.pos;
|
||||
}
|
||||
|
||||
if (isJSDocNode(node)) {
|
||||
return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos, /*stopAfterLineBreak*/ false, /*stopAtComments*/ true);
|
||||
}
|
||||
|
||||
if (includeJsDocComment && node.jsDocComments && node.jsDocComments.length > 0) {
|
||||
return getTokenPosOfNode(node.jsDocComments[0]);
|
||||
}
|
||||
|
||||
// For a syntax list, it is possible that one of its children has JSDocComment nodes, while
|
||||
// the syntax list itself considers them as normal trivia. Therefore if we simply skip
|
||||
// trivia for the list, we may have skipped the JSDocComment as well. So we should process its
|
||||
// first child to determine the actual position of its first token.
|
||||
if (node.kind === SyntaxKind.SyntaxList && (<SyntaxList>node)._children.length > 0) {
|
||||
return getTokenPosOfNode((<SyntaxList>node)._children[0], sourceFile, includeJsDocComment);
|
||||
}
|
||||
|
||||
return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos);
|
||||
}
|
||||
|
||||
export function isJSDocNode(node: Node) {
|
||||
return node.kind >= SyntaxKind.FirstJSDocNode && node.kind <= SyntaxKind.LastJSDocNode;
|
||||
}
|
||||
|
||||
export function getNonDecoratorTokenPosOfNode(node: Node, sourceFile?: SourceFile): number {
|
||||
if (nodeIsMissing(node) || !node.decorators) {
|
||||
return getTokenPosOfNode(node, sourceFile);
|
||||
|
@ -987,6 +1007,20 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
export function getImmediatelyInvokedFunctionExpression(func: Node): CallExpression {
|
||||
if (func.kind === SyntaxKind.FunctionExpression || func.kind === SyntaxKind.ArrowFunction) {
|
||||
let prev = func;
|
||||
let parent = func.parent;
|
||||
while (parent.kind === SyntaxKind.ParenthesizedExpression) {
|
||||
prev = parent;
|
||||
parent = parent.parent;
|
||||
}
|
||||
if (parent.kind === SyntaxKind.CallExpression && (parent as CallExpression).expression === prev) {
|
||||
return parent as CallExpression;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a node is a property or element access expression for super.
|
||||
*/
|
||||
|
@ -1322,21 +1356,23 @@ namespace ts {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
const jsDocComment = getJSDocComment(node, checkParentVariableStatement);
|
||||
if (!jsDocComment) {
|
||||
const jsDocComments = getJSDocComments(node, checkParentVariableStatement);
|
||||
if (!jsDocComments) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
for (const tag of jsDocComment.tags) {
|
||||
if (tag.kind === kind) {
|
||||
return tag;
|
||||
for (const jsDocComment of jsDocComments) {
|
||||
for (const tag of jsDocComment.tags) {
|
||||
if (tag.kind === kind) {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getJSDocComment(node: Node, checkParentVariableStatement: boolean): JSDocComment {
|
||||
if (node.jsDocComment) {
|
||||
return node.jsDocComment;
|
||||
function getJSDocComments(node: Node, checkParentVariableStatement: boolean): JSDocComment[] {
|
||||
if (node.jsDocComments) {
|
||||
return node.jsDocComments;
|
||||
}
|
||||
// Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement.
|
||||
// /**
|
||||
|
@ -1352,7 +1388,7 @@ namespace ts {
|
|||
|
||||
const variableStatementNode = isInitializerOfVariableDeclarationInStatement ? node.parent.parent.parent : undefined;
|
||||
if (variableStatementNode) {
|
||||
return variableStatementNode.jsDocComment;
|
||||
return variableStatementNode.jsDocComments;
|
||||
}
|
||||
|
||||
// Also recognize when the node is the RHS of an assignment expression
|
||||
|
@ -1363,12 +1399,12 @@ namespace ts {
|
|||
(parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken &&
|
||||
parent.parent.kind === SyntaxKind.ExpressionStatement;
|
||||
if (isSourceOfAssignmentExpressionStatement) {
|
||||
return parent.parent.jsDocComment;
|
||||
return parent.parent.jsDocComments;
|
||||
}
|
||||
|
||||
const isPropertyAssignmentExpression = parent && parent.kind === SyntaxKind.PropertyAssignment;
|
||||
if (isPropertyAssignmentExpression) {
|
||||
return parent.jsDocComment;
|
||||
return parent.jsDocComments;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1393,14 +1429,16 @@ namespace ts {
|
|||
// annotation.
|
||||
const parameterName = (<Identifier>parameter.name).text;
|
||||
|
||||
const jsDocComment = getJSDocComment(parameter.parent, /*checkParentVariableStatement*/ true);
|
||||
if (jsDocComment) {
|
||||
for (const tag of jsDocComment.tags) {
|
||||
if (tag.kind === SyntaxKind.JSDocParameterTag) {
|
||||
const parameterTag = <JSDocParameterTag>tag;
|
||||
const name = parameterTag.preParameterName || parameterTag.postParameterName;
|
||||
if (name.text === parameterName) {
|
||||
return parameterTag;
|
||||
const jsDocComments = getJSDocComments(parameter.parent, /*checkParentVariableStatement*/ true);
|
||||
if (jsDocComments) {
|
||||
for (const jsDocComment of jsDocComments) {
|
||||
for (const tag of jsDocComment.tags) {
|
||||
if (tag.kind === SyntaxKind.JSDocParameterTag) {
|
||||
const parameterTag = <JSDocParameterTag>tag;
|
||||
const name = parameterTag.preParameterName || parameterTag.postParameterName;
|
||||
if (name.text === parameterName) {
|
||||
return parameterTag;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1525,6 +1563,7 @@ namespace ts {
|
|||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.TypeParameter:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -1486,6 +1486,12 @@ namespace FourSlash {
|
|||
this.fixCaretPosition();
|
||||
}
|
||||
|
||||
public formatOnType(pos: number, key: string) {
|
||||
const edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, pos, key, this.formatCodeOptions);
|
||||
this.currentCaretPosition += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true);
|
||||
this.fixCaretPosition();
|
||||
}
|
||||
|
||||
private updateMarkersForEdit(fileName: string, minChar: number, limChar: number, text: string) {
|
||||
for (let i = 0; i < this.testData.markers.length; i++) {
|
||||
const marker = this.testData.markers[i];
|
||||
|
@ -3223,6 +3229,10 @@ namespace FourSlashInterface {
|
|||
this.state.formatSelection(this.state.getMarkerByName(startMarker).position, this.state.getMarkerByName(endMarker).position);
|
||||
}
|
||||
|
||||
public onType(posMarker: string, key: string) {
|
||||
this.state.formatOnType(this.state.getMarkerByName(posMarker).position, key);
|
||||
}
|
||||
|
||||
public setOption(name: string, value: number): void;
|
||||
public setOption(name: string, value: string): void;
|
||||
public setOption(name: string, value: boolean): void;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
@ -221,6 +221,19 @@ namespace Utils {
|
|||
return k;
|
||||
}
|
||||
|
||||
// For some markers in SyntaxKind, we should print its original syntax name instead of
|
||||
// the marker name in tests.
|
||||
if (k === (<any>ts).SyntaxKind.FirstJSDocNode ||
|
||||
k === (<any>ts).SyntaxKind.LastJSDocNode ||
|
||||
k === (<any>ts).SyntaxKind.FirstJSDocTagNode ||
|
||||
k === (<any>ts).SyntaxKind.LastJSDocTagNode) {
|
||||
for (const kindName in (<any>ts).SyntaxKind) {
|
||||
if ((<any>ts).SyntaxKind[kindName] === k) {
|
||||
return kindName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (<any>ts).SyntaxKind[k];
|
||||
}
|
||||
|
||||
|
@ -350,7 +363,7 @@ namespace Utils {
|
|||
assert.equal(node1.end, node2.end, "node1.end !== node2.end");
|
||||
assert.equal(node1.kind, node2.kind, "node1.kind !== node2.kind");
|
||||
|
||||
// call this on both nodes to ensure all propagated flags have been set (and thus can be
|
||||
// call this on both nodes to ensure all propagated flags have been set (and thus can be
|
||||
// compared).
|
||||
assert.equal(ts.containsParseError(node1), ts.containsParseError(node2));
|
||||
assert.equal(node1.flags, node2.flags, "node1.flags !== node2.flags");
|
||||
|
@ -751,7 +764,7 @@ namespace Harness {
|
|||
(emittedFile: string, emittedLine: number, emittedColumn: number, sourceFile: string, sourceLine: number, sourceColumn: number, sourceName: string): void;
|
||||
}
|
||||
|
||||
// Settings
|
||||
// Settings
|
||||
export let userSpecifiedRoot = "";
|
||||
export let lightMode = false;
|
||||
|
||||
|
@ -790,7 +803,7 @@ namespace Harness {
|
|||
fileName: string,
|
||||
sourceText: string,
|
||||
languageVersion: ts.ScriptTarget) {
|
||||
// We'll only assert invariants outside of light mode.
|
||||
// We'll only assert invariants outside of light mode.
|
||||
const shouldAssertInvariants = !Harness.lightMode;
|
||||
|
||||
// Only set the parent nodes if we're asserting invariants. We don't need them otherwise.
|
||||
|
@ -935,7 +948,7 @@ namespace Harness {
|
|||
libFiles?: string;
|
||||
}
|
||||
|
||||
// Additional options not already in ts.optionDeclarations
|
||||
// Additional options not already in ts.optionDeclarations
|
||||
const harnessOptionDeclarations: ts.CommandLineOption[] = [
|
||||
{ name: "allowNonTsExtensions", type: "boolean" },
|
||||
{ name: "useCaseSensitiveFileNames", type: "boolean" },
|
||||
|
@ -1187,7 +1200,7 @@ namespace Harness {
|
|||
errLines.forEach(e => outputLines.push(e));
|
||||
|
||||
// do not count errors from lib.d.ts here, they are computed separately as numLibraryDiagnostics
|
||||
// if lib.d.ts is explicitly included in input files and there are some errors in it (i.e. because of duplicate identifiers)
|
||||
// if lib.d.ts is explicitly included in input files and there are some errors in it (i.e. because of duplicate identifiers)
|
||||
// then they will be added twice thus triggering 'total errors' assertion with condition
|
||||
// 'totalErrorsReportedInNonLibraryFiles + numLibraryDiagnostics + numTest262HarnessDiagnostics, diagnostics.length
|
||||
|
||||
|
@ -1497,7 +1510,7 @@ namespace Harness {
|
|||
};
|
||||
testUnitData.push(newTestFile2);
|
||||
|
||||
// unit tests always list files explicitly
|
||||
// unit tests always list files explicitly
|
||||
const parseConfigHost: ts.ParseConfigHost = {
|
||||
readDirectory: (name) => []
|
||||
};
|
||||
|
|
|
@ -1131,7 +1131,7 @@ namespace ts.server {
|
|||
else {
|
||||
this.log("No config files found.");
|
||||
}
|
||||
return {};
|
||||
return configFileName ? { configFileName } : {};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -81,6 +81,12 @@ namespace ts.formatting {
|
|||
while (isWhiteSpace(sourceFile.text.charCodeAt(endOfFormatSpan)) && !isLineBreak(sourceFile.text.charCodeAt(endOfFormatSpan))) {
|
||||
endOfFormatSpan--;
|
||||
}
|
||||
// if the character at the end of the span is a line break, we shouldn't include it, because it indicates we don't want to
|
||||
// touch the current line at all. Also, on some OSes the line break consists of two characters (\r\n), we should test if the
|
||||
// previous character before the end of format span is line break character as well.
|
||||
if (isLineBreak(sourceFile.text.charCodeAt(endOfFormatSpan))) {
|
||||
endOfFormatSpan--;
|
||||
}
|
||||
const span = {
|
||||
// get start position for the previous line
|
||||
pos: getStartPositionOfLine(line - 1, sourceFile),
|
||||
|
|
|
@ -652,6 +652,12 @@ namespace ts.NavigationBar {
|
|||
topItem.childItems.push(newItem);
|
||||
}
|
||||
|
||||
if (node.jsDocComments && node.jsDocComments.length > 0) {
|
||||
for (const jsDocComment of node.jsDocComments) {
|
||||
visitNode(jsDocComment);
|
||||
}
|
||||
}
|
||||
|
||||
// Add a level if traversing into a container
|
||||
if (newItem && (isFunctionLike(node) || isClassLike(node))) {
|
||||
const lastTop = topItem;
|
||||
|
@ -731,6 +737,27 @@ namespace ts.NavigationBar {
|
|||
}
|
||||
const declName = declarationNameToString(decl.name);
|
||||
return getNavBarItem(declName, ScriptElementKind.constElement, [getNodeSpan(node)]);
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
if ((<JSDocTypedefTag>node).name) {
|
||||
return getNavBarItem(
|
||||
(<JSDocTypedefTag>node).name.text,
|
||||
ScriptElementKind.typeElement,
|
||||
[getNodeSpan(node)]);
|
||||
}
|
||||
else {
|
||||
const parentNode = node.parent && node.parent.parent;
|
||||
if (parentNode && parentNode.kind === SyntaxKind.VariableStatement) {
|
||||
if ((<VariableStatement>parentNode).declarationList.declarations.length > 0) {
|
||||
const nameIdentifier = (<VariableStatement>parentNode).declarationList.declarations[0].name;
|
||||
if (nameIdentifier.kind === SyntaxKind.Identifier) {
|
||||
return getNavBarItem(
|
||||
(<Identifier>nameIdentifier).text,
|
||||
ScriptElementKind.typeElement,
|
||||
[getNodeSpan(node)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
|
@ -801,7 +828,7 @@ namespace ts.NavigationBar {
|
|||
}
|
||||
|
||||
function getNodeSpan(node: Node) {
|
||||
return node.kind === SyntaxKind.SourceFile
|
||||
return node.kind === SyntaxKind.SourceFile
|
||||
? createTextSpanFromBounds(node.getFullStart(), node.getEnd())
|
||||
: createTextSpanFromBounds(node.getStart(), node.getEnd());
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace ts {
|
|||
getChildCount(sourceFile?: SourceFile): number;
|
||||
getChildAt(index: number, sourceFile?: SourceFile): Node;
|
||||
getChildren(sourceFile?: SourceFile): Node[];
|
||||
getStart(sourceFile?: SourceFile): number;
|
||||
getStart(sourceFile?: SourceFile, includeJsDocComment?: boolean): number;
|
||||
getFullStart(): number;
|
||||
getEnd(): number;
|
||||
getWidth(sourceFile?: SourceFile): number;
|
||||
|
@ -172,6 +172,9 @@ namespace ts {
|
|||
"static",
|
||||
"throws",
|
||||
"type",
|
||||
"typedef",
|
||||
"property",
|
||||
"prop",
|
||||
"version"
|
||||
];
|
||||
let jsDocCompletionEntries: CompletionEntry[];
|
||||
|
@ -189,6 +192,7 @@ namespace ts {
|
|||
public end: number;
|
||||
public flags: NodeFlags;
|
||||
public parent: Node;
|
||||
public jsDocComments: JSDocComment[];
|
||||
private _children: Node[];
|
||||
|
||||
constructor(kind: SyntaxKind, pos: number, end: number) {
|
||||
|
@ -203,8 +207,8 @@ namespace ts {
|
|||
return getSourceFileOfNode(this);
|
||||
}
|
||||
|
||||
public getStart(sourceFile?: SourceFile): number {
|
||||
return getTokenPosOfNode(this, sourceFile);
|
||||
public getStart(sourceFile?: SourceFile, includeJsDocComment?: boolean): number {
|
||||
return getTokenPosOfNode(this, sourceFile, includeJsDocComment);
|
||||
}
|
||||
|
||||
public getFullStart(): number {
|
||||
|
@ -235,12 +239,14 @@ namespace ts {
|
|||
return (sourceFile || this.getSourceFile()).text.substring(this.getStart(), this.getEnd());
|
||||
}
|
||||
|
||||
private addSyntheticNodes(nodes: Node[], pos: number, end: number): number {
|
||||
private addSyntheticNodes(nodes: Node[], pos: number, end: number, useJSDocScanner?: boolean): number {
|
||||
scanner.setTextPos(pos);
|
||||
while (pos < end) {
|
||||
const token = scanner.scan();
|
||||
const token = useJSDocScanner ? scanner.scanJSDocToken() : scanner.scan();
|
||||
const textPos = scanner.getTextPos();
|
||||
nodes.push(createNode(token, pos, textPos, 0, this));
|
||||
if (textPos <= end) {
|
||||
nodes.push(createNode(token, pos, textPos, 0, this));
|
||||
}
|
||||
pos = textPos;
|
||||
}
|
||||
return pos;
|
||||
|
@ -270,20 +276,27 @@ namespace ts {
|
|||
scanner.setText((sourceFile || this.getSourceFile()).text);
|
||||
children = [];
|
||||
let pos = this.pos;
|
||||
const useJSDocScanner = this.kind >= SyntaxKind.FirstJSDocTagNode && this.kind <= SyntaxKind.LastJSDocTagNode;
|
||||
const processNode = (node: Node) => {
|
||||
if (pos < node.pos) {
|
||||
pos = this.addSyntheticNodes(children, pos, node.pos);
|
||||
pos = this.addSyntheticNodes(children, pos, node.pos, useJSDocScanner);
|
||||
}
|
||||
children.push(node);
|
||||
pos = node.end;
|
||||
};
|
||||
const processNodes = (nodes: NodeArray<Node>) => {
|
||||
if (pos < nodes.pos) {
|
||||
pos = this.addSyntheticNodes(children, pos, nodes.pos);
|
||||
pos = this.addSyntheticNodes(children, pos, nodes.pos, useJSDocScanner);
|
||||
}
|
||||
children.push(this.createSyntaxList(<NodeArray<Node>>nodes));
|
||||
pos = nodes.end;
|
||||
};
|
||||
// jsDocComments need to be the first children
|
||||
if (this.jsDocComments) {
|
||||
for (const jsDocComment of this.jsDocComments) {
|
||||
processNode(jsDocComment);
|
||||
}
|
||||
}
|
||||
forEachChild(this, processNode, processNodes);
|
||||
if (pos < this.end) {
|
||||
this.addSyntheticNodes(children, pos, this.end);
|
||||
|
@ -5637,7 +5650,7 @@ namespace ts {
|
|||
|
||||
const sourceFile = getValidSourceFile(fileName);
|
||||
|
||||
const node = getTouchingPropertyName(sourceFile, position);
|
||||
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
|
||||
if (node === sourceFile) {
|
||||
return undefined;
|
||||
}
|
||||
|
@ -5999,7 +6012,8 @@ namespace ts {
|
|||
const sourceFile = container.getSourceFile();
|
||||
const tripleSlashDirectivePrefixRegex = /^\/\/\/\s*</;
|
||||
|
||||
const possiblePositions = getPossibleSymbolReferencePositions(sourceFile, searchText, container.getStart(), container.getEnd());
|
||||
const start = findInComments ? container.getFullStart() : container.getStart();
|
||||
const possiblePositions = getPossibleSymbolReferencePositions(sourceFile, searchText, start, container.getEnd());
|
||||
|
||||
if (possiblePositions.length) {
|
||||
// Build the set of symbols to search for, initially it has only the current symbol
|
||||
|
@ -7829,7 +7843,7 @@ namespace ts {
|
|||
const defaultLibFileName = host.getDefaultLibFileName(host.getCompilationSettings());
|
||||
const canonicalDefaultLibName = getCanonicalFileName(ts.normalizePath(defaultLibFileName));
|
||||
|
||||
const node = getTouchingWord(sourceFile, position);
|
||||
const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ true);
|
||||
|
||||
// Can only rename an identifier.
|
||||
if (node) {
|
||||
|
@ -7999,6 +8013,11 @@ namespace ts {
|
|||
break;
|
||||
default:
|
||||
forEachChild(node, walk);
|
||||
if (node.jsDocComments) {
|
||||
for (const jsDocComment of node.jsDocComments) {
|
||||
forEachChild(jsDocComment, walk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -234,29 +234,29 @@ namespace ts {
|
|||
/* Gets the token whose text has range [start, end) and
|
||||
* position >= start and (position < end or (position === end && token is keyword or identifier))
|
||||
*/
|
||||
export function getTouchingWord(sourceFile: SourceFile, position: number): Node {
|
||||
return getTouchingToken(sourceFile, position, n => isWord(n.kind));
|
||||
export function getTouchingWord(sourceFile: SourceFile, position: number, includeJsDocComment = false): Node {
|
||||
return getTouchingToken(sourceFile, position, n => isWord(n.kind), includeJsDocComment);
|
||||
}
|
||||
|
||||
/* Gets the token whose text has range [start, end) and position >= start
|
||||
* and (position < end or (position === end && token is keyword or identifier or numeric/string literal))
|
||||
*/
|
||||
export function getTouchingPropertyName(sourceFile: SourceFile, position: number): Node {
|
||||
return getTouchingToken(sourceFile, position, n => isPropertyName(n.kind));
|
||||
export function getTouchingPropertyName(sourceFile: SourceFile, position: number, includeJsDocComment = false): Node {
|
||||
return getTouchingToken(sourceFile, position, n => isPropertyName(n.kind), includeJsDocComment);
|
||||
}
|
||||
|
||||
/** Returns the token if position is in [start, end) or if position === end and includeItemAtEndPosition(token) === true */
|
||||
export function getTouchingToken(sourceFile: SourceFile, position: number, includeItemAtEndPosition?: (n: Node) => boolean): Node {
|
||||
return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ false, includeItemAtEndPosition);
|
||||
export function getTouchingToken(sourceFile: SourceFile, position: number, includeItemAtEndPosition?: (n: Node) => boolean, includeJsDocComment = false): Node {
|
||||
return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ false, includeItemAtEndPosition, includeJsDocComment);
|
||||
}
|
||||
|
||||
/** Returns a token if position is in [start-of-leading-trivia, end) */
|
||||
export function getTokenAtPosition(sourceFile: SourceFile, position: number): Node {
|
||||
return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includeItemAtEndPosition*/ undefined);
|
||||
export function getTokenAtPosition(sourceFile: SourceFile, position: number, includeJsDocComment = false): Node {
|
||||
return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includeItemAtEndPosition*/ undefined, includeJsDocComment);
|
||||
}
|
||||
|
||||
/** Get the token whose text contains the position */
|
||||
function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allowPositionInLeadingTrivia: boolean, includeItemAtEndPosition: (n: Node) => boolean): Node {
|
||||
function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allowPositionInLeadingTrivia: boolean, includeItemAtEndPosition: (n: Node) => boolean, includeJsDocComment = false): Node {
|
||||
let current: Node = sourceFile;
|
||||
outer: while (true) {
|
||||
if (isToken(current)) {
|
||||
|
@ -264,13 +264,34 @@ namespace ts {
|
|||
return current;
|
||||
}
|
||||
|
||||
if (includeJsDocComment) {
|
||||
const jsDocChildren = ts.filter(current.getChildren(), isJSDocNode);
|
||||
for (const jsDocChild of jsDocChildren) {
|
||||
const start = allowPositionInLeadingTrivia ? jsDocChild.getFullStart() : jsDocChild.getStart(sourceFile, includeJsDocComment);
|
||||
if (start <= position) {
|
||||
const end = jsDocChild.getEnd();
|
||||
if (position < end || (position === end && jsDocChild.kind === SyntaxKind.EndOfFileToken)) {
|
||||
current = jsDocChild;
|
||||
continue outer;
|
||||
}
|
||||
else if (includeItemAtEndPosition && end === position) {
|
||||
const previousToken = findPrecedingToken(position, sourceFile, jsDocChild);
|
||||
if (previousToken && includeItemAtEndPosition(previousToken)) {
|
||||
return previousToken;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find the child that contains 'position'
|
||||
for (let i = 0, n = current.getChildCount(sourceFile); i < n; i++) {
|
||||
const child = current.getChildAt(i);
|
||||
if (position < child.getFullStart() || position > child.getEnd()) {
|
||||
// all jsDocComment nodes were already visited
|
||||
if (isJSDocNode(child)) {
|
||||
continue;
|
||||
}
|
||||
const start = allowPositionInLeadingTrivia ? child.getFullStart() : child.getStart(sourceFile);
|
||||
const start = allowPositionInLeadingTrivia ? child.getFullStart() : child.getStart(sourceFile, includeJsDocComment);
|
||||
if (start <= position) {
|
||||
const end = child.getEnd();
|
||||
if (position < end || (position === end && child.kind === SyntaxKind.EndOfFileToken)) {
|
||||
|
@ -285,6 +306,7 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
@ -423,6 +445,10 @@ namespace ts {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (token.kind === SyntaxKind.JsxText) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// <div>Hello |</div>
|
||||
if (token.kind === SyntaxKind.LessThanToken && token.parent.kind === SyntaxKind.JsxText) {
|
||||
return true;
|
||||
|
@ -433,7 +459,7 @@ namespace ts {
|
|||
return true;
|
||||
}
|
||||
|
||||
// <div> {
|
||||
// <div> {
|
||||
// |
|
||||
// } < /div>
|
||||
if (token && token.kind === SyntaxKind.CloseBraceToken && token.parent.kind === SyntaxKind.JsxExpression) {
|
||||
|
@ -518,11 +544,12 @@ namespace ts {
|
|||
}
|
||||
|
||||
if (node) {
|
||||
const jsDocComment = node.jsDocComment;
|
||||
if (jsDocComment) {
|
||||
for (const tag of jsDocComment.tags) {
|
||||
if (tag.pos <= position && position <= tag.end) {
|
||||
return tag;
|
||||
if (node.jsDocComments) {
|
||||
for (const jsDocComment of node.jsDocComments) {
|
||||
for (const tag of jsDocComment.tags) {
|
||||
if (tag.pos <= position && position <= tag.end) {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -646,7 +673,7 @@ namespace ts {
|
|||
|
||||
// [a, b, c] of
|
||||
// [x, [a, b, c] ] = someExpression
|
||||
// or
|
||||
// or
|
||||
// {x, a: {a, b, c} } = someExpression
|
||||
if (isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent.kind === SyntaxKind.PropertyAssignment ? node.parent.parent : node.parent)) {
|
||||
return true;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// array literals are widened upon assignment according to their element type
|
||||
|
||||
var a = []; // any[]
|
||||
var a = [,,];
|
||||
|
||||
var a = [null, null];
|
||||
var a = [undefined, undefined];
|
||||
|
@ -12,11 +13,20 @@ var b = [[undefined, undefined]];
|
|||
|
||||
var c = [[[]]]; // any[][][]
|
||||
var c = [[[null]],[undefined]]
|
||||
|
||||
// no widening when one or more elements are non-widening
|
||||
|
||||
var x: undefined = undefined;
|
||||
|
||||
var d = [x];
|
||||
var d = [, x];
|
||||
var d = [undefined, x];
|
||||
|
||||
|
||||
//// [arrayLiteralWidened.js]
|
||||
// array literals are widened upon assignment according to their element type
|
||||
var a = []; // any[]
|
||||
var a = [, ,];
|
||||
var a = [null, null];
|
||||
var a = [undefined, undefined];
|
||||
var b = [[], [null, null]]; // any[][]
|
||||
|
@ -24,3 +34,8 @@ var b = [[], []];
|
|||
var b = [[undefined, undefined]];
|
||||
var c = [[[]]]; // any[][][]
|
||||
var c = [[[null]], [undefined]];
|
||||
// no widening when one or more elements are non-widening
|
||||
var x = undefined;
|
||||
var d = [x];
|
||||
var d = [, x];
|
||||
var d = [undefined, x];
|
||||
|
|
|
@ -2,31 +2,53 @@
|
|||
// array literals are widened upon assignment according to their element type
|
||||
|
||||
var a = []; // any[]
|
||||
>a : Symbol(a, Decl(arrayLiteralWidened.ts, 2, 3), Decl(arrayLiteralWidened.ts, 4, 3), Decl(arrayLiteralWidened.ts, 5, 3))
|
||||
>a : Symbol(a, Decl(arrayLiteralWidened.ts, 2, 3), Decl(arrayLiteralWidened.ts, 3, 3), Decl(arrayLiteralWidened.ts, 5, 3), Decl(arrayLiteralWidened.ts, 6, 3))
|
||||
|
||||
var a = [,,];
|
||||
>a : Symbol(a, Decl(arrayLiteralWidened.ts, 2, 3), Decl(arrayLiteralWidened.ts, 3, 3), Decl(arrayLiteralWidened.ts, 5, 3), Decl(arrayLiteralWidened.ts, 6, 3))
|
||||
|
||||
var a = [null, null];
|
||||
>a : Symbol(a, Decl(arrayLiteralWidened.ts, 2, 3), Decl(arrayLiteralWidened.ts, 4, 3), Decl(arrayLiteralWidened.ts, 5, 3))
|
||||
>a : Symbol(a, Decl(arrayLiteralWidened.ts, 2, 3), Decl(arrayLiteralWidened.ts, 3, 3), Decl(arrayLiteralWidened.ts, 5, 3), Decl(arrayLiteralWidened.ts, 6, 3))
|
||||
|
||||
var a = [undefined, undefined];
|
||||
>a : Symbol(a, Decl(arrayLiteralWidened.ts, 2, 3), Decl(arrayLiteralWidened.ts, 4, 3), Decl(arrayLiteralWidened.ts, 5, 3))
|
||||
>a : Symbol(a, Decl(arrayLiteralWidened.ts, 2, 3), Decl(arrayLiteralWidened.ts, 3, 3), Decl(arrayLiteralWidened.ts, 5, 3), Decl(arrayLiteralWidened.ts, 6, 3))
|
||||
>undefined : Symbol(undefined)
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
var b = [[], [null, null]]; // any[][]
|
||||
>b : Symbol(b, Decl(arrayLiteralWidened.ts, 7, 3), Decl(arrayLiteralWidened.ts, 8, 3), Decl(arrayLiteralWidened.ts, 9, 3))
|
||||
>b : Symbol(b, Decl(arrayLiteralWidened.ts, 8, 3), Decl(arrayLiteralWidened.ts, 9, 3), Decl(arrayLiteralWidened.ts, 10, 3))
|
||||
|
||||
var b = [[], []];
|
||||
>b : Symbol(b, Decl(arrayLiteralWidened.ts, 7, 3), Decl(arrayLiteralWidened.ts, 8, 3), Decl(arrayLiteralWidened.ts, 9, 3))
|
||||
>b : Symbol(b, Decl(arrayLiteralWidened.ts, 8, 3), Decl(arrayLiteralWidened.ts, 9, 3), Decl(arrayLiteralWidened.ts, 10, 3))
|
||||
|
||||
var b = [[undefined, undefined]];
|
||||
>b : Symbol(b, Decl(arrayLiteralWidened.ts, 7, 3), Decl(arrayLiteralWidened.ts, 8, 3), Decl(arrayLiteralWidened.ts, 9, 3))
|
||||
>b : Symbol(b, Decl(arrayLiteralWidened.ts, 8, 3), Decl(arrayLiteralWidened.ts, 9, 3), Decl(arrayLiteralWidened.ts, 10, 3))
|
||||
>undefined : Symbol(undefined)
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
var c = [[[]]]; // any[][][]
|
||||
>c : Symbol(c, Decl(arrayLiteralWidened.ts, 11, 3), Decl(arrayLiteralWidened.ts, 12, 3))
|
||||
>c : Symbol(c, Decl(arrayLiteralWidened.ts, 12, 3), Decl(arrayLiteralWidened.ts, 13, 3))
|
||||
|
||||
var c = [[[null]],[undefined]]
|
||||
>c : Symbol(c, Decl(arrayLiteralWidened.ts, 11, 3), Decl(arrayLiteralWidened.ts, 12, 3))
|
||||
>c : Symbol(c, Decl(arrayLiteralWidened.ts, 12, 3), Decl(arrayLiteralWidened.ts, 13, 3))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
// no widening when one or more elements are non-widening
|
||||
|
||||
var x: undefined = undefined;
|
||||
>x : Symbol(x, Decl(arrayLiteralWidened.ts, 17, 3))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
var d = [x];
|
||||
>d : Symbol(d, Decl(arrayLiteralWidened.ts, 19, 3), Decl(arrayLiteralWidened.ts, 20, 3), Decl(arrayLiteralWidened.ts, 21, 3))
|
||||
>x : Symbol(x, Decl(arrayLiteralWidened.ts, 17, 3))
|
||||
|
||||
var d = [, x];
|
||||
>d : Symbol(d, Decl(arrayLiteralWidened.ts, 19, 3), Decl(arrayLiteralWidened.ts, 20, 3), Decl(arrayLiteralWidened.ts, 21, 3))
|
||||
>x : Symbol(x, Decl(arrayLiteralWidened.ts, 17, 3))
|
||||
|
||||
var d = [undefined, x];
|
||||
>d : Symbol(d, Decl(arrayLiteralWidened.ts, 19, 3), Decl(arrayLiteralWidened.ts, 20, 3), Decl(arrayLiteralWidened.ts, 21, 3))
|
||||
>undefined : Symbol(undefined)
|
||||
>x : Symbol(x, Decl(arrayLiteralWidened.ts, 17, 3))
|
||||
|
||||
|
|
|
@ -5,6 +5,12 @@ var a = []; // any[]
|
|||
>a : any[]
|
||||
>[] : undefined[]
|
||||
|
||||
var a = [,,];
|
||||
>a : any[]
|
||||
>[,,] : undefined[]
|
||||
> : undefined
|
||||
> : undefined
|
||||
|
||||
var a = [null, null];
|
||||
>a : any[]
|
||||
>[null, null] : null[]
|
||||
|
@ -53,3 +59,26 @@ var c = [[[null]],[undefined]]
|
|||
>[undefined] : undefined[]
|
||||
>undefined : undefined
|
||||
|
||||
// no widening when one or more elements are non-widening
|
||||
|
||||
var x: undefined = undefined;
|
||||
>x : undefined
|
||||
>undefined : undefined
|
||||
|
||||
var d = [x];
|
||||
>d : undefined[]
|
||||
>[x] : undefined[]
|
||||
>x : undefined
|
||||
|
||||
var d = [, x];
|
||||
>d : undefined[]
|
||||
>[, x] : undefined[]
|
||||
> : undefined
|
||||
>x : undefined
|
||||
|
||||
var d = [undefined, x];
|
||||
>d : undefined[]
|
||||
>[undefined, x] : undefined[]
|
||||
>undefined : undefined
|
||||
>x : undefined
|
||||
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
//// [constLocalsInFunctionExpressions.ts]
|
||||
declare function getStringOrNumber(): string | number;
|
||||
|
||||
function f1() {
|
||||
const x = getStringOrNumber();
|
||||
if (typeof x === "string") {
|
||||
const f = () => x.length;
|
||||
}
|
||||
}
|
||||
|
||||
function f2() {
|
||||
const x = getStringOrNumber();
|
||||
if (typeof x !== "string") {
|
||||
return;
|
||||
}
|
||||
const f = () => x.length;
|
||||
}
|
||||
|
||||
function f3() {
|
||||
const x = getStringOrNumber();
|
||||
if (typeof x === "string") {
|
||||
const f = function() { return x.length; };
|
||||
}
|
||||
}
|
||||
|
||||
function f4() {
|
||||
const x = getStringOrNumber();
|
||||
if (typeof x !== "string") {
|
||||
return;
|
||||
}
|
||||
const f = function() { return x.length; };
|
||||
}
|
||||
|
||||
function f5() {
|
||||
const x = getStringOrNumber();
|
||||
if (typeof x === "string") {
|
||||
const f = () => () => x.length;
|
||||
}
|
||||
}
|
||||
|
||||
//// [constLocalsInFunctionExpressions.js]
|
||||
function f1() {
|
||||
var x = getStringOrNumber();
|
||||
if (typeof x === "string") {
|
||||
var f = function () { return x.length; };
|
||||
}
|
||||
}
|
||||
function f2() {
|
||||
var x = getStringOrNumber();
|
||||
if (typeof x !== "string") {
|
||||
return;
|
||||
}
|
||||
var f = function () { return x.length; };
|
||||
}
|
||||
function f3() {
|
||||
var x = getStringOrNumber();
|
||||
if (typeof x === "string") {
|
||||
var f = function () { return x.length; };
|
||||
}
|
||||
}
|
||||
function f4() {
|
||||
var x = getStringOrNumber();
|
||||
if (typeof x !== "string") {
|
||||
return;
|
||||
}
|
||||
var f = function () { return x.length; };
|
||||
}
|
||||
function f5() {
|
||||
var x = getStringOrNumber();
|
||||
if (typeof x === "string") {
|
||||
var f = function () { return function () { return x.length; }; };
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
=== tests/cases/conformance/controlFlow/constLocalsInFunctionExpressions.ts ===
|
||||
declare function getStringOrNumber(): string | number;
|
||||
>getStringOrNumber : Symbol(getStringOrNumber, Decl(constLocalsInFunctionExpressions.ts, 0, 0))
|
||||
|
||||
function f1() {
|
||||
>f1 : Symbol(f1, Decl(constLocalsInFunctionExpressions.ts, 0, 54))
|
||||
|
||||
const x = getStringOrNumber();
|
||||
>x : Symbol(x, Decl(constLocalsInFunctionExpressions.ts, 3, 9))
|
||||
>getStringOrNumber : Symbol(getStringOrNumber, Decl(constLocalsInFunctionExpressions.ts, 0, 0))
|
||||
|
||||
if (typeof x === "string") {
|
||||
>x : Symbol(x, Decl(constLocalsInFunctionExpressions.ts, 3, 9))
|
||||
|
||||
const f = () => x.length;
|
||||
>f : Symbol(f, Decl(constLocalsInFunctionExpressions.ts, 5, 13))
|
||||
>x.length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(constLocalsInFunctionExpressions.ts, 3, 9))
|
||||
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
}
|
||||
}
|
||||
|
||||
function f2() {
|
||||
>f2 : Symbol(f2, Decl(constLocalsInFunctionExpressions.ts, 7, 1))
|
||||
|
||||
const x = getStringOrNumber();
|
||||
>x : Symbol(x, Decl(constLocalsInFunctionExpressions.ts, 10, 9))
|
||||
>getStringOrNumber : Symbol(getStringOrNumber, Decl(constLocalsInFunctionExpressions.ts, 0, 0))
|
||||
|
||||
if (typeof x !== "string") {
|
||||
>x : Symbol(x, Decl(constLocalsInFunctionExpressions.ts, 10, 9))
|
||||
|
||||
return;
|
||||
}
|
||||
const f = () => x.length;
|
||||
>f : Symbol(f, Decl(constLocalsInFunctionExpressions.ts, 14, 9))
|
||||
>x.length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(constLocalsInFunctionExpressions.ts, 10, 9))
|
||||
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
}
|
||||
|
||||
function f3() {
|
||||
>f3 : Symbol(f3, Decl(constLocalsInFunctionExpressions.ts, 15, 1))
|
||||
|
||||
const x = getStringOrNumber();
|
||||
>x : Symbol(x, Decl(constLocalsInFunctionExpressions.ts, 18, 9))
|
||||
>getStringOrNumber : Symbol(getStringOrNumber, Decl(constLocalsInFunctionExpressions.ts, 0, 0))
|
||||
|
||||
if (typeof x === "string") {
|
||||
>x : Symbol(x, Decl(constLocalsInFunctionExpressions.ts, 18, 9))
|
||||
|
||||
const f = function() { return x.length; };
|
||||
>f : Symbol(f, Decl(constLocalsInFunctionExpressions.ts, 20, 13))
|
||||
>x.length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(constLocalsInFunctionExpressions.ts, 18, 9))
|
||||
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
}
|
||||
}
|
||||
|
||||
function f4() {
|
||||
>f4 : Symbol(f4, Decl(constLocalsInFunctionExpressions.ts, 22, 1))
|
||||
|
||||
const x = getStringOrNumber();
|
||||
>x : Symbol(x, Decl(constLocalsInFunctionExpressions.ts, 25, 9))
|
||||
>getStringOrNumber : Symbol(getStringOrNumber, Decl(constLocalsInFunctionExpressions.ts, 0, 0))
|
||||
|
||||
if (typeof x !== "string") {
|
||||
>x : Symbol(x, Decl(constLocalsInFunctionExpressions.ts, 25, 9))
|
||||
|
||||
return;
|
||||
}
|
||||
const f = function() { return x.length; };
|
||||
>f : Symbol(f, Decl(constLocalsInFunctionExpressions.ts, 29, 9))
|
||||
>x.length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(constLocalsInFunctionExpressions.ts, 25, 9))
|
||||
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
}
|
||||
|
||||
function f5() {
|
||||
>f5 : Symbol(f5, Decl(constLocalsInFunctionExpressions.ts, 30, 1))
|
||||
|
||||
const x = getStringOrNumber();
|
||||
>x : Symbol(x, Decl(constLocalsInFunctionExpressions.ts, 33, 9))
|
||||
>getStringOrNumber : Symbol(getStringOrNumber, Decl(constLocalsInFunctionExpressions.ts, 0, 0))
|
||||
|
||||
if (typeof x === "string") {
|
||||
>x : Symbol(x, Decl(constLocalsInFunctionExpressions.ts, 33, 9))
|
||||
|
||||
const f = () => () => x.length;
|
||||
>f : Symbol(f, Decl(constLocalsInFunctionExpressions.ts, 35, 13))
|
||||
>x.length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(constLocalsInFunctionExpressions.ts, 33, 9))
|
||||
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
}
|
||||
}
|
121
tests/baselines/reference/constLocalsInFunctionExpressions.types
Normal file
121
tests/baselines/reference/constLocalsInFunctionExpressions.types
Normal file
|
@ -0,0 +1,121 @@
|
|||
=== tests/cases/conformance/controlFlow/constLocalsInFunctionExpressions.ts ===
|
||||
declare function getStringOrNumber(): string | number;
|
||||
>getStringOrNumber : () => string | number
|
||||
|
||||
function f1() {
|
||||
>f1 : () => void
|
||||
|
||||
const x = getStringOrNumber();
|
||||
>x : string | number
|
||||
>getStringOrNumber() : string | number
|
||||
>getStringOrNumber : () => string | number
|
||||
|
||||
if (typeof x === "string") {
|
||||
>typeof x === "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number
|
||||
>"string" : string
|
||||
|
||||
const f = () => x.length;
|
||||
>f : () => number
|
||||
>() => x.length : () => number
|
||||
>x.length : number
|
||||
>x : string
|
||||
>length : number
|
||||
}
|
||||
}
|
||||
|
||||
function f2() {
|
||||
>f2 : () => void
|
||||
|
||||
const x = getStringOrNumber();
|
||||
>x : string | number
|
||||
>getStringOrNumber() : string | number
|
||||
>getStringOrNumber : () => string | number
|
||||
|
||||
if (typeof x !== "string") {
|
||||
>typeof x !== "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number
|
||||
>"string" : string
|
||||
|
||||
return;
|
||||
}
|
||||
const f = () => x.length;
|
||||
>f : () => number
|
||||
>() => x.length : () => number
|
||||
>x.length : number
|
||||
>x : string
|
||||
>length : number
|
||||
}
|
||||
|
||||
function f3() {
|
||||
>f3 : () => void
|
||||
|
||||
const x = getStringOrNumber();
|
||||
>x : string | number
|
||||
>getStringOrNumber() : string | number
|
||||
>getStringOrNumber : () => string | number
|
||||
|
||||
if (typeof x === "string") {
|
||||
>typeof x === "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number
|
||||
>"string" : string
|
||||
|
||||
const f = function() { return x.length; };
|
||||
>f : () => number
|
||||
>function() { return x.length; } : () => number
|
||||
>x.length : number
|
||||
>x : string
|
||||
>length : number
|
||||
}
|
||||
}
|
||||
|
||||
function f4() {
|
||||
>f4 : () => void
|
||||
|
||||
const x = getStringOrNumber();
|
||||
>x : string | number
|
||||
>getStringOrNumber() : string | number
|
||||
>getStringOrNumber : () => string | number
|
||||
|
||||
if (typeof x !== "string") {
|
||||
>typeof x !== "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number
|
||||
>"string" : string
|
||||
|
||||
return;
|
||||
}
|
||||
const f = function() { return x.length; };
|
||||
>f : () => number
|
||||
>function() { return x.length; } : () => number
|
||||
>x.length : number
|
||||
>x : string
|
||||
>length : number
|
||||
}
|
||||
|
||||
function f5() {
|
||||
>f5 : () => void
|
||||
|
||||
const x = getStringOrNumber();
|
||||
>x : string | number
|
||||
>getStringOrNumber() : string | number
|
||||
>getStringOrNumber : () => string | number
|
||||
|
||||
if (typeof x === "string") {
|
||||
>typeof x === "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number
|
||||
>"string" : string
|
||||
|
||||
const f = () => () => x.length;
|
||||
>f : () => () => number
|
||||
>() => () => x.length : () => () => number
|
||||
>() => x.length : () => number
|
||||
>x.length : number
|
||||
>x : string
|
||||
>length : number
|
||||
}
|
||||
}
|
89
tests/baselines/reference/controlFlowIIFE.js
Normal file
89
tests/baselines/reference/controlFlowIIFE.js
Normal file
|
@ -0,0 +1,89 @@
|
|||
//// [controlFlowIIFE.ts]
|
||||
|
||||
declare function getStringOrNumber(): string | number;
|
||||
|
||||
function f1() {
|
||||
let x = getStringOrNumber();
|
||||
if (typeof x === "string") {
|
||||
let n = function() {
|
||||
return x.length;
|
||||
}();
|
||||
}
|
||||
}
|
||||
|
||||
function f2() {
|
||||
let x = getStringOrNumber();
|
||||
if (typeof x === "string") {
|
||||
let n = (function() {
|
||||
return x.length;
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
function f3() {
|
||||
let x = getStringOrNumber();
|
||||
let y: number;
|
||||
if (typeof x === "string") {
|
||||
let n = (z => x.length + y + z)(y = 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Repros from #8381
|
||||
|
||||
let maybeNumber: number | undefined;
|
||||
(function () {
|
||||
maybeNumber = 1;
|
||||
})();
|
||||
maybeNumber++;
|
||||
if (maybeNumber !== undefined) {
|
||||
maybeNumber++;
|
||||
}
|
||||
|
||||
let test: string | undefined;
|
||||
if (!test) {
|
||||
throw new Error('Test is not defined');
|
||||
}
|
||||
(() => {
|
||||
test.slice(1); // No error
|
||||
})();
|
||||
|
||||
//// [controlFlowIIFE.js]
|
||||
function f1() {
|
||||
var x = getStringOrNumber();
|
||||
if (typeof x === "string") {
|
||||
var n = function () {
|
||||
return x.length;
|
||||
}();
|
||||
}
|
||||
}
|
||||
function f2() {
|
||||
var x = getStringOrNumber();
|
||||
if (typeof x === "string") {
|
||||
var n = (function () {
|
||||
return x.length;
|
||||
})();
|
||||
}
|
||||
}
|
||||
function f3() {
|
||||
var x = getStringOrNumber();
|
||||
var y;
|
||||
if (typeof x === "string") {
|
||||
var n = (function (z) { return x.length + y + z; })(y = 1);
|
||||
}
|
||||
}
|
||||
// Repros from #8381
|
||||
var maybeNumber;
|
||||
(function () {
|
||||
maybeNumber = 1;
|
||||
})();
|
||||
maybeNumber++;
|
||||
if (maybeNumber !== undefined) {
|
||||
maybeNumber++;
|
||||
}
|
||||
var test;
|
||||
if (!test) {
|
||||
throw new Error('Test is not defined');
|
||||
}
|
||||
(function () {
|
||||
test.slice(1); // No error
|
||||
})();
|
111
tests/baselines/reference/controlFlowIIFE.symbols
Normal file
111
tests/baselines/reference/controlFlowIIFE.symbols
Normal file
|
@ -0,0 +1,111 @@
|
|||
=== tests/cases/conformance/controlFlow/controlFlowIIFE.ts ===
|
||||
|
||||
declare function getStringOrNumber(): string | number;
|
||||
>getStringOrNumber : Symbol(getStringOrNumber, Decl(controlFlowIIFE.ts, 0, 0))
|
||||
|
||||
function f1() {
|
||||
>f1 : Symbol(f1, Decl(controlFlowIIFE.ts, 1, 54))
|
||||
|
||||
let x = getStringOrNumber();
|
||||
>x : Symbol(x, Decl(controlFlowIIFE.ts, 4, 7))
|
||||
>getStringOrNumber : Symbol(getStringOrNumber, Decl(controlFlowIIFE.ts, 0, 0))
|
||||
|
||||
if (typeof x === "string") {
|
||||
>x : Symbol(x, Decl(controlFlowIIFE.ts, 4, 7))
|
||||
|
||||
let n = function() {
|
||||
>n : Symbol(n, Decl(controlFlowIIFE.ts, 6, 11))
|
||||
|
||||
return x.length;
|
||||
>x.length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowIIFE.ts, 4, 7))
|
||||
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
|
||||
}();
|
||||
}
|
||||
}
|
||||
|
||||
function f2() {
|
||||
>f2 : Symbol(f2, Decl(controlFlowIIFE.ts, 10, 1))
|
||||
|
||||
let x = getStringOrNumber();
|
||||
>x : Symbol(x, Decl(controlFlowIIFE.ts, 13, 7))
|
||||
>getStringOrNumber : Symbol(getStringOrNumber, Decl(controlFlowIIFE.ts, 0, 0))
|
||||
|
||||
if (typeof x === "string") {
|
||||
>x : Symbol(x, Decl(controlFlowIIFE.ts, 13, 7))
|
||||
|
||||
let n = (function() {
|
||||
>n : Symbol(n, Decl(controlFlowIIFE.ts, 15, 11))
|
||||
|
||||
return x.length;
|
||||
>x.length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowIIFE.ts, 13, 7))
|
||||
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
function f3() {
|
||||
>f3 : Symbol(f3, Decl(controlFlowIIFE.ts, 19, 1))
|
||||
|
||||
let x = getStringOrNumber();
|
||||
>x : Symbol(x, Decl(controlFlowIIFE.ts, 22, 7))
|
||||
>getStringOrNumber : Symbol(getStringOrNumber, Decl(controlFlowIIFE.ts, 0, 0))
|
||||
|
||||
let y: number;
|
||||
>y : Symbol(y, Decl(controlFlowIIFE.ts, 23, 7))
|
||||
|
||||
if (typeof x === "string") {
|
||||
>x : Symbol(x, Decl(controlFlowIIFE.ts, 22, 7))
|
||||
|
||||
let n = (z => x.length + y + z)(y = 1);
|
||||
>n : Symbol(n, Decl(controlFlowIIFE.ts, 25, 11))
|
||||
>z : Symbol(z, Decl(controlFlowIIFE.ts, 25, 17))
|
||||
>x.length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowIIFE.ts, 22, 7))
|
||||
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
>y : Symbol(y, Decl(controlFlowIIFE.ts, 23, 7))
|
||||
>z : Symbol(z, Decl(controlFlowIIFE.ts, 25, 17))
|
||||
>y : Symbol(y, Decl(controlFlowIIFE.ts, 23, 7))
|
||||
}
|
||||
}
|
||||
|
||||
// Repros from #8381
|
||||
|
||||
let maybeNumber: number | undefined;
|
||||
>maybeNumber : Symbol(maybeNumber, Decl(controlFlowIIFE.ts, 31, 3))
|
||||
|
||||
(function () {
|
||||
maybeNumber = 1;
|
||||
>maybeNumber : Symbol(maybeNumber, Decl(controlFlowIIFE.ts, 31, 3))
|
||||
|
||||
})();
|
||||
maybeNumber++;
|
||||
>maybeNumber : Symbol(maybeNumber, Decl(controlFlowIIFE.ts, 31, 3))
|
||||
|
||||
if (maybeNumber !== undefined) {
|
||||
>maybeNumber : Symbol(maybeNumber, Decl(controlFlowIIFE.ts, 31, 3))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
maybeNumber++;
|
||||
>maybeNumber : Symbol(maybeNumber, Decl(controlFlowIIFE.ts, 31, 3))
|
||||
}
|
||||
|
||||
let test: string | undefined;
|
||||
>test : Symbol(test, Decl(controlFlowIIFE.ts, 40, 3))
|
||||
|
||||
if (!test) {
|
||||
>test : Symbol(test, Decl(controlFlowIIFE.ts, 40, 3))
|
||||
|
||||
throw new Error('Test is not defined');
|
||||
>Error : Symbol(Error, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
}
|
||||
(() => {
|
||||
test.slice(1); // No error
|
||||
>test.slice : Symbol(String.slice, Decl(lib.d.ts, --, --))
|
||||
>test : Symbol(test, Decl(controlFlowIIFE.ts, 40, 3))
|
||||
>slice : Symbol(String.slice, Decl(lib.d.ts, --, --))
|
||||
|
||||
})();
|
153
tests/baselines/reference/controlFlowIIFE.types
Normal file
153
tests/baselines/reference/controlFlowIIFE.types
Normal file
|
@ -0,0 +1,153 @@
|
|||
=== tests/cases/conformance/controlFlow/controlFlowIIFE.ts ===
|
||||
|
||||
declare function getStringOrNumber(): string | number;
|
||||
>getStringOrNumber : () => string | number
|
||||
|
||||
function f1() {
|
||||
>f1 : () => void
|
||||
|
||||
let x = getStringOrNumber();
|
||||
>x : string | number
|
||||
>getStringOrNumber() : string | number
|
||||
>getStringOrNumber : () => string | number
|
||||
|
||||
if (typeof x === "string") {
|
||||
>typeof x === "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number
|
||||
>"string" : string
|
||||
|
||||
let n = function() {
|
||||
>n : number
|
||||
>function() { return x.length; }() : number
|
||||
>function() { return x.length; } : () => number
|
||||
|
||||
return x.length;
|
||||
>x.length : number
|
||||
>x : string
|
||||
>length : number
|
||||
|
||||
}();
|
||||
}
|
||||
}
|
||||
|
||||
function f2() {
|
||||
>f2 : () => void
|
||||
|
||||
let x = getStringOrNumber();
|
||||
>x : string | number
|
||||
>getStringOrNumber() : string | number
|
||||
>getStringOrNumber : () => string | number
|
||||
|
||||
if (typeof x === "string") {
|
||||
>typeof x === "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number
|
||||
>"string" : string
|
||||
|
||||
let n = (function() {
|
||||
>n : number
|
||||
>(function() { return x.length; })() : number
|
||||
>(function() { return x.length; }) : () => number
|
||||
>function() { return x.length; } : () => number
|
||||
|
||||
return x.length;
|
||||
>x.length : number
|
||||
>x : string
|
||||
>length : number
|
||||
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
function f3() {
|
||||
>f3 : () => void
|
||||
|
||||
let x = getStringOrNumber();
|
||||
>x : string | number
|
||||
>getStringOrNumber() : string | number
|
||||
>getStringOrNumber : () => string | number
|
||||
|
||||
let y: number;
|
||||
>y : number
|
||||
|
||||
if (typeof x === "string") {
|
||||
>typeof x === "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number
|
||||
>"string" : string
|
||||
|
||||
let n = (z => x.length + y + z)(y = 1);
|
||||
>n : number
|
||||
>(z => x.length + y + z)(y = 1) : number
|
||||
>(z => x.length + y + z) : (z: number) => number
|
||||
>z => x.length + y + z : (z: number) => number
|
||||
>z : number
|
||||
>x.length + y + z : number
|
||||
>x.length + y : number
|
||||
>x.length : number
|
||||
>x : string
|
||||
>length : number
|
||||
>y : number
|
||||
>z : number
|
||||
>y = 1 : number
|
||||
>y : number
|
||||
>1 : number
|
||||
}
|
||||
}
|
||||
|
||||
// Repros from #8381
|
||||
|
||||
let maybeNumber: number | undefined;
|
||||
>maybeNumber : number | undefined
|
||||
|
||||
(function () {
|
||||
>(function () { maybeNumber = 1;})() : void
|
||||
>(function () { maybeNumber = 1;}) : () => void
|
||||
>function () { maybeNumber = 1;} : () => void
|
||||
|
||||
maybeNumber = 1;
|
||||
>maybeNumber = 1 : number
|
||||
>maybeNumber : number | undefined
|
||||
>1 : number
|
||||
|
||||
})();
|
||||
maybeNumber++;
|
||||
>maybeNumber++ : number
|
||||
>maybeNumber : number
|
||||
|
||||
if (maybeNumber !== undefined) {
|
||||
>maybeNumber !== undefined : boolean
|
||||
>maybeNumber : number
|
||||
>undefined : undefined
|
||||
|
||||
maybeNumber++;
|
||||
>maybeNumber++ : number
|
||||
>maybeNumber : number
|
||||
}
|
||||
|
||||
let test: string | undefined;
|
||||
>test : string | undefined
|
||||
|
||||
if (!test) {
|
||||
>!test : boolean
|
||||
>test : string | undefined
|
||||
|
||||
throw new Error('Test is not defined');
|
||||
>new Error('Test is not defined') : Error
|
||||
>Error : ErrorConstructor
|
||||
>'Test is not defined' : string
|
||||
}
|
||||
(() => {
|
||||
>(() => { test.slice(1); // No error})() : void
|
||||
>(() => { test.slice(1); // No error}) : () => void
|
||||
>() => { test.slice(1); // No error} : () => void
|
||||
|
||||
test.slice(1); // No error
|
||||
>test.slice(1) : string
|
||||
>test.slice : (start?: number | undefined, end?: number | undefined) => string
|
||||
>test : string
|
||||
>slice : (start?: number | undefined, end?: number | undefined) => string
|
||||
>1 : number
|
||||
|
||||
})();
|
291
tests/baselines/reference/controlFlowPropertyDeclarations.js
Normal file
291
tests/baselines/reference/controlFlowPropertyDeclarations.js
Normal file
|
@ -0,0 +1,291 @@
|
|||
//// [controlFlowPropertyDeclarations.ts]
|
||||
// Repro from ##8913
|
||||
|
||||
declare var require:any;
|
||||
|
||||
var HTMLDOMPropertyConfig = require('react/lib/HTMLDOMPropertyConfig');
|
||||
|
||||
// Populate property map with ReactJS's attribute and property mappings
|
||||
// TODO handle/use .Properties value eg: MUST_USE_PROPERTY is not HTML attr
|
||||
for (var propname in HTMLDOMPropertyConfig.Properties) {
|
||||
if (!HTMLDOMPropertyConfig.Properties.hasOwnProperty(propname)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var mapFrom = HTMLDOMPropertyConfig.DOMAttributeNames[propname] || propname.toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeats a string a certain number of times.
|
||||
* Also: the future is bright and consists of native string repetition:
|
||||
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat
|
||||
*
|
||||
* @param {string} string String to repeat
|
||||
* @param {number} times Number of times to repeat string. Integer.
|
||||
* @see http://jsperf.com/string-repeater/2
|
||||
*/
|
||||
function repeatString(string, times) {
|
||||
if (times === 1) {
|
||||
return string;
|
||||
}
|
||||
if (times < 0) { throw new Error(); }
|
||||
var repeated = '';
|
||||
while (times) {
|
||||
if (times & 1) {
|
||||
repeated += string;
|
||||
}
|
||||
if (times >>= 1) {
|
||||
string += string;
|
||||
}
|
||||
}
|
||||
return repeated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the string ends with the specified substring.
|
||||
*
|
||||
* @param {string} haystack String to search in
|
||||
* @param {string} needle String to search for
|
||||
* @return {boolean}
|
||||
*/
|
||||
function endsWith(haystack, needle) {
|
||||
return haystack.slice(-needle.length) === needle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim the specified substring off the string. If the string does not end
|
||||
* with the specified substring, this is a no-op.
|
||||
*
|
||||
* @param {string} haystack String to search in
|
||||
* @param {string} needle String to search for
|
||||
* @return {string}
|
||||
*/
|
||||
function trimEnd(haystack, needle) {
|
||||
return endsWith(haystack, needle)
|
||||
? haystack.slice(0, -needle.length)
|
||||
: haystack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a hyphenated string to camelCase.
|
||||
*/
|
||||
function hyphenToCamelCase(string) {
|
||||
return string.replace(/-(.)/g, function(match, chr) {
|
||||
return chr.toUpperCase();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the specified string consists entirely of whitespace.
|
||||
*/
|
||||
function isEmpty(string) {
|
||||
return !/[^\s]/.test(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the CSS value can be converted from a
|
||||
* 'px' suffixed string to a numeric value
|
||||
*
|
||||
* @param {string} value CSS property value
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isConvertiblePixelValue(value) {
|
||||
return /^\d+px$/.test(value);
|
||||
}
|
||||
|
||||
export class HTMLtoJSX {
|
||||
private output: string;
|
||||
private level: number;
|
||||
private _inPreTag: boolean;
|
||||
|
||||
|
||||
/**
|
||||
* Handles processing of the specified text node
|
||||
*
|
||||
* @param {TextNode} node
|
||||
*/
|
||||
_visitText = (node) => {
|
||||
var parentTag = node.parentNode && node.parentNode.tagName.toLowerCase();
|
||||
if (parentTag === 'textarea' || parentTag === 'style') {
|
||||
// Ignore text content of textareas and styles, as it will have already been moved
|
||||
// to a "defaultValue" attribute and "dangerouslySetInnerHTML" attribute respectively.
|
||||
return;
|
||||
}
|
||||
|
||||
var text = ''
|
||||
|
||||
if (this._inPreTag) {
|
||||
// If this text is contained within a <pre>, we need to ensure the JSX
|
||||
// whitespace coalescing rules don't eat the whitespace. This means
|
||||
// wrapping newlines and sequences of two or more spaces in variables.
|
||||
text = text
|
||||
.replace(/\r/g, '')
|
||||
.replace(/( {2,}|\n|\t|\{|\})/g, function(whitespace) {
|
||||
return '{' + JSON.stringify(whitespace) + '}';
|
||||
});
|
||||
} else {
|
||||
// If there's a newline in the text, adjust the indent level
|
||||
if (text.indexOf('\n') > -1) {
|
||||
}
|
||||
}
|
||||
this.output += text;
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles parsing of inline styles
|
||||
*/
|
||||
export class StyleParser {
|
||||
styles = {};
|
||||
toJSXString = () => {
|
||||
for (var key in this.styles) {
|
||||
if (!this.styles.hasOwnProperty(key)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//// [controlFlowPropertyDeclarations.js]
|
||||
// Repro from ##8913
|
||||
"use strict";
|
||||
var HTMLDOMPropertyConfig = require('react/lib/HTMLDOMPropertyConfig');
|
||||
// Populate property map with ReactJS's attribute and property mappings
|
||||
// TODO handle/use .Properties value eg: MUST_USE_PROPERTY is not HTML attr
|
||||
for (var propname in HTMLDOMPropertyConfig.Properties) {
|
||||
if (!HTMLDOMPropertyConfig.Properties.hasOwnProperty(propname)) {
|
||||
continue;
|
||||
}
|
||||
var mapFrom = HTMLDOMPropertyConfig.DOMAttributeNames[propname] || propname.toLowerCase();
|
||||
}
|
||||
/**
|
||||
* Repeats a string a certain number of times.
|
||||
* Also: the future is bright and consists of native string repetition:
|
||||
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat
|
||||
*
|
||||
* @param {string} string String to repeat
|
||||
* @param {number} times Number of times to repeat string. Integer.
|
||||
* @see http://jsperf.com/string-repeater/2
|
||||
*/
|
||||
function repeatString(string, times) {
|
||||
if (times === 1) {
|
||||
return string;
|
||||
}
|
||||
if (times < 0) {
|
||||
throw new Error();
|
||||
}
|
||||
var repeated = '';
|
||||
while (times) {
|
||||
if (times & 1) {
|
||||
repeated += string;
|
||||
}
|
||||
if (times >>= 1) {
|
||||
string += string;
|
||||
}
|
||||
}
|
||||
return repeated;
|
||||
}
|
||||
/**
|
||||
* Determine if the string ends with the specified substring.
|
||||
*
|
||||
* @param {string} haystack String to search in
|
||||
* @param {string} needle String to search for
|
||||
* @return {boolean}
|
||||
*/
|
||||
function endsWith(haystack, needle) {
|
||||
return haystack.slice(-needle.length) === needle;
|
||||
}
|
||||
/**
|
||||
* Trim the specified substring off the string. If the string does not end
|
||||
* with the specified substring, this is a no-op.
|
||||
*
|
||||
* @param {string} haystack String to search in
|
||||
* @param {string} needle String to search for
|
||||
* @return {string}
|
||||
*/
|
||||
function trimEnd(haystack, needle) {
|
||||
return endsWith(haystack, needle)
|
||||
? haystack.slice(0, -needle.length)
|
||||
: haystack;
|
||||
}
|
||||
/**
|
||||
* Convert a hyphenated string to camelCase.
|
||||
*/
|
||||
function hyphenToCamelCase(string) {
|
||||
return string.replace(/-(.)/g, function (match, chr) {
|
||||
return chr.toUpperCase();
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Determines if the specified string consists entirely of whitespace.
|
||||
*/
|
||||
function isEmpty(string) {
|
||||
return !/[^\s]/.test(string);
|
||||
}
|
||||
/**
|
||||
* Determines if the CSS value can be converted from a
|
||||
* 'px' suffixed string to a numeric value
|
||||
*
|
||||
* @param {string} value CSS property value
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isConvertiblePixelValue(value) {
|
||||
return /^\d+px$/.test(value);
|
||||
}
|
||||
var HTMLtoJSX = (function () {
|
||||
function HTMLtoJSX() {
|
||||
var _this = this;
|
||||
/**
|
||||
* Handles processing of the specified text node
|
||||
*
|
||||
* @param {TextNode} node
|
||||
*/
|
||||
this._visitText = function (node) {
|
||||
var parentTag = node.parentNode && node.parentNode.tagName.toLowerCase();
|
||||
if (parentTag === 'textarea' || parentTag === 'style') {
|
||||
// Ignore text content of textareas and styles, as it will have already been moved
|
||||
// to a "defaultValue" attribute and "dangerouslySetInnerHTML" attribute respectively.
|
||||
return;
|
||||
}
|
||||
var text = '';
|
||||
if (_this._inPreTag) {
|
||||
// If this text is contained within a <pre>, we need to ensure the JSX
|
||||
// whitespace coalescing rules don't eat the whitespace. This means
|
||||
// wrapping newlines and sequences of two or more spaces in variables.
|
||||
text = text
|
||||
.replace(/\r/g, '')
|
||||
.replace(/( {2,}|\n|\t|\{|\})/g, function (whitespace) {
|
||||
return '{' + JSON.stringify(whitespace) + '}';
|
||||
});
|
||||
}
|
||||
else {
|
||||
// If there's a newline in the text, adjust the indent level
|
||||
if (text.indexOf('\n') > -1) {
|
||||
}
|
||||
}
|
||||
_this.output += text;
|
||||
};
|
||||
}
|
||||
return HTMLtoJSX;
|
||||
}());
|
||||
exports.HTMLtoJSX = HTMLtoJSX;
|
||||
;
|
||||
/**
|
||||
* Handles parsing of inline styles
|
||||
*/
|
||||
var StyleParser = (function () {
|
||||
function StyleParser() {
|
||||
var _this = this;
|
||||
this.styles = {};
|
||||
this.toJSXString = function () {
|
||||
for (var key in _this.styles) {
|
||||
if (!_this.styles.hasOwnProperty(key)) {
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
return StyleParser;
|
||||
}());
|
||||
exports.StyleParser = StyleParser;
|
|
@ -0,0 +1,288 @@
|
|||
=== tests/cases/compiler/controlFlowPropertyDeclarations.ts ===
|
||||
// Repro from ##8913
|
||||
|
||||
declare var require:any;
|
||||
>require : Symbol(require, Decl(controlFlowPropertyDeclarations.ts, 2, 11))
|
||||
|
||||
var HTMLDOMPropertyConfig = require('react/lib/HTMLDOMPropertyConfig');
|
||||
>HTMLDOMPropertyConfig : Symbol(HTMLDOMPropertyConfig, Decl(controlFlowPropertyDeclarations.ts, 4, 3))
|
||||
>require : Symbol(require, Decl(controlFlowPropertyDeclarations.ts, 2, 11))
|
||||
|
||||
// Populate property map with ReactJS's attribute and property mappings
|
||||
// TODO handle/use .Properties value eg: MUST_USE_PROPERTY is not HTML attr
|
||||
for (var propname in HTMLDOMPropertyConfig.Properties) {
|
||||
>propname : Symbol(propname, Decl(controlFlowPropertyDeclarations.ts, 8, 8))
|
||||
>HTMLDOMPropertyConfig : Symbol(HTMLDOMPropertyConfig, Decl(controlFlowPropertyDeclarations.ts, 4, 3))
|
||||
|
||||
if (!HTMLDOMPropertyConfig.Properties.hasOwnProperty(propname)) {
|
||||
>HTMLDOMPropertyConfig : Symbol(HTMLDOMPropertyConfig, Decl(controlFlowPropertyDeclarations.ts, 4, 3))
|
||||
>propname : Symbol(propname, Decl(controlFlowPropertyDeclarations.ts, 8, 8))
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var mapFrom = HTMLDOMPropertyConfig.DOMAttributeNames[propname] || propname.toLowerCase();
|
||||
>mapFrom : Symbol(mapFrom, Decl(controlFlowPropertyDeclarations.ts, 13, 5))
|
||||
>HTMLDOMPropertyConfig : Symbol(HTMLDOMPropertyConfig, Decl(controlFlowPropertyDeclarations.ts, 4, 3))
|
||||
>propname : Symbol(propname, Decl(controlFlowPropertyDeclarations.ts, 8, 8))
|
||||
>propname.toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, --, --))
|
||||
>propname : Symbol(propname, Decl(controlFlowPropertyDeclarations.ts, 8, 8))
|
||||
>toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, --, --))
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeats a string a certain number of times.
|
||||
* Also: the future is bright and consists of native string repetition:
|
||||
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat
|
||||
*
|
||||
* @param {string} string String to repeat
|
||||
* @param {number} times Number of times to repeat string. Integer.
|
||||
* @see http://jsperf.com/string-repeater/2
|
||||
*/
|
||||
function repeatString(string, times) {
|
||||
>repeatString : Symbol(repeatString, Decl(controlFlowPropertyDeclarations.ts, 14, 1))
|
||||
>string : Symbol(string, Decl(controlFlowPropertyDeclarations.ts, 25, 22))
|
||||
>times : Symbol(times, Decl(controlFlowPropertyDeclarations.ts, 25, 29))
|
||||
|
||||
if (times === 1) {
|
||||
>times : Symbol(times, Decl(controlFlowPropertyDeclarations.ts, 25, 29))
|
||||
|
||||
return string;
|
||||
>string : Symbol(string, Decl(controlFlowPropertyDeclarations.ts, 25, 22))
|
||||
}
|
||||
if (times < 0) { throw new Error(); }
|
||||
>times : Symbol(times, Decl(controlFlowPropertyDeclarations.ts, 25, 29))
|
||||
>Error : Symbol(Error, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
|
||||
var repeated = '';
|
||||
>repeated : Symbol(repeated, Decl(controlFlowPropertyDeclarations.ts, 30, 5))
|
||||
|
||||
while (times) {
|
||||
>times : Symbol(times, Decl(controlFlowPropertyDeclarations.ts, 25, 29))
|
||||
|
||||
if (times & 1) {
|
||||
>times : Symbol(times, Decl(controlFlowPropertyDeclarations.ts, 25, 29))
|
||||
|
||||
repeated += string;
|
||||
>repeated : Symbol(repeated, Decl(controlFlowPropertyDeclarations.ts, 30, 5))
|
||||
>string : Symbol(string, Decl(controlFlowPropertyDeclarations.ts, 25, 22))
|
||||
}
|
||||
if (times >>= 1) {
|
||||
>times : Symbol(times, Decl(controlFlowPropertyDeclarations.ts, 25, 29))
|
||||
|
||||
string += string;
|
||||
>string : Symbol(string, Decl(controlFlowPropertyDeclarations.ts, 25, 22))
|
||||
>string : Symbol(string, Decl(controlFlowPropertyDeclarations.ts, 25, 22))
|
||||
}
|
||||
}
|
||||
return repeated;
|
||||
>repeated : Symbol(repeated, Decl(controlFlowPropertyDeclarations.ts, 30, 5))
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the string ends with the specified substring.
|
||||
*
|
||||
* @param {string} haystack String to search in
|
||||
* @param {string} needle String to search for
|
||||
* @return {boolean}
|
||||
*/
|
||||
function endsWith(haystack, needle) {
|
||||
>endsWith : Symbol(endsWith, Decl(controlFlowPropertyDeclarations.ts, 40, 1))
|
||||
>haystack : Symbol(haystack, Decl(controlFlowPropertyDeclarations.ts, 49, 18))
|
||||
>needle : Symbol(needle, Decl(controlFlowPropertyDeclarations.ts, 49, 27))
|
||||
|
||||
return haystack.slice(-needle.length) === needle;
|
||||
>haystack : Symbol(haystack, Decl(controlFlowPropertyDeclarations.ts, 49, 18))
|
||||
>needle : Symbol(needle, Decl(controlFlowPropertyDeclarations.ts, 49, 27))
|
||||
>needle : Symbol(needle, Decl(controlFlowPropertyDeclarations.ts, 49, 27))
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim the specified substring off the string. If the string does not end
|
||||
* with the specified substring, this is a no-op.
|
||||
*
|
||||
* @param {string} haystack String to search in
|
||||
* @param {string} needle String to search for
|
||||
* @return {string}
|
||||
*/
|
||||
function trimEnd(haystack, needle) {
|
||||
>trimEnd : Symbol(trimEnd, Decl(controlFlowPropertyDeclarations.ts, 51, 1))
|
||||
>haystack : Symbol(haystack, Decl(controlFlowPropertyDeclarations.ts, 61, 17))
|
||||
>needle : Symbol(needle, Decl(controlFlowPropertyDeclarations.ts, 61, 26))
|
||||
|
||||
return endsWith(haystack, needle)
|
||||
>endsWith : Symbol(endsWith, Decl(controlFlowPropertyDeclarations.ts, 40, 1))
|
||||
>haystack : Symbol(haystack, Decl(controlFlowPropertyDeclarations.ts, 61, 17))
|
||||
>needle : Symbol(needle, Decl(controlFlowPropertyDeclarations.ts, 61, 26))
|
||||
|
||||
? haystack.slice(0, -needle.length)
|
||||
>haystack : Symbol(haystack, Decl(controlFlowPropertyDeclarations.ts, 61, 17))
|
||||
>needle : Symbol(needle, Decl(controlFlowPropertyDeclarations.ts, 61, 26))
|
||||
|
||||
: haystack;
|
||||
>haystack : Symbol(haystack, Decl(controlFlowPropertyDeclarations.ts, 61, 17))
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a hyphenated string to camelCase.
|
||||
*/
|
||||
function hyphenToCamelCase(string) {
|
||||
>hyphenToCamelCase : Symbol(hyphenToCamelCase, Decl(controlFlowPropertyDeclarations.ts, 65, 1))
|
||||
>string : Symbol(string, Decl(controlFlowPropertyDeclarations.ts, 70, 27))
|
||||
|
||||
return string.replace(/-(.)/g, function(match, chr) {
|
||||
>string : Symbol(string, Decl(controlFlowPropertyDeclarations.ts, 70, 27))
|
||||
>match : Symbol(match, Decl(controlFlowPropertyDeclarations.ts, 71, 42))
|
||||
>chr : Symbol(chr, Decl(controlFlowPropertyDeclarations.ts, 71, 48))
|
||||
|
||||
return chr.toUpperCase();
|
||||
>chr : Symbol(chr, Decl(controlFlowPropertyDeclarations.ts, 71, 48))
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the specified string consists entirely of whitespace.
|
||||
*/
|
||||
function isEmpty(string) {
|
||||
>isEmpty : Symbol(isEmpty, Decl(controlFlowPropertyDeclarations.ts, 74, 1))
|
||||
>string : Symbol(string, Decl(controlFlowPropertyDeclarations.ts, 79, 17))
|
||||
|
||||
return !/[^\s]/.test(string);
|
||||
>/[^\s]/.test : Symbol(RegExp.test, Decl(lib.d.ts, --, --))
|
||||
>test : Symbol(RegExp.test, Decl(lib.d.ts, --, --))
|
||||
>string : Symbol(string, Decl(controlFlowPropertyDeclarations.ts, 79, 17))
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the CSS value can be converted from a
|
||||
* 'px' suffixed string to a numeric value
|
||||
*
|
||||
* @param {string} value CSS property value
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isConvertiblePixelValue(value) {
|
||||
>isConvertiblePixelValue : Symbol(isConvertiblePixelValue, Decl(controlFlowPropertyDeclarations.ts, 81, 1))
|
||||
>value : Symbol(value, Decl(controlFlowPropertyDeclarations.ts, 90, 33))
|
||||
|
||||
return /^\d+px$/.test(value);
|
||||
>/^\d+px$/.test : Symbol(RegExp.test, Decl(lib.d.ts, --, --))
|
||||
>test : Symbol(RegExp.test, Decl(lib.d.ts, --, --))
|
||||
>value : Symbol(value, Decl(controlFlowPropertyDeclarations.ts, 90, 33))
|
||||
}
|
||||
|
||||
export class HTMLtoJSX {
|
||||
>HTMLtoJSX : Symbol(HTMLtoJSX, Decl(controlFlowPropertyDeclarations.ts, 92, 1))
|
||||
|
||||
private output: string;
|
||||
>output : Symbol(HTMLtoJSX.output, Decl(controlFlowPropertyDeclarations.ts, 94, 24))
|
||||
|
||||
private level: number;
|
||||
>level : Symbol(HTMLtoJSX.level, Decl(controlFlowPropertyDeclarations.ts, 95, 27))
|
||||
|
||||
private _inPreTag: boolean;
|
||||
>_inPreTag : Symbol(HTMLtoJSX._inPreTag, Decl(controlFlowPropertyDeclarations.ts, 96, 26))
|
||||
|
||||
|
||||
/**
|
||||
* Handles processing of the specified text node
|
||||
*
|
||||
* @param {TextNode} node
|
||||
*/
|
||||
_visitText = (node) => {
|
||||
>_visitText : Symbol(HTMLtoJSX._visitText, Decl(controlFlowPropertyDeclarations.ts, 97, 31))
|
||||
>node : Symbol(node, Decl(controlFlowPropertyDeclarations.ts, 105, 16))
|
||||
|
||||
var parentTag = node.parentNode && node.parentNode.tagName.toLowerCase();
|
||||
>parentTag : Symbol(parentTag, Decl(controlFlowPropertyDeclarations.ts, 106, 7))
|
||||
>node : Symbol(node, Decl(controlFlowPropertyDeclarations.ts, 105, 16))
|
||||
>node : Symbol(node, Decl(controlFlowPropertyDeclarations.ts, 105, 16))
|
||||
|
||||
if (parentTag === 'textarea' || parentTag === 'style') {
|
||||
>parentTag : Symbol(parentTag, Decl(controlFlowPropertyDeclarations.ts, 106, 7))
|
||||
>parentTag : Symbol(parentTag, Decl(controlFlowPropertyDeclarations.ts, 106, 7))
|
||||
|
||||
// Ignore text content of textareas and styles, as it will have already been moved
|
||||
// to a "defaultValue" attribute and "dangerouslySetInnerHTML" attribute respectively.
|
||||
return;
|
||||
}
|
||||
|
||||
var text = ''
|
||||
>text : Symbol(text, Decl(controlFlowPropertyDeclarations.ts, 113, 7))
|
||||
|
||||
if (this._inPreTag) {
|
||||
>this._inPreTag : Symbol(HTMLtoJSX._inPreTag, Decl(controlFlowPropertyDeclarations.ts, 96, 26))
|
||||
>this : Symbol(HTMLtoJSX, Decl(controlFlowPropertyDeclarations.ts, 92, 1))
|
||||
>_inPreTag : Symbol(HTMLtoJSX._inPreTag, Decl(controlFlowPropertyDeclarations.ts, 96, 26))
|
||||
|
||||
// If this text is contained within a <pre>, we need to ensure the JSX
|
||||
// whitespace coalescing rules don't eat the whitespace. This means
|
||||
// wrapping newlines and sequences of two or more spaces in variables.
|
||||
text = text
|
||||
>text : Symbol(text, Decl(controlFlowPropertyDeclarations.ts, 113, 7))
|
||||
>text .replace(/\r/g, '') .replace : Symbol(String.replace, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>text .replace : Symbol(String.replace, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>text : Symbol(text, Decl(controlFlowPropertyDeclarations.ts, 113, 7))
|
||||
|
||||
.replace(/\r/g, '')
|
||||
>replace : Symbol(String.replace, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
|
||||
.replace(/( {2,}|\n|\t|\{|\})/g, function(whitespace) {
|
||||
>replace : Symbol(String.replace, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>whitespace : Symbol(whitespace, Decl(controlFlowPropertyDeclarations.ts, 121, 50))
|
||||
|
||||
return '{' + JSON.stringify(whitespace) + '}';
|
||||
>JSON.stringify : Symbol(JSON.stringify, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>JSON : Symbol(JSON, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>stringify : Symbol(JSON.stringify, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>whitespace : Symbol(whitespace, Decl(controlFlowPropertyDeclarations.ts, 121, 50))
|
||||
|
||||
});
|
||||
} else {
|
||||
// If there's a newline in the text, adjust the indent level
|
||||
if (text.indexOf('\n') > -1) {
|
||||
>text.indexOf : Symbol(String.indexOf, Decl(lib.d.ts, --, --))
|
||||
>text : Symbol(text, Decl(controlFlowPropertyDeclarations.ts, 113, 7))
|
||||
>indexOf : Symbol(String.indexOf, Decl(lib.d.ts, --, --))
|
||||
}
|
||||
}
|
||||
this.output += text;
|
||||
>this.output : Symbol(HTMLtoJSX.output, Decl(controlFlowPropertyDeclarations.ts, 94, 24))
|
||||
>this : Symbol(HTMLtoJSX, Decl(controlFlowPropertyDeclarations.ts, 92, 1))
|
||||
>output : Symbol(HTMLtoJSX.output, Decl(controlFlowPropertyDeclarations.ts, 94, 24))
|
||||
>text : Symbol(text, Decl(controlFlowPropertyDeclarations.ts, 113, 7))
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles parsing of inline styles
|
||||
*/
|
||||
export class StyleParser {
|
||||
>StyleParser : Symbol(StyleParser, Decl(controlFlowPropertyDeclarations.ts, 134, 2))
|
||||
|
||||
styles = {};
|
||||
>styles : Symbol(StyleParser.styles, Decl(controlFlowPropertyDeclarations.ts, 139, 26))
|
||||
|
||||
toJSXString = () => {
|
||||
>toJSXString : Symbol(StyleParser.toJSXString, Decl(controlFlowPropertyDeclarations.ts, 140, 14))
|
||||
|
||||
for (var key in this.styles) {
|
||||
>key : Symbol(key, Decl(controlFlowPropertyDeclarations.ts, 142, 12))
|
||||
>this.styles : Symbol(StyleParser.styles, Decl(controlFlowPropertyDeclarations.ts, 139, 26))
|
||||
>this : Symbol(StyleParser, Decl(controlFlowPropertyDeclarations.ts, 134, 2))
|
||||
>styles : Symbol(StyleParser.styles, Decl(controlFlowPropertyDeclarations.ts, 139, 26))
|
||||
|
||||
if (!this.styles.hasOwnProperty(key)) {
|
||||
>this.styles.hasOwnProperty : Symbol(Object.hasOwnProperty, Decl(lib.d.ts, --, --))
|
||||
>this.styles : Symbol(StyleParser.styles, Decl(controlFlowPropertyDeclarations.ts, 139, 26))
|
||||
>this : Symbol(StyleParser, Decl(controlFlowPropertyDeclarations.ts, 134, 2))
|
||||
>styles : Symbol(StyleParser.styles, Decl(controlFlowPropertyDeclarations.ts, 139, 26))
|
||||
>hasOwnProperty : Symbol(Object.hasOwnProperty, Decl(lib.d.ts, --, --))
|
||||
>key : Symbol(key, Decl(controlFlowPropertyDeclarations.ts, 142, 12))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
383
tests/baselines/reference/controlFlowPropertyDeclarations.types
Normal file
383
tests/baselines/reference/controlFlowPropertyDeclarations.types
Normal file
|
@ -0,0 +1,383 @@
|
|||
=== tests/cases/compiler/controlFlowPropertyDeclarations.ts ===
|
||||
// Repro from ##8913
|
||||
|
||||
declare var require:any;
|
||||
>require : any
|
||||
|
||||
var HTMLDOMPropertyConfig = require('react/lib/HTMLDOMPropertyConfig');
|
||||
>HTMLDOMPropertyConfig : any
|
||||
>require('react/lib/HTMLDOMPropertyConfig') : any
|
||||
>require : any
|
||||
>'react/lib/HTMLDOMPropertyConfig' : string
|
||||
|
||||
// Populate property map with ReactJS's attribute and property mappings
|
||||
// TODO handle/use .Properties value eg: MUST_USE_PROPERTY is not HTML attr
|
||||
for (var propname in HTMLDOMPropertyConfig.Properties) {
|
||||
>propname : string
|
||||
>HTMLDOMPropertyConfig.Properties : any
|
||||
>HTMLDOMPropertyConfig : any
|
||||
>Properties : any
|
||||
|
||||
if (!HTMLDOMPropertyConfig.Properties.hasOwnProperty(propname)) {
|
||||
>!HTMLDOMPropertyConfig.Properties.hasOwnProperty(propname) : boolean
|
||||
>HTMLDOMPropertyConfig.Properties.hasOwnProperty(propname) : any
|
||||
>HTMLDOMPropertyConfig.Properties.hasOwnProperty : any
|
||||
>HTMLDOMPropertyConfig.Properties : any
|
||||
>HTMLDOMPropertyConfig : any
|
||||
>Properties : any
|
||||
>hasOwnProperty : any
|
||||
>propname : string
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var mapFrom = HTMLDOMPropertyConfig.DOMAttributeNames[propname] || propname.toLowerCase();
|
||||
>mapFrom : any
|
||||
>HTMLDOMPropertyConfig.DOMAttributeNames[propname] || propname.toLowerCase() : any
|
||||
>HTMLDOMPropertyConfig.DOMAttributeNames[propname] : any
|
||||
>HTMLDOMPropertyConfig.DOMAttributeNames : any
|
||||
>HTMLDOMPropertyConfig : any
|
||||
>DOMAttributeNames : any
|
||||
>propname : string
|
||||
>propname.toLowerCase() : string
|
||||
>propname.toLowerCase : () => string
|
||||
>propname : string
|
||||
>toLowerCase : () => string
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeats a string a certain number of times.
|
||||
* Also: the future is bright and consists of native string repetition:
|
||||
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat
|
||||
*
|
||||
* @param {string} string String to repeat
|
||||
* @param {number} times Number of times to repeat string. Integer.
|
||||
* @see http://jsperf.com/string-repeater/2
|
||||
*/
|
||||
function repeatString(string, times) {
|
||||
>repeatString : (string: any, times: any) => any
|
||||
>string : any
|
||||
>times : any
|
||||
|
||||
if (times === 1) {
|
||||
>times === 1 : boolean
|
||||
>times : any
|
||||
>1 : number
|
||||
|
||||
return string;
|
||||
>string : any
|
||||
}
|
||||
if (times < 0) { throw new Error(); }
|
||||
>times < 0 : boolean
|
||||
>times : any
|
||||
>0 : number
|
||||
>new Error() : Error
|
||||
>Error : ErrorConstructor
|
||||
|
||||
var repeated = '';
|
||||
>repeated : string
|
||||
>'' : string
|
||||
|
||||
while (times) {
|
||||
>times : any
|
||||
|
||||
if (times & 1) {
|
||||
>times & 1 : number
|
||||
>times : any
|
||||
>1 : number
|
||||
|
||||
repeated += string;
|
||||
>repeated += string : string
|
||||
>repeated : string
|
||||
>string : any
|
||||
}
|
||||
if (times >>= 1) {
|
||||
>times >>= 1 : number
|
||||
>times : any
|
||||
>1 : number
|
||||
|
||||
string += string;
|
||||
>string += string : any
|
||||
>string : any
|
||||
>string : any
|
||||
}
|
||||
}
|
||||
return repeated;
|
||||
>repeated : string
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the string ends with the specified substring.
|
||||
*
|
||||
* @param {string} haystack String to search in
|
||||
* @param {string} needle String to search for
|
||||
* @return {boolean}
|
||||
*/
|
||||
function endsWith(haystack, needle) {
|
||||
>endsWith : (haystack: any, needle: any) => boolean
|
||||
>haystack : any
|
||||
>needle : any
|
||||
|
||||
return haystack.slice(-needle.length) === needle;
|
||||
>haystack.slice(-needle.length) === needle : boolean
|
||||
>haystack.slice(-needle.length) : any
|
||||
>haystack.slice : any
|
||||
>haystack : any
|
||||
>slice : any
|
||||
>-needle.length : number
|
||||
>needle.length : any
|
||||
>needle : any
|
||||
>length : any
|
||||
>needle : any
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim the specified substring off the string. If the string does not end
|
||||
* with the specified substring, this is a no-op.
|
||||
*
|
||||
* @param {string} haystack String to search in
|
||||
* @param {string} needle String to search for
|
||||
* @return {string}
|
||||
*/
|
||||
function trimEnd(haystack, needle) {
|
||||
>trimEnd : (haystack: any, needle: any) => any
|
||||
>haystack : any
|
||||
>needle : any
|
||||
|
||||
return endsWith(haystack, needle)
|
||||
>endsWith(haystack, needle) ? haystack.slice(0, -needle.length) : haystack : any
|
||||
>endsWith(haystack, needle) : boolean
|
||||
>endsWith : (haystack: any, needle: any) => boolean
|
||||
>haystack : any
|
||||
>needle : any
|
||||
|
||||
? haystack.slice(0, -needle.length)
|
||||
>haystack.slice(0, -needle.length) : any
|
||||
>haystack.slice : any
|
||||
>haystack : any
|
||||
>slice : any
|
||||
>0 : number
|
||||
>-needle.length : number
|
||||
>needle.length : any
|
||||
>needle : any
|
||||
>length : any
|
||||
|
||||
: haystack;
|
||||
>haystack : any
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a hyphenated string to camelCase.
|
||||
*/
|
||||
function hyphenToCamelCase(string) {
|
||||
>hyphenToCamelCase : (string: any) => any
|
||||
>string : any
|
||||
|
||||
return string.replace(/-(.)/g, function(match, chr) {
|
||||
>string.replace(/-(.)/g, function(match, chr) { return chr.toUpperCase(); }) : any
|
||||
>string.replace : any
|
||||
>string : any
|
||||
>replace : any
|
||||
>/-(.)/g : RegExp
|
||||
>function(match, chr) { return chr.toUpperCase(); } : (match: any, chr: any) => any
|
||||
>match : any
|
||||
>chr : any
|
||||
|
||||
return chr.toUpperCase();
|
||||
>chr.toUpperCase() : any
|
||||
>chr.toUpperCase : any
|
||||
>chr : any
|
||||
>toUpperCase : any
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the specified string consists entirely of whitespace.
|
||||
*/
|
||||
function isEmpty(string) {
|
||||
>isEmpty : (string: any) => boolean
|
||||
>string : any
|
||||
|
||||
return !/[^\s]/.test(string);
|
||||
>!/[^\s]/.test(string) : boolean
|
||||
>/[^\s]/.test(string) : boolean
|
||||
>/[^\s]/.test : (string: string) => boolean
|
||||
>/[^\s]/ : RegExp
|
||||
>test : (string: string) => boolean
|
||||
>string : any
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the CSS value can be converted from a
|
||||
* 'px' suffixed string to a numeric value
|
||||
*
|
||||
* @param {string} value CSS property value
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isConvertiblePixelValue(value) {
|
||||
>isConvertiblePixelValue : (value: any) => boolean
|
||||
>value : any
|
||||
|
||||
return /^\d+px$/.test(value);
|
||||
>/^\d+px$/.test(value) : boolean
|
||||
>/^\d+px$/.test : (string: string) => boolean
|
||||
>/^\d+px$/ : RegExp
|
||||
>test : (string: string) => boolean
|
||||
>value : any
|
||||
}
|
||||
|
||||
export class HTMLtoJSX {
|
||||
>HTMLtoJSX : HTMLtoJSX
|
||||
|
||||
private output: string;
|
||||
>output : string
|
||||
|
||||
private level: number;
|
||||
>level : number
|
||||
|
||||
private _inPreTag: boolean;
|
||||
>_inPreTag : boolean
|
||||
|
||||
|
||||
/**
|
||||
* Handles processing of the specified text node
|
||||
*
|
||||
* @param {TextNode} node
|
||||
*/
|
||||
_visitText = (node) => {
|
||||
>_visitText : (node: any) => void
|
||||
>(node) => { var parentTag = node.parentNode && node.parentNode.tagName.toLowerCase(); if (parentTag === 'textarea' || parentTag === 'style') { // Ignore text content of textareas and styles, as it will have already been moved // to a "defaultValue" attribute and "dangerouslySetInnerHTML" attribute respectively. return; } var text = '' if (this._inPreTag) { // If this text is contained within a <pre>, we need to ensure the JSX // whitespace coalescing rules don't eat the whitespace. This means // wrapping newlines and sequences of two or more spaces in variables. text = text .replace(/\r/g, '') .replace(/( {2,}|\n|\t|\{|\})/g, function(whitespace) { return '{' + JSON.stringify(whitespace) + '}'; }); } else { // If there's a newline in the text, adjust the indent level if (text.indexOf('\n') > -1) { } } this.output += text; } : (node: any) => void
|
||||
>node : any
|
||||
|
||||
var parentTag = node.parentNode && node.parentNode.tagName.toLowerCase();
|
||||
>parentTag : any
|
||||
>node.parentNode && node.parentNode.tagName.toLowerCase() : any
|
||||
>node.parentNode : any
|
||||
>node : any
|
||||
>parentNode : any
|
||||
>node.parentNode.tagName.toLowerCase() : any
|
||||
>node.parentNode.tagName.toLowerCase : any
|
||||
>node.parentNode.tagName : any
|
||||
>node.parentNode : any
|
||||
>node : any
|
||||
>parentNode : any
|
||||
>tagName : any
|
||||
>toLowerCase : any
|
||||
|
||||
if (parentTag === 'textarea' || parentTag === 'style') {
|
||||
>parentTag === 'textarea' || parentTag === 'style' : boolean
|
||||
>parentTag === 'textarea' : boolean
|
||||
>parentTag : any
|
||||
>'textarea' : string
|
||||
>parentTag === 'style' : boolean
|
||||
>parentTag : any
|
||||
>'style' : string
|
||||
|
||||
// Ignore text content of textareas and styles, as it will have already been moved
|
||||
// to a "defaultValue" attribute and "dangerouslySetInnerHTML" attribute respectively.
|
||||
return;
|
||||
}
|
||||
|
||||
var text = ''
|
||||
>text : string
|
||||
>'' : string
|
||||
|
||||
if (this._inPreTag) {
|
||||
>this._inPreTag : boolean
|
||||
>this : this
|
||||
>_inPreTag : boolean
|
||||
|
||||
// If this text is contained within a <pre>, we need to ensure the JSX
|
||||
// whitespace coalescing rules don't eat the whitespace. This means
|
||||
// wrapping newlines and sequences of two or more spaces in variables.
|
||||
text = text
|
||||
>text = text .replace(/\r/g, '') .replace(/( {2,}|\n|\t|\{|\})/g, function(whitespace) { return '{' + JSON.stringify(whitespace) + '}'; }) : string
|
||||
>text : string
|
||||
>text .replace(/\r/g, '') .replace(/( {2,}|\n|\t|\{|\})/g, function(whitespace) { return '{' + JSON.stringify(whitespace) + '}'; }) : string
|
||||
>text .replace(/\r/g, '') .replace : { (searchValue: string, replaceValue: string): string; (searchValue: string, replacer: (substring: string, ...args: any[]) => string): string; (searchValue: RegExp, replaceValue: string): string; (searchValue: RegExp, replacer: (substring: string, ...args: any[]) => string): string; }
|
||||
>text .replace(/\r/g, '') : string
|
||||
>text .replace : { (searchValue: string, replaceValue: string): string; (searchValue: string, replacer: (substring: string, ...args: any[]) => string): string; (searchValue: RegExp, replaceValue: string): string; (searchValue: RegExp, replacer: (substring: string, ...args: any[]) => string): string; }
|
||||
>text : string
|
||||
|
||||
.replace(/\r/g, '')
|
||||
>replace : { (searchValue: string, replaceValue: string): string; (searchValue: string, replacer: (substring: string, ...args: any[]) => string): string; (searchValue: RegExp, replaceValue: string): string; (searchValue: RegExp, replacer: (substring: string, ...args: any[]) => string): string; }
|
||||
>/\r/g : RegExp
|
||||
>'' : string
|
||||
|
||||
.replace(/( {2,}|\n|\t|\{|\})/g, function(whitespace) {
|
||||
>replace : { (searchValue: string, replaceValue: string): string; (searchValue: string, replacer: (substring: string, ...args: any[]) => string): string; (searchValue: RegExp, replaceValue: string): string; (searchValue: RegExp, replacer: (substring: string, ...args: any[]) => string): string; }
|
||||
>/( {2,}|\n|\t|\{|\})/g : RegExp
|
||||
>function(whitespace) { return '{' + JSON.stringify(whitespace) + '}'; } : (whitespace: string) => string
|
||||
>whitespace : string
|
||||
|
||||
return '{' + JSON.stringify(whitespace) + '}';
|
||||
>'{' + JSON.stringify(whitespace) + '}' : string
|
||||
>'{' + JSON.stringify(whitespace) : string
|
||||
>'{' : string
|
||||
>JSON.stringify(whitespace) : string
|
||||
>JSON.stringify : { (value: any, replacer?: (key: string, value: any) => any, space?: string | number): string; (value: any, replacer?: (number | string)[], space?: string | number): string; }
|
||||
>JSON : JSON
|
||||
>stringify : { (value: any, replacer?: (key: string, value: any) => any, space?: string | number): string; (value: any, replacer?: (number | string)[], space?: string | number): string; }
|
||||
>whitespace : string
|
||||
>'}' : string
|
||||
|
||||
});
|
||||
} else {
|
||||
// If there's a newline in the text, adjust the indent level
|
||||
if (text.indexOf('\n') > -1) {
|
||||
>text.indexOf('\n') > -1 : boolean
|
||||
>text.indexOf('\n') : number
|
||||
>text.indexOf : (searchString: string, position?: number) => number
|
||||
>text : string
|
||||
>indexOf : (searchString: string, position?: number) => number
|
||||
>'\n' : string
|
||||
>-1 : number
|
||||
>1 : number
|
||||
}
|
||||
}
|
||||
this.output += text;
|
||||
>this.output += text : string
|
||||
>this.output : string
|
||||
>this : this
|
||||
>output : string
|
||||
>text : string
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles parsing of inline styles
|
||||
*/
|
||||
export class StyleParser {
|
||||
>StyleParser : StyleParser
|
||||
|
||||
styles = {};
|
||||
>styles : {}
|
||||
>{} : {}
|
||||
|
||||
toJSXString = () => {
|
||||
>toJSXString : () => void
|
||||
>() => { for (var key in this.styles) { if (!this.styles.hasOwnProperty(key)) { } } } : () => void
|
||||
|
||||
for (var key in this.styles) {
|
||||
>key : string
|
||||
>this.styles : {}
|
||||
>this : this
|
||||
>styles : {}
|
||||
|
||||
if (!this.styles.hasOwnProperty(key)) {
|
||||
>!this.styles.hasOwnProperty(key) : boolean
|
||||
>this.styles.hasOwnProperty(key) : boolean
|
||||
>this.styles.hasOwnProperty : (v: string) => boolean
|
||||
>this.styles : {}
|
||||
>this : this
|
||||
>styles : {}
|
||||
>hasOwnProperty : (v: string) => boolean
|
||||
>key : string
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,44 @@
|
|||
//// [initializersWidened.ts]
|
||||
// these are widened to any at the point of assignment
|
||||
|
||||
var x = null;
|
||||
var y = undefined;
|
||||
var x1 = null;
|
||||
var y1 = undefined;
|
||||
var z1 = void 0;
|
||||
|
||||
// these are not widened
|
||||
|
||||
var x2: null;
|
||||
var y2: undefined;
|
||||
|
||||
var x3: null = null;
|
||||
var y3: undefined = undefined;
|
||||
var z3: undefined = void 0;
|
||||
|
||||
// widen only when all constituents of union are widening
|
||||
|
||||
var x4 = null || null;
|
||||
var y4 = undefined || undefined;
|
||||
var z4 = void 0 || void 0;
|
||||
|
||||
var x5 = null || x2;
|
||||
var y5 = undefined || y2;
|
||||
var z5 = void 0 || y2;
|
||||
|
||||
//// [initializersWidened.js]
|
||||
// these are widened to any at the point of assignment
|
||||
var x = null;
|
||||
var y = undefined;
|
||||
var x1 = null;
|
||||
var y1 = undefined;
|
||||
var z1 = void 0;
|
||||
// these are not widened
|
||||
var x2;
|
||||
var y2;
|
||||
var x3 = null;
|
||||
var y3 = undefined;
|
||||
var z3 = void 0;
|
||||
// widen only when all constituents of union are widening
|
||||
var x4 = null || null;
|
||||
var y4 = undefined || undefined;
|
||||
var z4 = void 0 || void 0;
|
||||
var x5 = null || x2;
|
||||
var y5 = undefined || y2;
|
||||
var z5 = void 0 || y2;
|
||||
|
|
|
@ -1,10 +1,57 @@
|
|||
=== tests/cases/conformance/types/typeRelationships/widenedTypes/initializersWidened.ts ===
|
||||
// these are widened to any at the point of assignment
|
||||
|
||||
var x = null;
|
||||
>x : Symbol(x, Decl(initializersWidened.ts, 2, 3))
|
||||
var x1 = null;
|
||||
>x1 : Symbol(x1, Decl(initializersWidened.ts, 2, 3))
|
||||
|
||||
var y = undefined;
|
||||
>y : Symbol(y, Decl(initializersWidened.ts, 3, 3))
|
||||
var y1 = undefined;
|
||||
>y1 : Symbol(y1, Decl(initializersWidened.ts, 3, 3))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
var z1 = void 0;
|
||||
>z1 : Symbol(z1, Decl(initializersWidened.ts, 4, 3))
|
||||
|
||||
// these are not widened
|
||||
|
||||
var x2: null;
|
||||
>x2 : Symbol(x2, Decl(initializersWidened.ts, 8, 3))
|
||||
|
||||
var y2: undefined;
|
||||
>y2 : Symbol(y2, Decl(initializersWidened.ts, 9, 3))
|
||||
|
||||
var x3: null = null;
|
||||
>x3 : Symbol(x3, Decl(initializersWidened.ts, 11, 3))
|
||||
|
||||
var y3: undefined = undefined;
|
||||
>y3 : Symbol(y3, Decl(initializersWidened.ts, 12, 3))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
var z3: undefined = void 0;
|
||||
>z3 : Symbol(z3, Decl(initializersWidened.ts, 13, 3))
|
||||
|
||||
// widen only when all constituents of union are widening
|
||||
|
||||
var x4 = null || null;
|
||||
>x4 : Symbol(x4, Decl(initializersWidened.ts, 17, 3))
|
||||
|
||||
var y4 = undefined || undefined;
|
||||
>y4 : Symbol(y4, Decl(initializersWidened.ts, 18, 3))
|
||||
>undefined : Symbol(undefined)
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
var z4 = void 0 || void 0;
|
||||
>z4 : Symbol(z4, Decl(initializersWidened.ts, 19, 3))
|
||||
|
||||
var x5 = null || x2;
|
||||
>x5 : Symbol(x5, Decl(initializersWidened.ts, 21, 3))
|
||||
>x2 : Symbol(x2, Decl(initializersWidened.ts, 8, 3))
|
||||
|
||||
var y5 = undefined || y2;
|
||||
>y5 : Symbol(y5, Decl(initializersWidened.ts, 22, 3))
|
||||
>undefined : Symbol(undefined)
|
||||
>y2 : Symbol(y2, Decl(initializersWidened.ts, 9, 3))
|
||||
|
||||
var z5 = void 0 || y2;
|
||||
>z5 : Symbol(z5, Decl(initializersWidened.ts, 23, 3))
|
||||
>y2 : Symbol(y2, Decl(initializersWidened.ts, 9, 3))
|
||||
|
||||
|
|
|
@ -1,11 +1,80 @@
|
|||
=== tests/cases/conformance/types/typeRelationships/widenedTypes/initializersWidened.ts ===
|
||||
// these are widened to any at the point of assignment
|
||||
|
||||
var x = null;
|
||||
>x : any
|
||||
var x1 = null;
|
||||
>x1 : any
|
||||
>null : null
|
||||
|
||||
var y = undefined;
|
||||
>y : any
|
||||
var y1 = undefined;
|
||||
>y1 : any
|
||||
>undefined : undefined
|
||||
|
||||
var z1 = void 0;
|
||||
>z1 : any
|
||||
>void 0 : undefined
|
||||
>0 : number
|
||||
|
||||
// these are not widened
|
||||
|
||||
var x2: null;
|
||||
>x2 : null
|
||||
>null : null
|
||||
|
||||
var y2: undefined;
|
||||
>y2 : undefined
|
||||
|
||||
var x3: null = null;
|
||||
>x3 : null
|
||||
>null : null
|
||||
>null : null
|
||||
|
||||
var y3: undefined = undefined;
|
||||
>y3 : undefined
|
||||
>undefined : undefined
|
||||
|
||||
var z3: undefined = void 0;
|
||||
>z3 : undefined
|
||||
>void 0 : undefined
|
||||
>0 : number
|
||||
|
||||
// widen only when all constituents of union are widening
|
||||
|
||||
var x4 = null || null;
|
||||
>x4 : any
|
||||
>null || null : null
|
||||
>null : null
|
||||
>null : null
|
||||
|
||||
var y4 = undefined || undefined;
|
||||
>y4 : any
|
||||
>undefined || undefined : undefined
|
||||
>undefined : undefined
|
||||
>undefined : undefined
|
||||
|
||||
var z4 = void 0 || void 0;
|
||||
>z4 : any
|
||||
>void 0 || void 0 : undefined
|
||||
>void 0 : undefined
|
||||
>0 : number
|
||||
>void 0 : undefined
|
||||
>0 : number
|
||||
|
||||
var x5 = null || x2;
|
||||
>x5 : null
|
||||
>null || x2 : null
|
||||
>null : null
|
||||
>x2 : null
|
||||
|
||||
var y5 = undefined || y2;
|
||||
>y5 : undefined
|
||||
>undefined || y2 : undefined
|
||||
>undefined : undefined
|
||||
>y2 : undefined
|
||||
|
||||
var z5 = void 0 || y2;
|
||||
>z5 : undefined
|
||||
>void 0 || y2 : undefined
|
||||
>void 0 : undefined
|
||||
>0 : number
|
||||
>y2 : undefined
|
||||
|
||||
|
|
|
@ -623,7 +623,7 @@ var rj8 = a8 && undefined;
|
|||
|
||||
var rj9 = null && undefined;
|
||||
>rj9 : any
|
||||
>null && undefined : null
|
||||
>null && undefined : undefined
|
||||
>null : null
|
||||
>undefined : undefined
|
||||
|
||||
|
|
|
@ -1,29 +1,61 @@
|
|||
//// [objectLiteralWidened.ts]
|
||||
// object literal properties are widened to any
|
||||
|
||||
var x = {
|
||||
var x1 = {
|
||||
foo: null,
|
||||
bar: undefined
|
||||
}
|
||||
|
||||
var y = {
|
||||
var y1 = {
|
||||
foo: null,
|
||||
bar: {
|
||||
baz: null,
|
||||
boo: undefined
|
||||
}
|
||||
}
|
||||
|
||||
// these are not widened
|
||||
|
||||
var u: undefined = undefined;
|
||||
var n: null = null;
|
||||
|
||||
var x2 = {
|
||||
foo: n,
|
||||
bar: u
|
||||
}
|
||||
|
||||
var y2 = {
|
||||
foo: n,
|
||||
bar: {
|
||||
baz: n,
|
||||
boo: u
|
||||
}
|
||||
}
|
||||
|
||||
//// [objectLiteralWidened.js]
|
||||
// object literal properties are widened to any
|
||||
var x = {
|
||||
var x1 = {
|
||||
foo: null,
|
||||
bar: undefined
|
||||
};
|
||||
var y = {
|
||||
var y1 = {
|
||||
foo: null,
|
||||
bar: {
|
||||
baz: null,
|
||||
boo: undefined
|
||||
}
|
||||
};
|
||||
// these are not widened
|
||||
var u = undefined;
|
||||
var n = null;
|
||||
var x2 = {
|
||||
foo: n,
|
||||
bar: u
|
||||
};
|
||||
var y2 = {
|
||||
foo: n,
|
||||
bar: {
|
||||
baz: n,
|
||||
boo: u
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
=== tests/cases/conformance/types/typeRelationships/widenedTypes/objectLiteralWidened.ts ===
|
||||
// object literal properties are widened to any
|
||||
|
||||
var x = {
|
||||
>x : Symbol(x, Decl(objectLiteralWidened.ts, 2, 3))
|
||||
var x1 = {
|
||||
>x1 : Symbol(x1, Decl(objectLiteralWidened.ts, 2, 3))
|
||||
|
||||
foo: null,
|
||||
>foo : Symbol(foo, Decl(objectLiteralWidened.ts, 2, 9))
|
||||
>foo : Symbol(foo, Decl(objectLiteralWidened.ts, 2, 10))
|
||||
|
||||
bar: undefined
|
||||
>bar : Symbol(bar, Decl(objectLiteralWidened.ts, 3, 14))
|
||||
>undefined : Symbol(undefined)
|
||||
}
|
||||
|
||||
var y = {
|
||||
>y : Symbol(y, Decl(objectLiteralWidened.ts, 7, 3))
|
||||
var y1 = {
|
||||
>y1 : Symbol(y1, Decl(objectLiteralWidened.ts, 7, 3))
|
||||
|
||||
foo: null,
|
||||
>foo : Symbol(foo, Decl(objectLiteralWidened.ts, 7, 9))
|
||||
>foo : Symbol(foo, Decl(objectLiteralWidened.ts, 7, 10))
|
||||
|
||||
bar: {
|
||||
>bar : Symbol(bar, Decl(objectLiteralWidened.ts, 8, 14))
|
||||
|
@ -29,3 +29,44 @@ var y = {
|
|||
>undefined : Symbol(undefined)
|
||||
}
|
||||
}
|
||||
|
||||
// these are not widened
|
||||
|
||||
var u: undefined = undefined;
|
||||
>u : Symbol(u, Decl(objectLiteralWidened.ts, 17, 3))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
var n: null = null;
|
||||
>n : Symbol(n, Decl(objectLiteralWidened.ts, 18, 3))
|
||||
|
||||
var x2 = {
|
||||
>x2 : Symbol(x2, Decl(objectLiteralWidened.ts, 20, 3))
|
||||
|
||||
foo: n,
|
||||
>foo : Symbol(foo, Decl(objectLiteralWidened.ts, 20, 10))
|
||||
>n : Symbol(n, Decl(objectLiteralWidened.ts, 18, 3))
|
||||
|
||||
bar: u
|
||||
>bar : Symbol(bar, Decl(objectLiteralWidened.ts, 21, 11))
|
||||
>u : Symbol(u, Decl(objectLiteralWidened.ts, 17, 3))
|
||||
}
|
||||
|
||||
var y2 = {
|
||||
>y2 : Symbol(y2, Decl(objectLiteralWidened.ts, 25, 3))
|
||||
|
||||
foo: n,
|
||||
>foo : Symbol(foo, Decl(objectLiteralWidened.ts, 25, 10))
|
||||
>n : Symbol(n, Decl(objectLiteralWidened.ts, 18, 3))
|
||||
|
||||
bar: {
|
||||
>bar : Symbol(bar, Decl(objectLiteralWidened.ts, 26, 11))
|
||||
|
||||
baz: n,
|
||||
>baz : Symbol(baz, Decl(objectLiteralWidened.ts, 27, 10))
|
||||
>n : Symbol(n, Decl(objectLiteralWidened.ts, 18, 3))
|
||||
|
||||
boo: u
|
||||
>boo : Symbol(boo, Decl(objectLiteralWidened.ts, 28, 15))
|
||||
>u : Symbol(u, Decl(objectLiteralWidened.ts, 17, 3))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
=== tests/cases/conformance/types/typeRelationships/widenedTypes/objectLiteralWidened.ts ===
|
||||
// object literal properties are widened to any
|
||||
|
||||
var x = {
|
||||
>x : { foo: any; bar: any; }
|
||||
var x1 = {
|
||||
>x1 : { foo: any; bar: any; }
|
||||
>{ foo: null, bar: undefined} : { foo: null; bar: undefined; }
|
||||
|
||||
foo: null,
|
||||
|
@ -14,8 +14,8 @@ var x = {
|
|||
>undefined : undefined
|
||||
}
|
||||
|
||||
var y = {
|
||||
>y : { foo: any; bar: { baz: any; boo: any; }; }
|
||||
var y1 = {
|
||||
>y1 : { foo: any; bar: { baz: any; boo: any; }; }
|
||||
>{ foo: null, bar: { baz: null, boo: undefined }} : { foo: null; bar: { baz: null; boo: undefined; }; }
|
||||
|
||||
foo: null,
|
||||
|
@ -35,3 +35,49 @@ var y = {
|
|||
>undefined : undefined
|
||||
}
|
||||
}
|
||||
|
||||
// these are not widened
|
||||
|
||||
var u: undefined = undefined;
|
||||
>u : undefined
|
||||
>undefined : undefined
|
||||
|
||||
var n: null = null;
|
||||
>n : null
|
||||
>null : null
|
||||
>null : null
|
||||
|
||||
var x2 = {
|
||||
>x2 : { foo: null; bar: undefined; }
|
||||
>{ foo: n, bar: u} : { foo: null; bar: undefined; }
|
||||
|
||||
foo: n,
|
||||
>foo : null
|
||||
>n : null
|
||||
|
||||
bar: u
|
||||
>bar : undefined
|
||||
>u : undefined
|
||||
}
|
||||
|
||||
var y2 = {
|
||||
>y2 : { foo: null; bar: { baz: null; boo: undefined; }; }
|
||||
>{ foo: n, bar: { baz: n, boo: u }} : { foo: null; bar: { baz: null; boo: undefined; }; }
|
||||
|
||||
foo: n,
|
||||
>foo : null
|
||||
>n : null
|
||||
|
||||
bar: {
|
||||
>bar : { baz: null; boo: undefined; }
|
||||
>{ baz: n, boo: u } : { baz: null; boo: undefined; }
|
||||
|
||||
baz: n,
|
||||
>baz : null
|
||||
>n : null
|
||||
|
||||
boo: u
|
||||
>boo : undefined
|
||||
>u : undefined
|
||||
}
|
||||
}
|
||||
|
|
31
tests/baselines/reference/strictNullChecksNoWidening.js
Normal file
31
tests/baselines/reference/strictNullChecksNoWidening.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
//// [strictNullChecksNoWidening.ts]
|
||||
|
||||
var a1 = null;
|
||||
var a2 = undefined;
|
||||
var a3 = void 0;
|
||||
|
||||
var b1 = [];
|
||||
var b2 = [,];
|
||||
var b3 = [undefined];
|
||||
var b4 = [[], []];
|
||||
var b5 = [[], [,]];
|
||||
|
||||
declare function f<T>(x: T): T;
|
||||
|
||||
var c1 = f(null);
|
||||
var c2 = f(undefined);
|
||||
var c3 = f([]);
|
||||
|
||||
|
||||
//// [strictNullChecksNoWidening.js]
|
||||
var a1 = null;
|
||||
var a2 = undefined;
|
||||
var a3 = void 0;
|
||||
var b1 = [];
|
||||
var b2 = [,];
|
||||
var b3 = [undefined];
|
||||
var b4 = [[], []];
|
||||
var b5 = [[], [,]];
|
||||
var c1 = f(null);
|
||||
var c2 = f(undefined);
|
||||
var c3 = f([]);
|
48
tests/baselines/reference/strictNullChecksNoWidening.symbols
Normal file
48
tests/baselines/reference/strictNullChecksNoWidening.symbols
Normal file
|
@ -0,0 +1,48 @@
|
|||
=== tests/cases/conformance/types/typeRelationships/widenedTypes/strictNullChecksNoWidening.ts ===
|
||||
|
||||
var a1 = null;
|
||||
>a1 : Symbol(a1, Decl(strictNullChecksNoWidening.ts, 1, 3))
|
||||
|
||||
var a2 = undefined;
|
||||
>a2 : Symbol(a2, Decl(strictNullChecksNoWidening.ts, 2, 3))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
var a3 = void 0;
|
||||
>a3 : Symbol(a3, Decl(strictNullChecksNoWidening.ts, 3, 3))
|
||||
|
||||
var b1 = [];
|
||||
>b1 : Symbol(b1, Decl(strictNullChecksNoWidening.ts, 5, 3))
|
||||
|
||||
var b2 = [,];
|
||||
>b2 : Symbol(b2, Decl(strictNullChecksNoWidening.ts, 6, 3))
|
||||
|
||||
var b3 = [undefined];
|
||||
>b3 : Symbol(b3, Decl(strictNullChecksNoWidening.ts, 7, 3))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
var b4 = [[], []];
|
||||
>b4 : Symbol(b4, Decl(strictNullChecksNoWidening.ts, 8, 3))
|
||||
|
||||
var b5 = [[], [,]];
|
||||
>b5 : Symbol(b5, Decl(strictNullChecksNoWidening.ts, 9, 3))
|
||||
|
||||
declare function f<T>(x: T): T;
|
||||
>f : Symbol(f, Decl(strictNullChecksNoWidening.ts, 9, 19))
|
||||
>T : Symbol(T, Decl(strictNullChecksNoWidening.ts, 11, 19))
|
||||
>x : Symbol(x, Decl(strictNullChecksNoWidening.ts, 11, 22))
|
||||
>T : Symbol(T, Decl(strictNullChecksNoWidening.ts, 11, 19))
|
||||
>T : Symbol(T, Decl(strictNullChecksNoWidening.ts, 11, 19))
|
||||
|
||||
var c1 = f(null);
|
||||
>c1 : Symbol(c1, Decl(strictNullChecksNoWidening.ts, 13, 3))
|
||||
>f : Symbol(f, Decl(strictNullChecksNoWidening.ts, 9, 19))
|
||||
|
||||
var c2 = f(undefined);
|
||||
>c2 : Symbol(c2, Decl(strictNullChecksNoWidening.ts, 14, 3))
|
||||
>f : Symbol(f, Decl(strictNullChecksNoWidening.ts, 9, 19))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
var c3 = f([]);
|
||||
>c3 : Symbol(c3, Decl(strictNullChecksNoWidening.ts, 15, 3))
|
||||
>f : Symbol(f, Decl(strictNullChecksNoWidening.ts, 9, 19))
|
||||
|
67
tests/baselines/reference/strictNullChecksNoWidening.types
Normal file
67
tests/baselines/reference/strictNullChecksNoWidening.types
Normal file
|
@ -0,0 +1,67 @@
|
|||
=== tests/cases/conformance/types/typeRelationships/widenedTypes/strictNullChecksNoWidening.ts ===
|
||||
|
||||
var a1 = null;
|
||||
>a1 : null
|
||||
>null : null
|
||||
|
||||
var a2 = undefined;
|
||||
>a2 : undefined
|
||||
>undefined : undefined
|
||||
|
||||
var a3 = void 0;
|
||||
>a3 : undefined
|
||||
>void 0 : undefined
|
||||
>0 : number
|
||||
|
||||
var b1 = [];
|
||||
>b1 : never[]
|
||||
>[] : never[]
|
||||
|
||||
var b2 = [,];
|
||||
>b2 : undefined[]
|
||||
>[,] : undefined[]
|
||||
> : undefined
|
||||
|
||||
var b3 = [undefined];
|
||||
>b3 : undefined[]
|
||||
>[undefined] : undefined[]
|
||||
>undefined : undefined
|
||||
|
||||
var b4 = [[], []];
|
||||
>b4 : never[][]
|
||||
>[[], []] : never[][]
|
||||
>[] : never[]
|
||||
>[] : never[]
|
||||
|
||||
var b5 = [[], [,]];
|
||||
>b5 : undefined[][]
|
||||
>[[], [,]] : undefined[][]
|
||||
>[] : never[]
|
||||
>[,] : undefined[]
|
||||
> : undefined
|
||||
|
||||
declare function f<T>(x: T): T;
|
||||
>f : <T>(x: T) => T
|
||||
>T : T
|
||||
>x : T
|
||||
>T : T
|
||||
>T : T
|
||||
|
||||
var c1 = f(null);
|
||||
>c1 : null
|
||||
>f(null) : null
|
||||
>f : <T>(x: T) => T
|
||||
>null : null
|
||||
|
||||
var c2 = f(undefined);
|
||||
>c2 : undefined
|
||||
>f(undefined) : undefined
|
||||
>f : <T>(x: T) => T
|
||||
>undefined : undefined
|
||||
|
||||
var c3 = f([]);
|
||||
>c3 : never[]
|
||||
>f([]) : never[]
|
||||
>f : <T>(x: T) => T
|
||||
>[] : never[]
|
||||
|
|
@ -41,7 +41,7 @@ function foo4(x: number | string | boolean) {
|
|||
: x.toString(); // number
|
||||
})(x); // x here is narrowed to number | boolean
|
||||
}
|
||||
// Type guards affect nested function expressions and nested function declarations
|
||||
// Type guards do not affect nested function declarations
|
||||
function foo5(x: number | string | boolean) {
|
||||
if (typeof x === "string") {
|
||||
var y = x; // string;
|
||||
|
@ -121,7 +121,7 @@ function foo4(x) {
|
|||
: x.toString(); // number
|
||||
})(x); // x here is narrowed to number | boolean
|
||||
}
|
||||
// Type guards affect nested function expressions and nested function declarations
|
||||
// Type guards do not affect nested function declarations
|
||||
function foo5(x) {
|
||||
if (typeof x === "string") {
|
||||
var y = x; // string;
|
||||
|
|
|
@ -27,9 +27,9 @@ function foo(x: number | string | boolean) {
|
|||
>toString : Symbol(Object.toString, Decl(lib.d.ts, --, --))
|
||||
|
||||
: x.toString(); // number
|
||||
>x.toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>x.toString : Symbol(Number.toString, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(typeGuardsInFunctionAndModuleBlock.ts, 2, 13))
|
||||
>toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>toString : Symbol(Number.toString, Decl(lib.d.ts, --, --))
|
||||
|
||||
} ();
|
||||
}
|
||||
|
@ -60,9 +60,9 @@ function foo2(x: number | string | boolean) {
|
|||
>toString : Symbol(Object.toString, Decl(lib.d.ts, --, --))
|
||||
|
||||
: x.toString(); // number
|
||||
>x.toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>x.toString : Symbol(Number.toString, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(typeGuardsInFunctionAndModuleBlock.ts, 12, 14))
|
||||
>toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>toString : Symbol(Number.toString, Decl(lib.d.ts, --, --))
|
||||
|
||||
} (x); // x here is narrowed to number | boolean
|
||||
>x : Symbol(x, Decl(typeGuardsInFunctionAndModuleBlock.ts, 12, 14))
|
||||
|
@ -91,9 +91,9 @@ function foo3(x: number | string | boolean) {
|
|||
>toString : Symbol(Object.toString, Decl(lib.d.ts, --, --))
|
||||
|
||||
: x.toString(); // number
|
||||
>x.toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>x.toString : Symbol(Number.toString, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(typeGuardsInFunctionAndModuleBlock.ts, 22, 14))
|
||||
>toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>toString : Symbol(Number.toString, Decl(lib.d.ts, --, --))
|
||||
|
||||
})();
|
||||
}
|
||||
|
@ -123,14 +123,14 @@ function foo4(x: number | string | boolean) {
|
|||
>toString : Symbol(Object.toString, Decl(lib.d.ts, --, --))
|
||||
|
||||
: x.toString(); // number
|
||||
>x.toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>x.toString : Symbol(Number.toString, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(typeGuardsInFunctionAndModuleBlock.ts, 32, 14))
|
||||
>toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>toString : Symbol(Number.toString, Decl(lib.d.ts, --, --))
|
||||
|
||||
})(x); // x here is narrowed to number | boolean
|
||||
>x : Symbol(x, Decl(typeGuardsInFunctionAndModuleBlock.ts, 32, 14))
|
||||
}
|
||||
// Type guards affect nested function expressions and nested function declarations
|
||||
// Type guards do not affect nested function declarations
|
||||
function foo5(x: number | string | boolean) {
|
||||
>foo5 : Symbol(foo5, Decl(typeGuardsInFunctionAndModuleBlock.ts, 41, 1))
|
||||
>x : Symbol(x, Decl(typeGuardsInFunctionAndModuleBlock.ts, 43, 14))
|
||||
|
|
|
@ -21,14 +21,14 @@ function foo(x: number | string | boolean) {
|
|||
>f : () => string
|
||||
|
||||
var b = x; // number | boolean
|
||||
>b : number | string | boolean
|
||||
>x : number | string | boolean
|
||||
>b : number | boolean
|
||||
>x : number | boolean
|
||||
|
||||
return typeof x === "boolean"
|
||||
>typeof x === "boolean" ? x.toString() // boolean : x.toString() : string
|
||||
>typeof x === "boolean" : boolean
|
||||
>typeof x : string
|
||||
>x : number | string | boolean
|
||||
>x : number | boolean
|
||||
>"boolean" : string
|
||||
|
||||
? x.toString() // boolean
|
||||
|
@ -40,7 +40,7 @@ function foo(x: number | string | boolean) {
|
|||
: x.toString(); // number
|
||||
>x.toString() : string
|
||||
>x.toString : (radix?: number) => string
|
||||
>x : number | string
|
||||
>x : number
|
||||
>toString : (radix?: number) => string
|
||||
|
||||
} ();
|
||||
|
@ -66,14 +66,14 @@ function foo2(x: number | string | boolean) {
|
|||
>a : number | boolean
|
||||
|
||||
var b = x; // new scope - number | boolean
|
||||
>b : number | string | boolean
|
||||
>x : number | string | boolean
|
||||
>b : number | boolean
|
||||
>x : number | boolean
|
||||
|
||||
return typeof x === "boolean"
|
||||
>typeof x === "boolean" ? x.toString() // boolean : x.toString() : string
|
||||
>typeof x === "boolean" : boolean
|
||||
>typeof x : string
|
||||
>x : number | string | boolean
|
||||
>x : number | boolean
|
||||
>"boolean" : string
|
||||
|
||||
? x.toString() // boolean
|
||||
|
@ -85,7 +85,7 @@ function foo2(x: number | string | boolean) {
|
|||
: x.toString(); // number
|
||||
>x.toString() : string
|
||||
>x.toString : (radix?: number) => string
|
||||
>x : number | string
|
||||
>x : number
|
||||
>toString : (radix?: number) => string
|
||||
|
||||
} (x); // x here is narrowed to number | boolean
|
||||
|
@ -111,14 +111,14 @@ function foo3(x: number | string | boolean) {
|
|||
>() => { var b = x; // new scope - number | boolean return typeof x === "boolean" ? x.toString() // boolean : x.toString(); // number } : () => string
|
||||
|
||||
var b = x; // new scope - number | boolean
|
||||
>b : number | string | boolean
|
||||
>x : number | string | boolean
|
||||
>b : number | boolean
|
||||
>x : number | boolean
|
||||
|
||||
return typeof x === "boolean"
|
||||
>typeof x === "boolean" ? x.toString() // boolean : x.toString() : string
|
||||
>typeof x === "boolean" : boolean
|
||||
>typeof x : string
|
||||
>x : number | string | boolean
|
||||
>x : number | boolean
|
||||
>"boolean" : string
|
||||
|
||||
? x.toString() // boolean
|
||||
|
@ -130,7 +130,7 @@ function foo3(x: number | string | boolean) {
|
|||
: x.toString(); // number
|
||||
>x.toString() : string
|
||||
>x.toString : (radix?: number) => string
|
||||
>x : number | string
|
||||
>x : number
|
||||
>toString : (radix?: number) => string
|
||||
|
||||
})();
|
||||
|
@ -156,14 +156,14 @@ function foo4(x: number | string | boolean) {
|
|||
>a : number | boolean
|
||||
|
||||
var b = x; // new scope - number | boolean
|
||||
>b : number | string | boolean
|
||||
>x : number | string | boolean
|
||||
>b : number | boolean
|
||||
>x : number | boolean
|
||||
|
||||
return typeof x === "boolean"
|
||||
>typeof x === "boolean" ? x.toString() // boolean : x.toString() : string
|
||||
>typeof x === "boolean" : boolean
|
||||
>typeof x : string
|
||||
>x : number | string | boolean
|
||||
>x : number | boolean
|
||||
>"boolean" : string
|
||||
|
||||
? x.toString() // boolean
|
||||
|
@ -175,13 +175,13 @@ function foo4(x: number | string | boolean) {
|
|||
: x.toString(); // number
|
||||
>x.toString() : string
|
||||
>x.toString : (radix?: number) => string
|
||||
>x : number | string
|
||||
>x : number
|
||||
>toString : (radix?: number) => string
|
||||
|
||||
})(x); // x here is narrowed to number | boolean
|
||||
>x : number | boolean
|
||||
}
|
||||
// Type guards affect nested function expressions and nested function declarations
|
||||
// Type guards do not affect nested function declarations
|
||||
function foo5(x: number | string | boolean) {
|
||||
>foo5 : (x: number | string | boolean) => void
|
||||
>x : number | string | boolean
|
||||
|
|
148
tests/cases/compiler/controlFlowPropertyDeclarations.ts
Normal file
148
tests/cases/compiler/controlFlowPropertyDeclarations.ts
Normal file
|
@ -0,0 +1,148 @@
|
|||
// Repro from ##8913
|
||||
|
||||
declare var require:any;
|
||||
|
||||
var HTMLDOMPropertyConfig = require('react/lib/HTMLDOMPropertyConfig');
|
||||
|
||||
// Populate property map with ReactJS's attribute and property mappings
|
||||
// TODO handle/use .Properties value eg: MUST_USE_PROPERTY is not HTML attr
|
||||
for (var propname in HTMLDOMPropertyConfig.Properties) {
|
||||
if (!HTMLDOMPropertyConfig.Properties.hasOwnProperty(propname)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var mapFrom = HTMLDOMPropertyConfig.DOMAttributeNames[propname] || propname.toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeats a string a certain number of times.
|
||||
* Also: the future is bright and consists of native string repetition:
|
||||
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat
|
||||
*
|
||||
* @param {string} string String to repeat
|
||||
* @param {number} times Number of times to repeat string. Integer.
|
||||
* @see http://jsperf.com/string-repeater/2
|
||||
*/
|
||||
function repeatString(string, times) {
|
||||
if (times === 1) {
|
||||
return string;
|
||||
}
|
||||
if (times < 0) { throw new Error(); }
|
||||
var repeated = '';
|
||||
while (times) {
|
||||
if (times & 1) {
|
||||
repeated += string;
|
||||
}
|
||||
if (times >>= 1) {
|
||||
string += string;
|
||||
}
|
||||
}
|
||||
return repeated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the string ends with the specified substring.
|
||||
*
|
||||
* @param {string} haystack String to search in
|
||||
* @param {string} needle String to search for
|
||||
* @return {boolean}
|
||||
*/
|
||||
function endsWith(haystack, needle) {
|
||||
return haystack.slice(-needle.length) === needle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim the specified substring off the string. If the string does not end
|
||||
* with the specified substring, this is a no-op.
|
||||
*
|
||||
* @param {string} haystack String to search in
|
||||
* @param {string} needle String to search for
|
||||
* @return {string}
|
||||
*/
|
||||
function trimEnd(haystack, needle) {
|
||||
return endsWith(haystack, needle)
|
||||
? haystack.slice(0, -needle.length)
|
||||
: haystack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a hyphenated string to camelCase.
|
||||
*/
|
||||
function hyphenToCamelCase(string) {
|
||||
return string.replace(/-(.)/g, function(match, chr) {
|
||||
return chr.toUpperCase();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the specified string consists entirely of whitespace.
|
||||
*/
|
||||
function isEmpty(string) {
|
||||
return !/[^\s]/.test(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the CSS value can be converted from a
|
||||
* 'px' suffixed string to a numeric value
|
||||
*
|
||||
* @param {string} value CSS property value
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isConvertiblePixelValue(value) {
|
||||
return /^\d+px$/.test(value);
|
||||
}
|
||||
|
||||
export class HTMLtoJSX {
|
||||
private output: string;
|
||||
private level: number;
|
||||
private _inPreTag: boolean;
|
||||
|
||||
|
||||
/**
|
||||
* Handles processing of the specified text node
|
||||
*
|
||||
* @param {TextNode} node
|
||||
*/
|
||||
_visitText = (node) => {
|
||||
var parentTag = node.parentNode && node.parentNode.tagName.toLowerCase();
|
||||
if (parentTag === 'textarea' || parentTag === 'style') {
|
||||
// Ignore text content of textareas and styles, as it will have already been moved
|
||||
// to a "defaultValue" attribute and "dangerouslySetInnerHTML" attribute respectively.
|
||||
return;
|
||||
}
|
||||
|
||||
var text = ''
|
||||
|
||||
if (this._inPreTag) {
|
||||
// If this text is contained within a <pre>, we need to ensure the JSX
|
||||
// whitespace coalescing rules don't eat the whitespace. This means
|
||||
// wrapping newlines and sequences of two or more spaces in variables.
|
||||
text = text
|
||||
.replace(/\r/g, '')
|
||||
.replace(/( {2,}|\n|\t|\{|\})/g, function(whitespace) {
|
||||
return '{' + JSON.stringify(whitespace) + '}';
|
||||
});
|
||||
} else {
|
||||
// If there's a newline in the text, adjust the indent level
|
||||
if (text.indexOf('\n') > -1) {
|
||||
}
|
||||
}
|
||||
this.output += text;
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles parsing of inline styles
|
||||
*/
|
||||
export class StyleParser {
|
||||
styles = {};
|
||||
toJSXString = () => {
|
||||
for (var key in this.styles) {
|
||||
if (!this.styles.hasOwnProperty(key)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
declare function getStringOrNumber(): string | number;
|
||||
|
||||
function f1() {
|
||||
const x = getStringOrNumber();
|
||||
if (typeof x === "string") {
|
||||
const f = () => x.length;
|
||||
}
|
||||
}
|
||||
|
||||
function f2() {
|
||||
const x = getStringOrNumber();
|
||||
if (typeof x !== "string") {
|
||||
return;
|
||||
}
|
||||
const f = () => x.length;
|
||||
}
|
||||
|
||||
function f3() {
|
||||
const x = getStringOrNumber();
|
||||
if (typeof x === "string") {
|
||||
const f = function() { return x.length; };
|
||||
}
|
||||
}
|
||||
|
||||
function f4() {
|
||||
const x = getStringOrNumber();
|
||||
if (typeof x !== "string") {
|
||||
return;
|
||||
}
|
||||
const f = function() { return x.length; };
|
||||
}
|
||||
|
||||
function f5() {
|
||||
const x = getStringOrNumber();
|
||||
if (typeof x === "string") {
|
||||
const f = () => () => x.length;
|
||||
}
|
||||
}
|
48
tests/cases/conformance/controlFlow/controlFlowIIFE.ts
Normal file
48
tests/cases/conformance/controlFlow/controlFlowIIFE.ts
Normal file
|
@ -0,0 +1,48 @@
|
|||
// @strictNullChecks: true
|
||||
|
||||
declare function getStringOrNumber(): string | number;
|
||||
|
||||
function f1() {
|
||||
let x = getStringOrNumber();
|
||||
if (typeof x === "string") {
|
||||
let n = function() {
|
||||
return x.length;
|
||||
}();
|
||||
}
|
||||
}
|
||||
|
||||
function f2() {
|
||||
let x = getStringOrNumber();
|
||||
if (typeof x === "string") {
|
||||
let n = (function() {
|
||||
return x.length;
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
function f3() {
|
||||
let x = getStringOrNumber();
|
||||
let y: number;
|
||||
if (typeof x === "string") {
|
||||
let n = (z => x.length + y + z)(y = 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Repros from #8381
|
||||
|
||||
let maybeNumber: number | undefined;
|
||||
(function () {
|
||||
maybeNumber = 1;
|
||||
})();
|
||||
maybeNumber++;
|
||||
if (maybeNumber !== undefined) {
|
||||
maybeNumber++;
|
||||
}
|
||||
|
||||
let test: string | undefined;
|
||||
if (!test) {
|
||||
throw new Error('Test is not defined');
|
||||
}
|
||||
(() => {
|
||||
test.slice(1); // No error
|
||||
})();
|
|
@ -40,7 +40,7 @@ function foo4(x: number | string | boolean) {
|
|||
: x.toString(); // number
|
||||
})(x); // x here is narrowed to number | boolean
|
||||
}
|
||||
// Type guards affect nested function expressions and nested function declarations
|
||||
// Type guards do not affect nested function declarations
|
||||
function foo5(x: number | string | boolean) {
|
||||
if (typeof x === "string") {
|
||||
var y = x; // string;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// array literals are widened upon assignment according to their element type
|
||||
|
||||
var a = []; // any[]
|
||||
var a = [,,];
|
||||
|
||||
var a = [null, null];
|
||||
var a = [undefined, undefined];
|
||||
|
@ -11,3 +12,11 @@ var b = [[undefined, undefined]];
|
|||
|
||||
var c = [[[]]]; // any[][][]
|
||||
var c = [[[null]],[undefined]]
|
||||
|
||||
// no widening when one or more elements are non-widening
|
||||
|
||||
var x: undefined = undefined;
|
||||
|
||||
var d = [x];
|
||||
var d = [, x];
|
||||
var d = [undefined, x];
|
||||
|
|
|
@ -1,4 +1,24 @@
|
|||
// these are widened to any at the point of assignment
|
||||
|
||||
var x = null;
|
||||
var y = undefined;
|
||||
var x1 = null;
|
||||
var y1 = undefined;
|
||||
var z1 = void 0;
|
||||
|
||||
// these are not widened
|
||||
|
||||
var x2: null;
|
||||
var y2: undefined;
|
||||
|
||||
var x3: null = null;
|
||||
var y3: undefined = undefined;
|
||||
var z3: undefined = void 0;
|
||||
|
||||
// widen only when all constituents of union are widening
|
||||
|
||||
var x4 = null || null;
|
||||
var y4 = undefined || undefined;
|
||||
var z4 = void 0 || void 0;
|
||||
|
||||
var x5 = null || x2;
|
||||
var y5 = undefined || y2;
|
||||
var z5 = void 0 || y2;
|
|
@ -1,14 +1,32 @@
|
|||
// object literal properties are widened to any
|
||||
|
||||
var x = {
|
||||
var x1 = {
|
||||
foo: null,
|
||||
bar: undefined
|
||||
}
|
||||
|
||||
var y = {
|
||||
var y1 = {
|
||||
foo: null,
|
||||
bar: {
|
||||
baz: null,
|
||||
boo: undefined
|
||||
}
|
||||
}
|
||||
|
||||
// these are not widened
|
||||
|
||||
var u: undefined = undefined;
|
||||
var n: null = null;
|
||||
|
||||
var x2 = {
|
||||
foo: n,
|
||||
bar: u
|
||||
}
|
||||
|
||||
var y2 = {
|
||||
foo: n,
|
||||
bar: {
|
||||
baz: n,
|
||||
boo: u
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// @strictNullChecks: true
|
||||
|
||||
var a1 = null;
|
||||
var a2 = undefined;
|
||||
var a3 = void 0;
|
||||
|
||||
var b1 = [];
|
||||
var b2 = [,];
|
||||
var b3 = [undefined];
|
||||
var b4 = [[], []];
|
||||
var b5 = [[], [,]];
|
||||
|
||||
declare function f<T>(x: T): T;
|
||||
|
||||
var c1 = f(null);
|
||||
var c2 = f(undefined);
|
||||
var c3 = f([]);
|
|
@ -246,6 +246,7 @@ declare namespace FourSlashInterface {
|
|||
copyFormatOptions(): FormatCodeOptions;
|
||||
setFormatOptions(options: FormatCodeOptions): any;
|
||||
selection(startMarker: string, endMarker: string): void;
|
||||
onType(posMarker: string, key: string): void;
|
||||
setOption(name: string, value: number): any;
|
||||
setOption(name: string, value: string): any;
|
||||
setOption(name: string, value: boolean): any;
|
||||
|
|
17
tests/cases/fourslash/server/formatOnEnter.ts
Normal file
17
tests/cases/fourslash/server/formatOnEnter.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
/// <reference path="fourslash.ts"/>
|
||||
|
||||
/////*3*/function listAPIFiles (path : string): string[] {
|
||||
//// /*1*/
|
||||
//// /*2*/
|
||||
////}
|
||||
|
||||
goTo.marker("1");
|
||||
format.onType("1", "\n");
|
||||
verify.currentLineContentIs(" ");
|
||||
|
||||
goTo.marker("2");
|
||||
format.onType("2", "\n");
|
||||
verify.currentLineContentIs(" ");
|
||||
|
||||
goTo.marker("3");
|
||||
verify.currentLineContentIs("function listAPIFiles(path: string): string[] {");
|
64
tests/cases/fourslash/server/jsdocTypedefTag.ts
Normal file
64
tests/cases/fourslash/server/jsdocTypedefTag.ts
Normal file
|
@ -0,0 +1,64 @@
|
|||
/// <reference path="../fourslash.ts"/>
|
||||
|
||||
// @allowNonTsExtensions: true
|
||||
// @Filename: jsdocCompletion_typedef.js
|
||||
|
||||
//// /** @typedef {(string | number)} NumberLike */
|
||||
////
|
||||
//// /**
|
||||
//// * @typedef Animal
|
||||
//// * @type {Object}
|
||||
//// * @property {string} animalName
|
||||
//// * @property {number} animalAge
|
||||
//// */
|
||||
////
|
||||
//// /**
|
||||
//// * @typedef {Object} Person
|
||||
//// * @property {string} personName
|
||||
//// * @property {number} personAge
|
||||
//// */
|
||||
////
|
||||
//// /**
|
||||
//// * @typedef {Object}
|
||||
//// * @property {string} catName
|
||||
//// * @property {number} catAge
|
||||
//// */
|
||||
//// var Cat;
|
||||
////
|
||||
//// /** @typedef {{ dogName: string, dogAge: number }} */
|
||||
//// var Dog;
|
||||
////
|
||||
//// /** @type {NumberLike} */
|
||||
//// var numberLike; numberLike./*numberLike*/
|
||||
////
|
||||
//// /** @type {Person} */
|
||||
//// var p;p./*person*/
|
||||
////
|
||||
//// /** @type {Animal} */
|
||||
//// var a;a./*animal*/
|
||||
////
|
||||
//// /** @type {Cat} */
|
||||
//// var c;c./*cat*/
|
||||
////
|
||||
//// /** @type {Dog} */
|
||||
//// var d;d./*dog*/
|
||||
|
||||
goTo.marker('numberLike');
|
||||
verify.memberListContains('charAt');
|
||||
verify.memberListContains('toExponential');
|
||||
|
||||
goTo.marker('person');
|
||||
verify.memberListContains('personName');
|
||||
verify.memberListContains('personAge');
|
||||
|
||||
goTo.marker('animal');
|
||||
verify.memberListContains('animalName');
|
||||
verify.memberListContains('animalAge');
|
||||
|
||||
goTo.marker('dog');
|
||||
verify.memberListContains('dogName');
|
||||
verify.memberListContains('dogAge');
|
||||
|
||||
goTo.marker('cat');
|
||||
verify.memberListContains('catName');
|
||||
verify.memberListContains('catAge');
|
|
@ -0,0 +1,29 @@
|
|||
/// <reference path="../fourslash.ts"/>
|
||||
|
||||
// @allowNonTsExtensions: true
|
||||
// @Filename: jsdocCompletion_typedef.js
|
||||
|
||||
//// /**
|
||||
//// * @typedef {Object} Person
|
||||
//// * /*1*/@property {string} personName
|
||||
//// * @property {number} personAge
|
||||
//// */
|
||||
////
|
||||
//// /**
|
||||
//// * @typedef {{ /*2*/animalName: string, animalAge: number }} Animal
|
||||
//// */
|
||||
////
|
||||
//// /** @type {Person} */
|
||||
//// var person; person.personName/*3*/
|
||||
////
|
||||
//// /** @type {Animal} */
|
||||
//// var animal; animal.animalName/*4*/
|
||||
|
||||
goTo.file('jsdocCompletion_typedef.js');
|
||||
goTo.marker('3');
|
||||
goTo.definition();
|
||||
verify.caretAtMarker('1');
|
||||
|
||||
goTo.marker('4');
|
||||
goTo.definition();
|
||||
verify.caretAtMarker('2');
|
30
tests/cases/fourslash/server/jsdocTypedefTagNavigateTo.ts
Normal file
30
tests/cases/fourslash/server/jsdocTypedefTagNavigateTo.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
/// <reference path="../fourslash.ts"/>
|
||||
|
||||
// @allowNonTsExtensions: true
|
||||
// @Filename: jsDocTypedef_form2.js
|
||||
////
|
||||
//// /** @typedef {(string | number)} NumberLike */
|
||||
//// /** @typedef {(string | number | string[])} */
|
||||
//// var NumberLike2;
|
||||
////
|
||||
//// /** @type {/*1*/NumberLike} */
|
||||
//// var numberLike;
|
||||
|
||||
verify.navigationBar([
|
||||
{
|
||||
"text": "NumberLike",
|
||||
"kind": "type"
|
||||
},
|
||||
{
|
||||
"text": "NumberLike2",
|
||||
"kind": "type"
|
||||
},
|
||||
{
|
||||
"text": "NumberLike2",
|
||||
"kind": "var"
|
||||
},
|
||||
{
|
||||
"text": "numberLike",
|
||||
"kind": "var"
|
||||
}
|
||||
]);
|
20
tests/cases/fourslash/server/jsdocTypedefTagRename01.ts
Normal file
20
tests/cases/fourslash/server/jsdocTypedefTagRename01.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
/// <reference path="../fourslash.ts"/>
|
||||
|
||||
// @allowNonTsExtensions: true
|
||||
// @Filename: jsDocTypedef_form1.js
|
||||
////
|
||||
//// /** @typedef {(string | number)} */
|
||||
//// var /*1*/[|NumberLike|];
|
||||
////
|
||||
//// /*2*/[|NumberLike|] = 10;
|
||||
////
|
||||
//// /** @type {/*3*/[|NumberLike|]} */
|
||||
//// var numberLike;
|
||||
|
||||
goTo.file('jsDocTypedef_form1.js')
|
||||
goTo.marker('1');
|
||||
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ true);
|
||||
goTo.marker('2');
|
||||
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ true);
|
||||
goTo.marker('3');
|
||||
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ true);
|
15
tests/cases/fourslash/server/jsdocTypedefTagRename02.ts
Normal file
15
tests/cases/fourslash/server/jsdocTypedefTagRename02.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
/// <reference path="../fourslash.ts"/>
|
||||
|
||||
// @allowNonTsExtensions: true
|
||||
// @Filename: jsDocTypedef_form2.js
|
||||
////
|
||||
//// /** @typedef {(string | number)} /*1*/[|NumberLike|] */
|
||||
////
|
||||
//// /** @type {/*2*/[|NumberLike|]} */
|
||||
//// var numberLike;
|
||||
|
||||
goTo.file('jsDocTypedef_form2.js')
|
||||
goTo.marker('1');
|
||||
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ true);
|
||||
goTo.marker('2');
|
||||
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ true);
|
20
tests/cases/fourslash/server/jsdocTypedefTagRename03.ts
Normal file
20
tests/cases/fourslash/server/jsdocTypedefTagRename03.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
/// <reference path="../fourslash.ts"/>
|
||||
|
||||
// @allowNonTsExtensions: true
|
||||
// @Filename: jsDocTypedef_form3.js
|
||||
////
|
||||
//// /**
|
||||
//// * @typedef /*1*/[|Person|]
|
||||
//// * @type {Object}
|
||||
//// * @property {number} age
|
||||
//// * @property {string} name
|
||||
//// */
|
||||
////
|
||||
//// /** @type {/*2*/[|Person|]} */
|
||||
//// var person;
|
||||
|
||||
goTo.file('jsDocTypedef_form3.js')
|
||||
goTo.marker('1');
|
||||
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ true);
|
||||
goTo.marker('2');
|
||||
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ true);
|
24
tests/cases/fourslash/server/jsdocTypedefTagRename04.ts
Normal file
24
tests/cases/fourslash/server/jsdocTypedefTagRename04.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
/// <reference path="../fourslash.ts"/>
|
||||
|
||||
// @allowNonTsExtensions: true
|
||||
// @Filename: jsDocTypedef_form2.js
|
||||
////
|
||||
//// function test1() {
|
||||
//// /** @typedef {(string | number)} NumberLike */
|
||||
////
|
||||
//// /** @type {/*1*/NumberLike} */
|
||||
//// var numberLike;
|
||||
//// }
|
||||
//// function test2() {
|
||||
//// /** @typedef {(string | number)} NumberLike2 */
|
||||
////
|
||||
//// /** @type {NumberLike2} */
|
||||
//// var n/*2*/umberLike2;
|
||||
//// }
|
||||
|
||||
goTo.marker('2');
|
||||
verify.quickInfoExists();
|
||||
goTo.marker('1');
|
||||
edit.insert('111');
|
||||
goTo.marker('2');
|
||||
verify.quickInfoExists();
|
|
@ -0,0 +1,22 @@
|
|||
/// <reference path="fourslash.ts"/>
|
||||
|
||||
/////** @template T */
|
||||
////function ident<T>: T {
|
||||
////}
|
||||
|
||||
var c = classification;
|
||||
verify.syntacticClassificationsAre(
|
||||
c.comment("/** "),
|
||||
c.punctuation("@"),
|
||||
c.docCommentTagName("template"),
|
||||
c.typeParameterName("T"),
|
||||
c.comment(" */"),
|
||||
c.keyword("function"),
|
||||
c.identifier("ident"),
|
||||
c.punctuation("<"),
|
||||
c.typeParameterName("T"),
|
||||
c.punctuation(">"),
|
||||
c.punctuation(":"),
|
||||
c.identifier("T"),
|
||||
c.punctuation("{"),
|
||||
c.punctuation("}"));
|
|
@ -1004,7 +1004,8 @@ namespace ts {
|
|||
if (result !== expected) {
|
||||
// Turn on a human-readable diff
|
||||
if (typeof require !== "undefined") {
|
||||
require("chai").config.showDiff = true;
|
||||
const chai = require("chai");
|
||||
chai.config.showDiff = true;
|
||||
chai.expect(JSON.parse(result)).equal(JSON.parse(expected));
|
||||
}
|
||||
else {
|
||||
|
@ -2218,4 +2219,4 @@ namespace ts {
|
|||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
294
tests/cases/unittests/tsserverProjectSystem.ts
Normal file
294
tests/cases/unittests/tsserverProjectSystem.ts
Normal file
|
@ -0,0 +1,294 @@
|
|||
/// <reference path="..\..\..\src\harness\harness.ts" />
|
||||
|
||||
namespace ts {
|
||||
function notImplemented(): any {
|
||||
throw new Error("Not yet implemented");
|
||||
}
|
||||
|
||||
const nullLogger: server.Logger = {
|
||||
close: () => void 0,
|
||||
isVerbose: () => void 0,
|
||||
loggingEnabled: () => false,
|
||||
perftrc: () => void 0,
|
||||
info: () => void 0,
|
||||
startGroup: () => void 0,
|
||||
endGroup: () => void 0,
|
||||
msg: () => void 0
|
||||
};
|
||||
|
||||
const { content: libFileContent } = Harness.getDefaultLibraryFile(Harness.IO);
|
||||
|
||||
function getExecutingFilePathFromLibFile(libFile: FileOrFolder): string {
|
||||
return combinePaths(getDirectoryPath(libFile.path), "tsc.js");
|
||||
}
|
||||
|
||||
interface FileOrFolder {
|
||||
path: string;
|
||||
content?: string;
|
||||
}
|
||||
|
||||
interface FSEntry {
|
||||
path: Path;
|
||||
fullPath: string;
|
||||
}
|
||||
|
||||
interface File extends FSEntry {
|
||||
content: string;
|
||||
}
|
||||
|
||||
interface Folder extends FSEntry {
|
||||
entries: FSEntry[];
|
||||
}
|
||||
|
||||
function isFolder(s: FSEntry): s is Folder {
|
||||
return isArray((<Folder>s).entries);
|
||||
}
|
||||
|
||||
function isFile(s: FSEntry): s is File {
|
||||
return typeof (<File>s).content === "string";
|
||||
}
|
||||
|
||||
function addFolder(fullPath: string, toPath: (s: string) => Path, fs: FileMap<FSEntry>): Folder {
|
||||
const path = toPath(fullPath);
|
||||
if (fs.contains(path)) {
|
||||
Debug.assert(isFolder(fs.get(path)));
|
||||
return (<Folder>fs.get(path));
|
||||
}
|
||||
|
||||
const entry: Folder = { path, entries: [], fullPath };
|
||||
fs.set(path, entry);
|
||||
|
||||
const baseFullPath = getDirectoryPath(fullPath);
|
||||
if (fullPath !== baseFullPath) {
|
||||
addFolder(baseFullPath, toPath, fs).entries.push(entry);
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
function sizeOfMap(map: Map<any>): number {
|
||||
let n = 0;
|
||||
for (const name in map) {
|
||||
if (hasProperty(map, name)) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
function checkMapKeys(caption: string, map: Map<any>, expectedKeys: string[]) {
|
||||
assert.equal(sizeOfMap(map), expectedKeys.length, `${caption}: incorrect size of map`);
|
||||
for (const name of expectedKeys) {
|
||||
assert.isTrue(hasProperty(map, name), `${caption} is expected to contain ${name}, actual keys: ${getKeys(map)}`);
|
||||
}
|
||||
}
|
||||
|
||||
function checkFileNames(caption: string, actualFileNames: string[], expectedFileNames: string[]) {
|
||||
assert.equal(actualFileNames.length, expectedFileNames.length, `${caption}: incorrect actual number of files, expected ${JSON.stringify(expectedFileNames)}, got ${actualFileNames}`);
|
||||
for (const f of expectedFileNames) {
|
||||
assert.isTrue(contains(actualFileNames, f), `${caption}: expected to find ${f} in ${JSON.stringify(actualFileNames)}`);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TestServerHost implements server.ServerHost {
|
||||
args: string[] = [];
|
||||
newLine: "\n";
|
||||
|
||||
private fs: ts.FileMap<FSEntry>;
|
||||
private getCanonicalFileName: (s: string) => string;
|
||||
private toPath: (f: string) => Path;
|
||||
readonly watchedDirectories: Map<{ cb: DirectoryWatcherCallback, recursive: boolean }[]> = {};
|
||||
readonly watchedFiles: Map<FileWatcherCallback[]> = {};
|
||||
|
||||
constructor(public useCaseSensitiveFileNames: boolean, private executingFilePath: string, private currentDirectory: string, fileOrFolderList: FileOrFolder[]) {
|
||||
this.getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
|
||||
this.toPath = s => toPath(s, currentDirectory, this.getCanonicalFileName);
|
||||
|
||||
this.reloadFS(fileOrFolderList);
|
||||
}
|
||||
|
||||
reloadFS(filesOrFolders: FileOrFolder[]) {
|
||||
this.fs = createFileMap<FSEntry>();
|
||||
for (const fileOrFolder of filesOrFolders) {
|
||||
const path = this.toPath(fileOrFolder.path);
|
||||
const fullPath = getNormalizedAbsolutePath(fileOrFolder.path, this.currentDirectory);
|
||||
if (typeof fileOrFolder.content === "string") {
|
||||
const entry = { path, content: fileOrFolder.content, fullPath };
|
||||
this.fs.set(path, entry);
|
||||
addFolder(getDirectoryPath(fullPath), this.toPath, this.fs).entries.push(entry);
|
||||
}
|
||||
else {
|
||||
addFolder(fullPath, this.toPath, this.fs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileExists(s: string) {
|
||||
const path = this.toPath(s);
|
||||
return this.fs.contains(path) && isFile(this.fs.get(path));
|
||||
};
|
||||
|
||||
directoryExists(s: string) {
|
||||
const path = this.toPath(s);
|
||||
return this.fs.contains(path) && isFolder(this.fs.get(path));
|
||||
}
|
||||
|
||||
getDirectories(s: string) {
|
||||
const path = this.toPath(s);
|
||||
if (!this.fs.contains(path)) {
|
||||
return [];
|
||||
}
|
||||
else {
|
||||
const entry = this.fs.get(path);
|
||||
return isFolder(entry) ? map(entry.entries, x => getBaseFileName(x.fullPath)) : [];
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
watchDirectory(directoryName: string, callback: DirectoryWatcherCallback, recursive: boolean): DirectoryWatcher {
|
||||
const path = this.toPath(directoryName);
|
||||
const callbacks = lookUp(this.watchedDirectories, path) || (this.watchedDirectories[path] = []);
|
||||
callbacks.push({ cb: callback, recursive });
|
||||
return {
|
||||
referenceCount: 0,
|
||||
directoryName,
|
||||
close: () => {
|
||||
for (let i = 0; i < callbacks.length; i++) {
|
||||
if (callbacks[i].cb === callback) {
|
||||
callbacks.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!callbacks.length) {
|
||||
delete this.watchedDirectories[path];
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
watchFile(fileName: string, callback: FileWatcherCallback) {
|
||||
const path = this.toPath(fileName);
|
||||
const callbacks = lookUp(this.watchedFiles, path) || (this.watchedFiles[path] = []);
|
||||
callbacks.push(callback);
|
||||
return {
|
||||
close: () => {
|
||||
const i = callbacks.indexOf(callback);
|
||||
callbacks.splice(i, 1);
|
||||
if (!callbacks.length) {
|
||||
delete this.watchedFiles[path];
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// TOOD: record and invoke callbacks to simulate timer events
|
||||
readonly setTimeout = (callback: (...args: any[]) => void, ms: number, ...args: any[]): any => void 0;
|
||||
readonly clearTimeout = (timeoutId: any): void => void 0;
|
||||
readonly readFile = (s: string) => (<File>this.fs.get(this.toPath(s))).content;
|
||||
readonly resolvePath = (s: string) => s;
|
||||
readonly getExecutingFilePath = () => this.executingFilePath;
|
||||
readonly getCurrentDirectory = () => this.currentDirectory;
|
||||
readonly writeFile = (path: string, content: string) => notImplemented();
|
||||
readonly write = (s: string) => notImplemented();
|
||||
readonly createDirectory = (s: string) => notImplemented();
|
||||
readonly exit = () => notImplemented();
|
||||
}
|
||||
|
||||
describe("tsserver project system:", () => {
|
||||
it("create inferred project", () => {
|
||||
const appFile: FileOrFolder = {
|
||||
path: "/a/b/c/app.ts",
|
||||
content: `
|
||||
import {f} from "./module"
|
||||
console.log(f)
|
||||
`
|
||||
};
|
||||
const libFile: FileOrFolder = {
|
||||
path: "/a/lib/lib.d.ts",
|
||||
content: libFileContent
|
||||
};
|
||||
const moduleFile: FileOrFolder = {
|
||||
path: "/a/b/c/module.d.ts",
|
||||
content: `export let x: number`
|
||||
};
|
||||
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", [appFile, moduleFile, libFile]);
|
||||
const projectService = new server.ProjectService(host, nullLogger);
|
||||
const { configFileName } = projectService.openClientFile(appFile.path);
|
||||
|
||||
assert(!configFileName, `should not find config, got: '${configFileName}`);
|
||||
assert.equal(projectService.inferredProjects.length, 1, "expected one inferred project");
|
||||
assert.equal(projectService.configuredProjects.length, 0, "expected no configured project");
|
||||
|
||||
const project = projectService.inferredProjects[0];
|
||||
|
||||
checkFileNames("inferred project", project.getFileNames(), [appFile.path, libFile.path, moduleFile.path]);
|
||||
checkMapKeys("watchedDirectories", host.watchedDirectories, ["/a/b/c", "/a/b", "/a"]);
|
||||
});
|
||||
|
||||
it("create configured project without file list", () => {
|
||||
const configFile: FileOrFolder = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: `
|
||||
{
|
||||
"compilerOptions": {},
|
||||
"exclude": [
|
||||
"e"
|
||||
]
|
||||
}`
|
||||
};
|
||||
const libFile: FileOrFolder = {
|
||||
path: "/a/lib/lib.d.ts",
|
||||
content: libFileContent
|
||||
};
|
||||
const file1: FileOrFolder = {
|
||||
path: "/a/b/c/f1.ts",
|
||||
content: "let x = 1"
|
||||
};
|
||||
const file2: FileOrFolder = {
|
||||
path: "/a/b/d/f2.ts",
|
||||
content: "let y = 1"
|
||||
};
|
||||
const file3: FileOrFolder = {
|
||||
path: "/a/b/e/f3.ts",
|
||||
content: "let z = 1"
|
||||
};
|
||||
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", [ configFile, libFile, file1, file2, file3 ]);
|
||||
const projectService = new server.ProjectService(host, nullLogger);
|
||||
const { configFileName, configFileErrors } = projectService.openClientFile(file1.path);
|
||||
|
||||
assert(configFileName, "should find config file");
|
||||
assert.isTrue(!configFileErrors, `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`);
|
||||
assert.equal(projectService.inferredProjects.length, 0, "expected no inferred project");
|
||||
assert.equal(projectService.configuredProjects.length, 1, "expected one configured project");
|
||||
|
||||
const project = projectService.configuredProjects[0];
|
||||
checkFileNames("configuredProjects project, actualFileNames", project.getFileNames(), [file1.path, libFile.path, file2.path]);
|
||||
checkFileNames("configuredProjects project, rootFileNames", project.getRootFiles(), [file1.path, file2.path]);
|
||||
|
||||
checkMapKeys("watchedFiles", host.watchedFiles, [configFile.path, file2.path, libFile.path]); // watching all files except one that was open
|
||||
checkMapKeys("watchedDirectories", host.watchedDirectories, [getDirectoryPath(configFile.path)]);
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue