All files visitNode.ts

100% Statements 39/39
100% Branches 18/18
100% Functions 15/15
100% Lines 39/39
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 862x 2x               2x   2x           1605x 304x 487x       1605x 1605x 304x 814x       1605x 1605x 1x     1604x 303x         4298x 4298x 2693x 5370x       791x 791x 487x 1156x       303x 1115x 1115x 426x 18x       303x 11x 4x 3x     7x           11x       313x 313x 21x   313x    
import * as ts from 'typescript';
import {
  DefKind,
  IgnoredKinds,
  ignoredKindsMap,
  Kind,
  NodeOrNodes,
  Visitor,
} from './types';
import { defs } from './utils';
 
export default function visitNode(
  node: ts.Node,
  visitor: Visitor,
  kind: DefKind,
  iterateBase: boolean,
) {
  if (iterateBase) {
    for (const key of resolveUnion(kind)) {
      visitNode(node, visitor, key, false);
    }
  }
 
  const baseKinds = resolveBase(kind);
  if (iterateBase) {
    for (const key of baseKinds) {
      visitNode(node, visitor, key, false);
    }
  }
 
  const visitorFunc = visitor[kind] || visitor.Default;
  if (visitorFunc(node, kind) === false) {
    return;
  }
 
  if (iterateBase) {
    visitChildren(visitor, resolveChildren(node, baseKinds));
  }
}
 
function resolveBase(kind: DefKind): DefKind[] {
  const base = defs[kind].base;
  return base
    .reduce((r, d) => r.concat(resolveBase(d)), [...base] as DefKind[])
    .filter((o, i, a) => a.indexOf(o) === i);
}
 
function resolveUnion(kind: DefKind): DefKind[] {
  const union = defs[kind].union || [];
  return union
    .reduce((r, d) => r.concat(resolveUnion(d)), [...union] as DefKind[])
    .filter((o, i, a) => a.indexOf(o) === i);
}
 
function resolveChildren(node: ts.Node, baseKinds: DefKind[]): NodeOrNodes[] {
  return [...baseKinds, getKind(node)]
    .map(k => defs[k].getChildren)
    .reduce((r, w) => (w ? r.concat(w(node)) : r), [] as NodeOrNodes[])
    .filter(o => o !== undefined)
    .filter((o, i, a) => a.indexOf(o) === i);
}
 
function visitChildren(visitor: Visitor, items: NodeOrNodes[]) {
  for (const item of items) {
    if (isArray(item)) {
      for (const child of item) {
        visitNode(child, visitor, getKind(child), true);
      }
    } else {
      visitNode(item as ts.Node, visitor, getKind(item as ts.Node), true);
    }
  }
}
 
function isArray(node: NodeOrNodes): node is ReadonlyArray<ts.Node> {
  return Array.isArray(node);
}
 
function getKind(node: ts.Node): Kind {
  let value = ts.SyntaxKind[node.kind];
  if (IgnoredKinds.hasOwnProperty(value)) {
    value = ignoredKindsMap[value];
  }
  return value as Kind;
}