The Export API provides tools for managing exports and module boundaries in TypeScript codebases.
Exports are a TS-only language feature
Export Statements vs Exports
Similar to imports, Codegen provides two levels of abstraction for working with exports:
// One ExportStatement containing multiple Export objects
export { foo, bar as default, type User };
// Creates:
// - Export for 'foo'
// - Export for 'bar' as default
// - Export for 'User' as a type
// Direct exports create one ExportStatement per export
export const value = 42;
export function process() {}
You can access these through your file’s collections:
# Access all exports in the codebase
for export in codebase.exports:
...
# Access all export statements
for stmt in file.export_statements:
for exp in stmt.exports:
...
ExportStatement inherits from Statement, providing operations like remove()
and insert_before()
. This is particularly useful when you want to manipulate the entire export declaration.
Common Operations
Here are common operations for working with exports:
# Add exports from source code
file.add_export_from_source("export { MyComponent };")
file.add_export_from_source("export type { MyType } from './types';")
# Export existing symbols
component = file.get_function("MyComponent")
file.add_export(component) # export { MyComponent }
file.add_export(component, alias="default") # export { MyComponent as default }
# Convert to type export
export = file.get_export("MyType")
export.make_type_export()
# Remove exports
export = file.get_export("MyComponent")
export.remove() # Removes export but keeps the symbol
# Remove multiple exports
for export in file.exports:
if not export.is_type_export():
export.remove()
# Update export properties
export.update(
name="NewName",
is_type=True,
is_default=False
)
# Export from another file
other_file = codebase.get_file("./components.ts")
component = other_file.get_class("Button")
file.add_export(component, from_file=other_file) # export { Button } from './components';
# Analyze symbols being exported
for export in file.exports:
if isinstance(export.exported_symbol, ExternalModule):
print('Exporting ExternalModule')
else:
...
When adding exports, you can:
- Add from source code with
add_export_from_source()
- Export existing symbols with
add_export()
- Re-export from other files by specifying
from_file
The export will automatically handle adding any required imports.
Export Types
Codegen supports several types of exports:
// Direct exports
export const value = 42; // Value export
export function myFunction() {} // Function export
export class MyClass {} // Class export
export type MyType = string; // Type export
export interface MyInterface {} // Interface export
export enum MyEnum {} // Enum export
// Re-exports
export { foo, bar } from './other-file'; // Named re-exports
export type { Type } from './other-file'; // Type re-exports
export * from './other-file'; // Wildcard re-exports
export * as utils from './other-file'; // Namespace re-exports
// Aliased exports
export { foo as foop }; // Basic alias
export { foo as default }; // Default export alias
export { bar as baz } from './other-file'; // Re-export with alias
Identifying Export Types
The Export API provides methods to identify and filter exports:
# Check export types
for exp in file.exports:
if exp.is_type_export():
print(f"Type export: {exp.name}")
elif exp.is_default_export():
print(f"Default export: {exp.name}")
elif exp.is_wildcard_export():
print(f"Wildcard export from: {exp.from_file.filepath}")
Export Resolution
You can trace exports to their original symbols:
for exp in file.exports:
if exp.is_reexport():
# Get original and current symbols
current = exp.exported_symbol
original = exp.resolved_symbol
print(f"Re-exporting {original.name} from {exp.from_file.filepath}")
print(f"Through: {' -> '.join(e.file.filepath for e in exp.export_chain)}")
Managing Re-exports
You can manage re-exports with the TSExport.is_reexport() API:
# Create public API
index_file = codebase.get_file("index.ts")
# Re-export from internal files
for internal_file in codebase.files:
if internal_file.name != "index":
for symbol in internal_file.symbols:
if symbol.is_public:
index_file.add_export(
symbol,
from_file=internal_file
)
# Convert default to named exports
for exp in file.exports:
if exp.is_default_export():
exp.make_named_export()
# Consolidate re-exports
from collections import defaultdict
file_exports = defaultdict(list)
for exp in file.exports:
if exp.is_reexport():
file_exports[exp.from_file].append(exp)
for from_file, exports in file_exports.items():
if len(exports) > 1:
# Create consolidated re-export
names = [exp.name for exp in exports]
file.add_export_from_source(
f"export {{ {', '.join(names)} }} from '{from_file.filepath}'"
)
# Remove individual exports
for exp in exports:
exp.remove()
When managing exports, consider the impact on your module’s public API. Not all symbols that can be exported should be exported.