private dispatch()

in src/renderer.ts [240:372]


  private dispatch(tree: ts.Node): OTree {
    const visitor = this.handler;

    // Using a switch on tree.kind + forced down-casting, because this is significantly faster than
    // doing a cascade of `if` statements with the `ts.is<NodeType>` functions, since `tree.kind` is
    // effectively integers, and this switch statement is hence optimizable to a jump table. This is
    // a VERY significant enhancement to the debugging experience, too.
    switch (tree.kind) {
      case ts.SyntaxKind.EmptyStatement:
        // Additional semicolon where it doesn't belong.
        return NO_SYNTAX;
      case ts.SyntaxKind.SourceFile:
        return visitor.sourceFile(tree as ts.SourceFile, this);
      case ts.SyntaxKind.ImportEqualsDeclaration:
        return visitor.importStatement(analyzeImportEquals(tree as ts.ImportEqualsDeclaration, this), this);
      case ts.SyntaxKind.ImportDeclaration:
        return new OTree(
          [],
          analyzeImportDeclaration(tree as ts.ImportDeclaration, this, this.submoduleReferences).map((import_) =>
            visitor.importStatement(import_, this),
          ),
          { canBreakLine: true, separator: '\n' },
        );
      case ts.SyntaxKind.StringLiteral:
      case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
        return visitor.stringLiteral(tree as ts.StringLiteral | ts.NoSubstitutionTemplateLiteral, this);
      case ts.SyntaxKind.NumericLiteral:
        return visitor.numericLiteral(tree as ts.NumericLiteral, this);
      case ts.SyntaxKind.FunctionDeclaration:
        return visitor.functionDeclaration(tree as ts.FunctionDeclaration, this);
      case ts.SyntaxKind.Identifier:
        return visitor.identifier(tree as ts.Identifier, this);
      case ts.SyntaxKind.Block:
        return visitor.block(tree as ts.Block, this);
      case ts.SyntaxKind.Parameter:
        return visitor.parameterDeclaration(tree as ts.ParameterDeclaration, this);
      case ts.SyntaxKind.ReturnStatement:
        return visitor.returnStatement(tree as ts.ReturnStatement, this);
      case ts.SyntaxKind.BinaryExpression:
        return visitor.binaryExpression(tree as ts.BinaryExpression, this);
      case ts.SyntaxKind.IfStatement:
        return visitor.ifStatement(tree as ts.IfStatement, this);
      case ts.SyntaxKind.PropertyAccessExpression:
        const submoduleReference = this.submoduleReferences?.get(tree as ts.PropertyAccessExpression);
        return visitor.propertyAccessExpression(tree as ts.PropertyAccessExpression, this, submoduleReference);
      case ts.SyntaxKind.AwaitExpression:
        return visitor.awaitExpression(tree as ts.AwaitExpression, this);
      case ts.SyntaxKind.CallExpression:
        return visitor.callExpression(tree as ts.CallExpression, this);
      case ts.SyntaxKind.ExpressionStatement:
        return visitor.expressionStatement(tree as ts.ExpressionStatement, this);
      case ts.SyntaxKind.ObjectLiteralExpression:
        return visitor.objectLiteralExpression(tree as ts.ObjectLiteralExpression, this);
      case ts.SyntaxKind.NewExpression:
        return visitor.newExpression(tree as ts.NewExpression, this);
      case ts.SyntaxKind.PropertyAssignment:
        return visitor.propertyAssignment(tree as ts.PropertyAssignment, this);
      case ts.SyntaxKind.VariableStatement:
        return visitor.variableStatement(tree as ts.VariableStatement, this);
      case ts.SyntaxKind.VariableDeclarationList:
        return visitor.variableDeclarationList(tree as ts.VariableDeclarationList, this);
      case ts.SyntaxKind.VariableDeclaration:
        return visitor.variableDeclaration(tree as ts.VariableDeclaration, this);
      case ts.SyntaxKind.ArrayLiteralExpression:
        return visitor.arrayLiteralExpression(tree as ts.ArrayLiteralExpression, this);
      case ts.SyntaxKind.ShorthandPropertyAssignment:
        return visitor.shorthandPropertyAssignment(tree as ts.ShorthandPropertyAssignment, this);
      case ts.SyntaxKind.ForOfStatement:
        return visitor.forOfStatement(tree as ts.ForOfStatement, this);
      case ts.SyntaxKind.ClassDeclaration:
        return visitor.classDeclaration(tree as ts.ClassDeclaration, this);
      case ts.SyntaxKind.Constructor:
        return visitor.constructorDeclaration(tree as ts.ConstructorDeclaration, this);
      case ts.SyntaxKind.PropertyDeclaration:
        return visitor.propertyDeclaration(tree as ts.PropertyDeclaration, this);
      case ts.SyntaxKind.ComputedPropertyName:
        return visitor.computedPropertyName((tree as ts.ComputedPropertyName).expression, this);
      case ts.SyntaxKind.MethodDeclaration:
        return visitor.methodDeclaration(tree as ts.MethodDeclaration, this);
      case ts.SyntaxKind.InterfaceDeclaration:
        return visitor.interfaceDeclaration(tree as ts.InterfaceDeclaration, this);
      case ts.SyntaxKind.PropertySignature:
        return visitor.propertySignature(tree as ts.PropertySignature, this);
      case ts.SyntaxKind.MethodSignature:
        return visitor.methodSignature(tree as ts.MethodSignature, this);
      case ts.SyntaxKind.AsExpression:
        return visitor.asExpression(tree as ts.AsExpression, this);
      case ts.SyntaxKind.PrefixUnaryExpression:
        return visitor.prefixUnaryExpression(tree as ts.PrefixUnaryExpression, this);
      case ts.SyntaxKind.SpreadAssignment:
        if (this.textOf(tree) === '...') {
          return visitor.ellipsis(tree as ts.SpreadAssignment, this);
        }
        return visitor.spreadAssignment(tree as ts.SpreadAssignment, this);
      case ts.SyntaxKind.SpreadElement:
        if (this.textOf(tree) === '...') {
          return visitor.ellipsis(tree as ts.SpreadElement, this);
        }
        return visitor.spreadElement(tree as ts.SpreadElement, this);
      case ts.SyntaxKind.ElementAccessExpression:
        return visitor.elementAccessExpression(tree as ts.ElementAccessExpression, this);
      case ts.SyntaxKind.TemplateExpression:
        return visitor.templateExpression(tree as ts.TemplateExpression, this);
      case ts.SyntaxKind.NonNullExpression:
        return visitor.nonNullExpression(tree as ts.NonNullExpression, this);
      case ts.SyntaxKind.ParenthesizedExpression:
        return visitor.parenthesizedExpression(tree as ts.ParenthesizedExpression, this);
      case ts.SyntaxKind.VoidExpression:
        return visitor.maskingVoidExpression(tree as ts.VoidExpression, this);
      case ts.SyntaxKind.JSDoc:
      case ts.SyntaxKind.JSDocComment:
        return visitor.jsDoc(tree as ts.JSDoc, this);
      default:
        if (ts.isToken(tree)) {
          return visitor.token(tree, this);
        }
        this.reportUnsupported(tree, undefined);
    }

    if (this.options.bestEffort !== false) {
      // When doing best-effort conversion and we don't understand the node type, just return the complete text of it as-is
      return new OTree([this.textOf(tree)]);
    }
    // Otherwise, show a placeholder indicating we don't recognize the type
    const nodeKind = ts.SyntaxKind[tree.kind];
    return new UnknownSyntax(
      [`<${nodeKind} ${this.textOf(tree)}>`],
      ['\n', ...nodeChildren(tree).map(this.convert.bind(this))],
      {
        indent: 2,
      },
    );
  }