in src/assembler.ts [708:770]
private _addToSubmodule(ns: ts.Symbol, moduleLike: ts.Symbol, packageRoot: string) {
// For each symbol exported by the moduleLike, map it to the ns submodule.
for (const symbol of this._typeChecker.getExportsOfModule(moduleLike)) {
if (this._submoduleMap.has(symbol)) {
const currNs = this._submoduleMap.get(symbol)!;
// Checking if there's been two submodules exporting the same symbol,
// which is illegal. We can tell if the currently registered symbol has
// a different name than the one we're currently trying to register in.
if (currNs.name !== ns.name) {
const currNsDecl = currNs.valueDeclaration ?? currNs.declarations?.[0];
const nsDecl = ns.valueDeclaration ?? ns.declarations?.[0];
// Make sure the error message always lists causes in the same order
const refs = [
{ decl: currNsDecl, name: currNs.name } as const,
{ decl: nsDecl, name: ns.name } as const,
].sort(({ name: l }, { name: r }) => l.localeCompare(r));
this._diagnostics.push(
JsiiDiagnostic.JSII_3003_SYMBOL_IS_EXPORTED_TWICE.create(
_nameOrDeclarationNode(symbol),
refs[0].name,
refs[1].name,
)
.addRelatedInformationIf(refs[0].decl, `Symbol is exported under the "${refs[0].name}" submodule`)
.addRelatedInformationIf(refs[1].decl, `Symbol is exported under the "${refs[1].name}" submodule`),
);
}
// Found two re-exports, which is odd, but they use the same submodule,
// so it's probably okay? That's likely a tsc error, which will have
// been reported for us already anyway.
continue;
}
this._submoduleMap.set(symbol, ns);
// If the exported symbol has any declaration, and that delcaration is of
// an entity that can have nested declarations of interest to jsii
// (classes, interfaces, enums, modules), we need to also associate those
// nested symbols to the submodule (or they won't be named correctly!)
const decl = symbol.declarations?.[0];
if (decl != null) {
if (ts.isClassDeclaration(decl) || ts.isInterfaceDeclaration(decl) || ts.isEnumDeclaration(decl)) {
const type = this._typeChecker.getTypeAtLocation(decl);
if (isSingleValuedEnum(type, this._typeChecker)) {
// type.symbol !== symbol, because symbol is the enum itself, but
// since it's single-valued, the TypeChecker will only show us the
// value's symbol later on.
this._submoduleMap.set(type.symbol, ns);
}
if (type.symbol.exports) {
// eslint-disable-next-line no-await-in-loop
this._addToSubmodule(ns, symbol, packageRoot);
}
} else if (ts.isModuleDeclaration(decl)) {
// eslint-disable-next-line no-await-in-loop
this._registerNamespaces(symbol, packageRoot);
} else if (ts.isNamespaceExport(decl)) {
// eslint-disable-next-line no-await-in-loop
this._registerNamespaces(symbol, packageRoot);
}
}
}
}