export function getAllBehaviors()

in compiler/src/model/utils.ts [1010:1048]


export function getAllBehaviors (node: ClassDeclaration | InterfaceDeclaration): string[] {
  const behaviors = getBehaviors(node.getHeritageClauses())
  const extended = getExtended(node.getHeritageClauses()).flatMap(clause => clause.getTypeNodes())
    .map(t => t.getExpression())

  for (const extend of extended) {
    assert(extend, Node.isReferenceFindable(extend), 'Should be a reference node')
    const declaration = extend.getType().getSymbol()?.getDeclarations()[0]
    assert(extend, declaration != null, `Cannot find declaration for ${extend.getText()}`)
    if (Node.isClassDeclaration(declaration) || Node.isInterfaceDeclaration(declaration)) {
      if (declaration.getHeritageClauses().length > 0) {
        behaviors.push(...getAllBehaviors(declaration))
      }
    } else if (Node.isImportSpecifier(declaration)) {
      const sourceFile = declaration.getImportDeclaration().getModuleSpecifierSourceFile()
      assert(declaration, sourceFile != null, 'Cannot find source file')
      const name = declaration.getName()
      for (const declaration of [...sourceFile.getClasses(), ...sourceFile.getInterfaces()]) {
        if (declaration.getName() === name && declaration.getHeritageClauses().length > 0) {
          behaviors.push(...getAllBehaviors(declaration))
        }
      }
    } else {
      assert(declaration, false, `Unhandled extended declaration ${declaration?.getText() ?? ''}`)
    }
  }

  return Array.from(new Set(behaviors))

  function getExtended (clauses: HeritageClause[]): HeritageClause[] {
    return clauses.filter(clause => clause.getToken() === ts.SyntaxKind.ExtendsKeyword)
  }

  function getBehaviors (clauses: HeritageClause[]): string[] {
    return clauses
      .filter(isKnownBehavior)
      .map(clause => clause.getTypeNodes()[0].getExpression().getText())
  }
}