# core/parsers/export.parser.ts

> 83 lines of code and 17 definitions.

Tree: GovLab Docs
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/docs#file-docs-core-parsers-export-parser-ts
Source text: https://banes-lab.com/source/docs/core/parsers/export.parser.ts.txt

Listed in [core/parsers](https://banes-lab.com/api/source/docs/core/parsers.md), after [core/parsers/diagram.parser.ts](https://banes-lab.com/source/docs/core/parsers/diagram.parser.ts.md) and before [core/parsers/layer.parser.ts](https://banes-lab.com/source/docs/core/parsers/layer.parser.ts.md).

## Definitions

- `isExported` (lexical_declaration, line 18)
- `hasModifier` (lexical_declaration, line 14)
- `variableNames` (lexical_declaration, line 29)
- `clauseNames` (lexical_declaration, line 33)
- `exportedNames` (lexical_declaration, line 59, exported)
- `valuePairs` (lexical_declaration, line 69)
- `declarationPair` (lexical_declaration, line 64)
- `isNamedDeclaration` (lexical_declaration, line 22)
- `exportsFromNode` (lexical_declaration, line 41)
- `barrelExports` (lexical_declaration, line 86, exported)
- `NamedDeclaration` (type_alias_declaration, line 7)
- `clause` (lexical_declaration, line 34)
- `sourceOf` (lexical_declaration, line 54)
- `text` (lexical_declaration, line 55)
- `label` (lexical_declaration, line 80)
- `source` (lexical_declaration, line 87, exported)
- `byName` (lexical_declaration, line 88, exported)

## Contained in

- [core/parsers](https://banes-lab.com/anatomy/docs/folder-docs-core-parsers.md)

## Used by

- [core/analyzers/drift.analyzer.ts](https://banes-lab.com/source/docs/core/analyzers/drift.analyzer.ts.md)
- [core/analyzers/package.analyzer.ts](https://banes-lab.com/source/docs/core/analyzers/package.analyzer.ts.md)

## Linked from

- [core/analyzers](https://banes-lab.com/anatomy/docs/folder-docs-core-analyzers.md)
- [core/parsers](https://banes-lab.com/anatomy/docs/folder-docs-core-parsers.md)

## Source

```typescript
import type { BarrelExport } from "#types/code.types";
import { DEFAULT_LABEL } from "#configuration/constants/graph.constants";
import { isCodeFile } from "#core/predicates/source.predicate";
import { readTextSafe } from "#core/loaders/base.loader";
import ts from "typescript";

type NamedDeclaration =
    | ts.ClassDeclaration
    | ts.EnumDeclaration
    | ts.FunctionDeclaration
    | ts.InterfaceDeclaration
    | ts.TypeAliasDeclaration;

const hasModifier = function hasModifier(node: ts.Node, kind: ts.SyntaxKind): boolean {
    return ts.canHaveModifiers(node) && (ts.getModifiers(node) ?? []).some((modifier) => modifier.kind === kind);
};

const isExported = function isExported(node: ts.Node): boolean {
    return hasModifier(node, ts.SyntaxKind.ExportKeyword);
};

const isNamedDeclaration = function isNamedDeclaration(node: ts.Node): node is NamedDeclaration {
    if (ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node)) {
        return true;
    }
    return ts.isInterfaceDeclaration(node) || ts.isEnumDeclaration(node) || ts.isTypeAliasDeclaration(node);
};

const variableNames = function variableNames(node: ts.VariableStatement): string[] {
    return node.declarationList.declarations.flatMap((decl) => (ts.isIdentifier(decl.name) ? [decl.name.text] : []));
};

const clauseNames = function clauseNames(node: ts.ExportDeclaration, valuesOnly: boolean): string[] {
    const clause = node.exportClause;
    if (!clause || !ts.isNamedExports(clause) || (valuesOnly && node.isTypeOnly)) {
        return [];
    }
    return clause.elements.filter((element) => !valuesOnly || !element.isTypeOnly).map((element) => element.name.text);
};

const exportsFromNode = function exportsFromNode(node: ts.Node): string[] {
    if (ts.isExportDeclaration(node)) {
        return clauseNames(node, false);
    }
    if (!isExported(node)) {
        return [];
    }
    if (ts.isVariableStatement(node)) {
        return variableNames(node);
    }
    return isNamedDeclaration(node) && node.name !== undefined ? [node.name.text] : [];
};

const sourceOf = function sourceOf(filePath: string, kind?: ts.ScriptKind): ts.SourceFile | null {
    const text = readTextSafe(filePath);
    return text === null ? null : ts.createSourceFile(filePath, text, ts.ScriptTarget.ESNext, true, kind);
};

export const exportedNames = function exportedNames(filePath: string): ReadonlySet<string> {
    const source = isCodeFile(filePath) ? sourceOf(filePath) : null;
    return new Set(source === null ? [] : source.statements.flatMap(exportsFromNode));
};

const declarationPair = function declarationPair(stmt: ts.ClassDeclaration | ts.FunctionDeclaration): BarrelExport {
    const label = stmt.name?.text ?? DEFAULT_LABEL;
    return { label, name: hasModifier(stmt, ts.SyntaxKind.DefaultKeyword) ? DEFAULT_LABEL : label };
};

const valuePairs = function valuePairs(stmt: ts.Statement): BarrelExport[] {
    if (ts.isExportDeclaration(stmt)) {
        return clauseNames(stmt, true).map((name) => ({ label: name, name }));
    }
    if ((ts.isFunctionDeclaration(stmt) || ts.isClassDeclaration(stmt)) && isExported(stmt)) {
        return [declarationPair(stmt)];
    }
    if (ts.isVariableStatement(stmt) && isExported(stmt)) {
        return variableNames(stmt).map((name) => ({ label: name, name }));
    }
    if (ts.isExportAssignment(stmt) && stmt.isExportEquals !== true) {
        const label = ts.isIdentifier(stmt.expression) ? stmt.expression.text : DEFAULT_LABEL;
        return [{ label, name: DEFAULT_LABEL }];
    }
    return [];
};

export const barrelExports = function barrelExports(barrelPath: string): BarrelExport[] {
    const source = sourceOf(barrelPath, ts.ScriptKind.JS);
    const byName = new Map<string, string>();
    for (const stmt of source?.statements ?? []) {
        for (const { name, label } of valuePairs(stmt)) {
            byName.set(name, label);
        }
    }
    return [...byName].map(([name, label]) => ({ label, name }));
};
```
