findAncestor:single callback returns boolean|"quit"
Previously there was a 'found' callback and a 'quit' callback.
This commit is contained in:
parent
3739216c79
commit
fabf5d8d53
2 changed files with 41 additions and 35 deletions
|
@ -803,6 +803,9 @@ namespace ts {
|
|||
|
||||
function isUsedInFunctionOrInstanceProperty(usage: Node, declaration: Node, container?: Node): boolean {
|
||||
return !!findAncestor(usage, current => {
|
||||
if (current === container) {
|
||||
return "quit";
|
||||
}
|
||||
if (isFunctionLike(current)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -824,7 +827,7 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
}
|
||||
}, n => n === container);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1246,7 +1249,7 @@ namespace ts {
|
|||
* Return false if 'stopAt' node is reached or isFunctionLike(current) === true.
|
||||
*/
|
||||
function isSameScopeDescendentOf(initial: Node, parent: Node, stopAt: Node): boolean {
|
||||
return parent && !!findAncestor(initial, n => n === parent, n => n === stopAt || isFunctionLike(n));
|
||||
return parent && !!findAncestor(initial, n => n === stopAt || isFunctionLike(n) ? "quit" : n === parent);
|
||||
}
|
||||
|
||||
function getAnyImportSyntax(node: Node): AnyImportSyntax {
|
||||
|
@ -7890,6 +7893,9 @@ namespace ts {
|
|||
// the type parameters introduced by enclosing declarations. We just pick the first
|
||||
// declaration since multiple declarations will all have the same parent anyway.
|
||||
return !!findAncestor(symbol.declarations[0], node => {
|
||||
if (node.kind === SyntaxKind.ModuleDeclaration || node.kind === SyntaxKind.SourceFile) {
|
||||
return "quit";
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
|
@ -7937,8 +7943,7 @@ namespace ts {
|
|||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
node => node.kind === SyntaxKind.ModuleDeclaration || node.kind === SyntaxKind.SourceFile);
|
||||
});
|
||||
}
|
||||
|
||||
function isTopLevelTypeAlias(symbol: Symbol) {
|
||||
|
@ -10384,8 +10389,7 @@ namespace ts {
|
|||
// The expression is restricted to a single identifier or a sequence of identifiers separated by periods
|
||||
return !!findAncestor(
|
||||
node,
|
||||
n => n.kind === SyntaxKind.TypeQuery,
|
||||
n => n.kind !== SyntaxKind.TypeQuery && n.kind !== SyntaxKind.Identifier && n.kind !== SyntaxKind.QualifiedName);
|
||||
n => n.kind === SyntaxKind.TypeQuery ? true : n.kind === SyntaxKind.Identifier || n.kind === SyntaxKind.QualifiedName ? false : "quit");
|
||||
}
|
||||
|
||||
// Return the flow cache key for a "dotted name" (i.e. a sequence of identifiers
|
||||
|
@ -11629,7 +11633,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
function hasParentWithAssignmentsMarked(node: Node) {
|
||||
return !!findAncestor(node.parent, node => isFunctionLike(node) && getNodeLinks(node).flags & NodeCheckFlags.AssignmentsMarked);
|
||||
return !!findAncestor(node.parent, node => isFunctionLike(node) && !!(getNodeLinks(node).flags & NodeCheckFlags.AssignmentsMarked));
|
||||
}
|
||||
|
||||
function markParameterAssignments(node: Node) {
|
||||
|
@ -11801,7 +11805,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
function isInsideFunction(node: Node, threshold: Node): boolean {
|
||||
return !!findAncestor(node, isFunctionLike, n => n === threshold);
|
||||
return !!findAncestor(node, n => n === threshold ? "quit" : isFunctionLike(n));
|
||||
}
|
||||
|
||||
function checkNestedBlockScopedBinding(node: Identifier, symbol: Symbol): void {
|
||||
|
@ -11875,7 +11879,7 @@ namespace ts {
|
|||
|
||||
// at this point we know that node is the target of assignment
|
||||
// now check that modification happens inside the statement part of the ForStatement
|
||||
return !!findAncestor(current, n => n === container.statement, n => n === container);
|
||||
return !!findAncestor(current, n => n === container ? "quit" : n === container.statement);
|
||||
}
|
||||
|
||||
function captureLexicalThis(node: Node, container: Node): void {
|
||||
|
@ -12057,7 +12061,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
function isInConstructorArgumentInitializer(node: Node, constructorDecl: Node): boolean {
|
||||
return !!findAncestor(node, n => n.kind === SyntaxKind.Parameter, n => n === constructorDecl);
|
||||
return !!findAncestor(node, n => n === constructorDecl ? "quit" : n.kind === SyntaxKind.Parameter);
|
||||
}
|
||||
|
||||
function checkSuperExpression(node: Node): Type {
|
||||
|
@ -12083,7 +12087,7 @@ namespace ts {
|
|||
// class B {
|
||||
// [super.foo()]() {}
|
||||
// }
|
||||
const current = findAncestor(node, n => n.kind === SyntaxKind.ComputedPropertyName, n => n === container);
|
||||
const current = findAncestor(node, n => n === container ? "quit" : n.kind === SyntaxKind.ComputedPropertyName);
|
||||
if (current && current.kind === SyntaxKind.ComputedPropertyName) {
|
||||
error(node, Diagnostics.super_cannot_be_referenced_in_a_computed_property_name);
|
||||
}
|
||||
|
@ -12687,7 +12691,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
function getContextualMapper(node: Node) {
|
||||
node = findAncestor(node, n => n.contextualMapper);
|
||||
node = findAncestor(node, n => !!n.contextualMapper);
|
||||
return node ? node.contextualMapper : identityMapper;
|
||||
}
|
||||
|
||||
|
@ -19138,14 +19142,17 @@ namespace ts {
|
|||
// - parameter is wrapped in function-like entity
|
||||
if (findAncestor(
|
||||
n,
|
||||
current =>
|
||||
isFunctionLike(current.parent) ||
|
||||
// computed property names/initializers in instance property declaration of class like entities
|
||||
// are executed in constructor and thus deferred
|
||||
(current.parent.kind === SyntaxKind.PropertyDeclaration &&
|
||||
!(hasModifier(current.parent, ModifierFlags.Static)) &&
|
||||
isClassLike(current.parent.parent)),
|
||||
n => n === node.initializer)) {
|
||||
current => {
|
||||
if (current === node.initializer) {
|
||||
return "quit";
|
||||
}
|
||||
return isFunctionLike(current.parent) ||
|
||||
// computed property names/initializers in instance property declaration of class like entities
|
||||
// are executed in constructor and thus deferred
|
||||
(current.parent.kind === SyntaxKind.PropertyDeclaration &&
|
||||
!(hasModifier(current.parent, ModifierFlags.Static)) &&
|
||||
isClassLike(current.parent.parent));
|
||||
})) {
|
||||
return;
|
||||
}
|
||||
// fall through to report error
|
||||
|
@ -19946,13 +19953,15 @@ namespace ts {
|
|||
if (!checkGrammarStatementInAmbientContext(node)) {
|
||||
findAncestor(node.parent,
|
||||
current => {
|
||||
if (isFunctionLike(current)) {
|
||||
return "quit";
|
||||
}
|
||||
if (current.kind === SyntaxKind.LabeledStatement && (<LabeledStatement>current).label.text === node.label.text) {
|
||||
const sourceFile = getSourceFileOfNode(node);
|
||||
grammarErrorOnNode(node.label, Diagnostics.Duplicate_label_0, getTextOfNodeFromSourceText(sourceFile.text, node.label));
|
||||
return true;
|
||||
}
|
||||
},
|
||||
isFunctionLike);
|
||||
});
|
||||
}
|
||||
|
||||
// ensure that label is unique
|
||||
|
|
|
@ -224,29 +224,26 @@ namespace ts {
|
|||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through the parent chain of a node and performs the callback on each parent until the callback
|
||||
* returns a truthy value, then returns that value.
|
||||
* If no such value is found, it applies the callback until the parent pointer is undefined or 'done' returns true
|
||||
* If no such value is found, it applies the callback until the parent pointer is undefined or the callback returns "quit"
|
||||
* At that point findAncestor returns undefined.
|
||||
*/
|
||||
export function findAncestor<T>(node: Node, callback: (element: Node) => T | undefined, done?: (element: Node) => boolean): Node {
|
||||
if (node) {
|
||||
while (node) {
|
||||
if (done && done(node)) {
|
||||
break;
|
||||
}
|
||||
if (callback(node)) {
|
||||
return node;
|
||||
}
|
||||
node = node.parent;
|
||||
export function findAncestor(node: Node, callback: (element: Node) => boolean | "quit"): Node {
|
||||
while (node) {
|
||||
const result = callback(node);
|
||||
if (result === "quit") {
|
||||
return undefined;
|
||||
}
|
||||
else if (result) {
|
||||
return node;
|
||||
}
|
||||
node = node.parent;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
export function zipWith<T, U>(arrayA: T[], arrayB: U[], callback: (a: T, b: U, index: number) => void): void {
|
||||
Debug.assert(arrayA.length === arrayB.length);
|
||||
for (let i = 0; i < arrayA.length; i++) {
|
||||
|
|
Loading…
Reference in a new issue