Skip to content

Commit

Permalink
Merge pull request #268 from Atrue/export-default-expression
Browse files Browse the repository at this point in the history
Resolve export default expression name collision
  • Loading branch information
timocov authored Nov 26, 2023
2 parents 697c6df + 6c033c0 commit b2e2d7e
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 19 deletions.
25 changes: 25 additions & 0 deletions src/bundle-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
resolveIdentifier,
SourceFileExport,
splitTransientSymbol,
StatementRenaming,
} from './helpers/typescript';

import { fixPath } from './helpers/fix-path';
Expand Down Expand Up @@ -182,6 +183,7 @@ export function generateDtsBundle(entries: readonly EntryPointConfig[], options:
statements: [],
renamedExports: [],
declarationsRenaming: new Map(),
nameCollision: new Map(),
};

const outputOptions: OutputOptions = entry.output || {};
Expand All @@ -199,6 +201,15 @@ export function generateDtsBundle(entries: readonly EntryPointConfig[], options:
};
};

const getStatementRenaming = (statement: ts.Statement): StatementRenaming => {
if (ts.isVariableStatement(statement)) {
return statement.declarationList.declarations.map(declaration => {
return collectionResult.declarationsRenaming.get(declaration);
});
}
return [];
};

const updateResultCommonParams = {
isStatementUsed: (statement: ts.Statement | ts.SourceFile) => isNodeUsed(
statement,
Expand Down Expand Up @@ -249,6 +260,18 @@ export function generateDtsBundle(entries: readonly EntryPointConfig[], options:
// so we have to generate some random name and then re-export it with really exported names
identifierName = `__DTS_BUNDLE_GENERATOR__GENERATED_NAME$${uniqueNameCounter++}`;
collectionResult.declarationsRenaming.set(resolvedDeclaration, identifierName);
} else if (
ts.isVariableDeclaration(resolvedDeclaration)
&& identifierName
) {
const collision = collectionResult.nameCollision.get(identifierName);
if (!collision) {
collectionResult.nameCollision.set(identifierName, new Set([resolvedDeclaration]));
} else if (!collision.has(resolvedDeclaration)) {
collision.add(resolvedDeclaration);
identifierName = `${identifierName}$${collision.size}`;
collectionResult.declarationsRenaming.set(resolvedDeclaration, identifierName);
}
}

return identifierName;
Expand Down Expand Up @@ -358,6 +381,7 @@ export function generateDtsBundle(entries: readonly EntryPointConfig[], options:
{
...collectionResult,
needStripDefaultKeywordForStatement,
getStatementRenaming,
shouldStatementHasExportKeyword: (statement: ts.Statement) => {
const statementExports = getExportsForStatement(rootFileExports, typeChecker, statement);

Expand Down Expand Up @@ -440,6 +464,7 @@ interface CollectingResult {
statements: ts.Statement[];
renamedExports: string[];
declarationsRenaming: Map<ts.NamedDeclaration, string>;
nameCollision: Map<string, Set<ts.NamedDeclaration>>;
}

type NodeWithReferencedModule = ts.ExportDeclaration | ts.ModuleDeclaration | ts.ImportTypeNode | ts.ImportEqualsDeclaration | ts.ImportDeclaration;
Expand Down
17 changes: 13 additions & 4 deletions src/generate-output.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import * as ts from 'typescript';

import { packageVersion } from './helpers/package-version';
import { getModifiers, modifiersToMap, recreateRootLevelNodeWithModifiers } from './helpers/typescript';
import {
getModifiers,
modifiersToMap,
recreateRootLevelNodeWithModifiers,
StatementRenaming,
} from './helpers/typescript';

export interface ModuleImportsSet {
defaultImports: Set<string>;
Expand All @@ -24,6 +29,7 @@ export interface NeedStripDefaultKeywordResult {

export interface OutputHelpers {
shouldStatementHasExportKeyword(statement: ts.Statement): boolean;
getStatementRenaming(statement: ts.Statement): StatementRenaming;
needStripDefaultKeywordForStatement(statement: ts.Statement): NeedStripDefaultKeywordResult;
needStripConstFromConstEnum(constEnum: ts.EnumDeclaration): boolean;
needStripImportFromImportTypeNode(importType: ts.ImportTypeNode): boolean;
Expand Down Expand Up @@ -156,8 +162,11 @@ function getStatementText(statement: ts.Statement, includeSortingValue: boolean,
modifiersMap[ts.SyntaxKind.ConstKeyword] = false;
}

let newName: string | undefined;
let renaming: StatementRenaming = [];

if (modifiersMap[ts.SyntaxKind.DeclareKeyword]) {
renaming = helpers.getStatementRenaming(statement);
}
// strip the `default` keyword from node
if (modifiersMap[ts.SyntaxKind.DefaultKeyword]) {
const needStripDefaultKeywordResult = helpers.needStripDefaultKeywordForStatement(statement);
Expand All @@ -169,7 +178,7 @@ function getStatementText(statement: ts.Statement, includeSortingValue: boolean,
modifiersMap[ts.SyntaxKind.DeclareKeyword] = true;
}

newName = needStripDefaultKeywordResult.newName;
renaming = [needStripDefaultKeywordResult.newName];
}
}

Expand All @@ -193,7 +202,7 @@ function getStatementText(statement: ts.Statement, includeSortingValue: boolean,
modifiersMap[ts.SyntaxKind.DeclareKeyword] = true;
}

return recreateRootLevelNodeWithModifiers(node, modifiersMap, newName, shouldStatementHasExportKeyword);
return recreateRootLevelNodeWithModifiers(node, modifiersMap, renaming, shouldStatementHasExportKeyword);
},
}
);
Expand Down
56 changes: 41 additions & 15 deletions src/helpers/typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,8 @@ function getExportsForName(

export type ModifiersMap = Record<ts.ModifierSyntaxKind, boolean>;

export type StatementRenaming = (string | undefined)[];

const modifiersPriority: Partial<Record<ts.ModifierSyntaxKind, number>> = {
[ts.SyntaxKind.ExportKeyword]: 4,
[ts.SyntaxKind.DefaultKeyword]: 3,
Expand Down Expand Up @@ -317,8 +319,8 @@ export function modifiersMapToArray(modifiersMap: ModifiersMap): ts.Modifier[] {
});
}

export function recreateRootLevelNodeWithModifiers(node: ts.Node, modifiersMap: ModifiersMap, newName?: string, keepComments: boolean = true): ts.Node {
const newNode = recreateRootLevelNodeWithModifiersImpl(node, modifiersMap, newName);
export function recreateRootLevelNodeWithModifiers(node: ts.Node, modifiersMap: ModifiersMap, renaming?: StatementRenaming, keepComments: boolean = true): ts.Node {
const newNode = recreateRootLevelNodeWithModifiersImpl(node, modifiersMap, renaming);

if (keepComments) {
ts.setCommentRange(newNode, ts.getCommentRange(node));
Expand All @@ -328,7 +330,7 @@ export function recreateRootLevelNodeWithModifiers(node: ts.Node, modifiersMap:
}

// eslint-disable-next-line complexity
function recreateRootLevelNodeWithModifiersImpl(node: ts.Node, modifiersMap: ModifiersMap, newName?: string): ts.Node {
function recreateRootLevelNodeWithModifiersImpl(node: ts.Node, modifiersMap: ModifiersMap, renaming: StatementRenaming = []): ts.Node {
const modifiers = modifiersMapToArray(modifiersMap);

if (ts.isArrowFunction(node)) {
Expand All @@ -345,7 +347,7 @@ function recreateRootLevelNodeWithModifiersImpl(node: ts.Node, modifiersMap: Mod
if (ts.isClassDeclaration(node)) {
return ts.factory.createClassDeclaration(
modifiers,
newName || node.name,
renaming[0] || node.name,
node.typeParameters,
node.heritageClauses,
node.members
Expand All @@ -355,7 +357,7 @@ function recreateRootLevelNodeWithModifiersImpl(node: ts.Node, modifiersMap: Mod
if (ts.isClassExpression(node)) {
return ts.factory.createClassExpression(
modifiers,
newName || node.name,
renaming[0] || node.name,
node.typeParameters,
node.heritageClauses,
node.members
Expand All @@ -365,7 +367,7 @@ function recreateRootLevelNodeWithModifiersImpl(node: ts.Node, modifiersMap: Mod
if (ts.isEnumDeclaration(node)) {
return ts.factory.createEnumDeclaration(
modifiers,
newName || node.name,
renaming[0] || node.name,
node.members
);
}
Expand All @@ -392,7 +394,7 @@ function recreateRootLevelNodeWithModifiersImpl(node: ts.Node, modifiersMap: Mod
return ts.factory.createFunctionDeclaration(
modifiers,
node.asteriskToken,
newName || node.name,
renaming[0] || node.name,
node.typeParameters,
node.parameters,
node.type,
Expand All @@ -404,7 +406,7 @@ function recreateRootLevelNodeWithModifiersImpl(node: ts.Node, modifiersMap: Mod
return ts.factory.createFunctionExpression(
modifiers,
node.asteriskToken,
newName || node.name,
renaming[0] || node.name,
node.typeParameters,
node.parameters,
node.type,
Expand All @@ -425,15 +427,15 @@ function recreateRootLevelNodeWithModifiersImpl(node: ts.Node, modifiersMap: Mod
return ts.factory.createImportEqualsDeclaration(
modifiers,
node.isTypeOnly,
newName || node.name,
renaming[0] || node.name,
node.moduleReference
);
}

if (ts.isInterfaceDeclaration(node)) {
return ts.factory.createInterfaceDeclaration(
modifiers,
newName || node.name,
renaming[0] || node.name,
node.typeParameters,
node.heritageClauses,
node.members
Expand All @@ -452,23 +454,47 @@ function recreateRootLevelNodeWithModifiersImpl(node: ts.Node, modifiersMap: Mod
if (ts.isTypeAliasDeclaration(node)) {
return ts.factory.createTypeAliasDeclaration(
modifiers,
newName || node.name,
renaming[0] || node.name,
node.typeParameters,
node.type
);
}

if (ts.isVariableStatement(node)) {
return ts.factory.createVariableStatement(
modifiers,
node.declarationList
);
return createVariableStatement(node, modifiers, renaming);
}

throw new Error(`Unknown top-level node kind (with modifiers): ${ts.SyntaxKind[node.kind]}.
If you're seeing this error, please report a bug on https://github.com/timocov/dts-bundle-generator/issues`);
}

function createVariableStatement(node: ts.VariableStatement, modifiers: ts.Modifier[], renaming: StatementRenaming): ts.Node {
const renamedDeclarations = node.declarationList.declarations.map((declaration, i) => {
const name = renaming[i];
if (!name) {
return declaration;
}

const identifier = ts.factory.createIdentifier(name);
return ts.factory.updateVariableDeclaration(
declaration,
identifier,
declaration.exclamationToken,
declaration.type,
declaration.initializer
);
});
const declarationList = ts.factory.updateVariableDeclarationList(
node.declarationList,
renamedDeclarations
);

return ts.factory.createVariableStatement(
modifiers,
declarationList
);
}

export function getModifiers(node: ts.Node): readonly ts.Modifier[] | undefined {
if (!ts.canHaveModifiers(node)) {
return undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ export { default as myClass1 } from './class';
export { default as myClass2 } from './class';
export { default as myClass3 } from './another-class';
export { default as myClass4 } from './another-class';

export { default as number } from './number';
export { default as string } from './string';
export { default as object } from './object';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default 0;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default {
type: 'object',
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ declare class __DTS_BUNDLE_GENERATOR__GENERATED_NAME$3 {
declare class __DTS_BUNDLE_GENERATOR__GENERATED_NAME$4 {
second: number;
}
declare const _default: 0;
declare const _default$2: "";
declare const _default$3: {
type: string;
};

export {
__DTS_BUNDLE_GENERATOR__GENERATED_NAME$1 as myFunc1,
Expand All @@ -16,6 +21,9 @@ export {
__DTS_BUNDLE_GENERATOR__GENERATED_NAME$3 as myClass2,
__DTS_BUNDLE_GENERATOR__GENERATED_NAME$4 as myClass3,
__DTS_BUNDLE_GENERATOR__GENERATED_NAME$4 as myClass4,
_default as number,
_default$2 as string,
_default$3 as object,
};

export {};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default '';

0 comments on commit b2e2d7e

Please sign in to comment.