/
export.ts
104 lines (89 loc) · 4.49 KB
/
export.ts
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import * as ts from 'typescript';
import { Reflection, ReflectionFlag, DeclarationReflection, ContainerReflection } from '../../models/index';
import { Context } from '../context';
import { Component, ConverterNodeComponent } from '../components';
import { createReferenceReflection } from '../factories/reference';
import { SourceFileMode } from '../../utils';
@Component({name: 'node:export'})
export class ExportConverter extends ConverterNodeComponent<ts.ExportAssignment> {
/**
* List of supported TypeScript syntax kinds.
*/
supports: ts.SyntaxKind[] = [
ts.SyntaxKind.ExportAssignment
];
convert(context: Context, node: ts.ExportAssignment): Reflection {
let symbol: ts.Symbol | undefined;
// default export
if (node.symbol && (node.symbol.flags & ts.SymbolFlags.Alias) === ts.SymbolFlags.Alias) {
symbol = context.checker.getAliasedSymbol(node.symbol);
} else {
let type = context.getTypeAtLocation(node.expression);
symbol = type ? type.symbol : undefined;
}
if (symbol && symbol.declarations) {
const project = context.project;
symbol.declarations.forEach((declaration) => {
if (!declaration.symbol) {
return;
}
const reflection = project.getReflectionFromFQN(context.checker.getFullyQualifiedName(declaration.symbol));
if (node.isExportEquals && reflection instanceof DeclarationReflection) {
reflection.setFlag(ReflectionFlag.ExportAssignment, true);
}
if (reflection) {
markAsExported(reflection);
}
});
}
function markAsExported(reflection: Reflection) {
if (reflection instanceof DeclarationReflection) {
reflection.setFlag(ReflectionFlag.Exported, true);
}
reflection.traverse(markAsExported);
}
return context.scope;
}
}
@Component({ name: 'node:export-declaration' })
export class ExportDeclarationConverter extends ConverterNodeComponent<ts.ExportDeclaration> {
supports = [ts.SyntaxKind.ExportDeclaration];
convert(context: Context, node: ts.ExportDeclaration): Reflection | undefined {
// It doesn't make sense to convert export declarations if we are pretending everything is global.
if (this.application.options.getValue('mode') === SourceFileMode.File) {
return;
}
const scope = context.scope;
if (!(scope instanceof ContainerReflection)) {
throw new Error('Expected to be within a container');
}
if (node.exportClause && node.exportClause.kind === ts.SyntaxKind.NamedExports) { // export { a, a as b }
node.exportClause.elements.forEach(specifier => {
const source = context.expectSymbolAtLocation(specifier.name);
const target = context.resolveAliasedSymbol(context.expectSymbolAtLocation(specifier.propertyName ?? specifier.name));
// If the original declaration is in this file, export {} was used with something
// defined in this file and we don't need to create a reference unless the name is different.
if (!node.moduleSpecifier && !specifier.propertyName) {
return;
}
createReferenceReflection(context, source, target);
});
} else if (node.exportClause && node.exportClause.kind === ts.SyntaxKind.NamespaceExport) { // export * as ns
const source = context.expectSymbolAtLocation(node.exportClause.name);
if (!node.moduleSpecifier) {
throw new Error('Namespace export is missing a module specifier.');
}
const target = context.resolveAliasedSymbol(context.expectSymbolAtLocation(node.moduleSpecifier));
createReferenceReflection(context, source, target);
} else if (node.moduleSpecifier) { // export * from ...
const sourceFileSymbol = context.expectSymbolAtLocation(node.moduleSpecifier);
for (const symbol of context.checker.getExportsOfModule(sourceFileSymbol)) {
if (symbol.name === 'default') { // Default exports are not re-exported with export *
continue;
}
createReferenceReflection(context, symbol, context.resolveAliasedSymbol(symbol));
}
}
return context.scope;
}
}