Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(namespace-exports): fix problem where ExportDeclarations- and/or …
…ImportDeclarations are sometimes lost when inlining ModuleDeclarations. Closes #130
- Loading branch information
Showing
18 changed files
with
549 additions
and
154 deletions.
There are no files selected for viewing
5 changes: 5 additions & 0 deletions
5
...ormers/inline-namespace-module-block-transformer/inline-namespace-module-block-options.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import {TS} from "../../../../../type/ts"; | ||
|
||
export interface InlineNamespaceModuleBlockOptions { | ||
intentToAddImportDeclaration (importDeclaration: TS.ImportDeclaration): void; | ||
} |
52 changes: 52 additions & 0 deletions
52
...rs/inline-namespace-module-block-transformer/inline-namespace-module-block-transformer.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import {TS} from "../../../../../type/ts"; | ||
import {visitNode} from "./visitor/visit-node"; | ||
import {shouldDebugMetrics, shouldDebugSourceFile} from "../../../../../util/is-debug/should-debug"; | ||
import {logMetrics} from "../../../../../util/logging/log-metrics"; | ||
import {logTransformer} from "../../../../../util/logging/log-transformer"; | ||
import {preserveMeta} from "../../util/clone-node-with-meta"; | ||
import {DeclarationTransformer} from "../../declaration-bundler-options"; | ||
import {InlineNamespaceModuleBlockOptions} from "./inline-namespace-module-block-options"; | ||
|
||
export function inlineNamespaceModuleBlockTransformer({intentToAddImportDeclaration}: InlineNamespaceModuleBlockOptions): DeclarationTransformer { | ||
return options => { | ||
const {typescript, context, sourceFile, pluginOptions, printer} = options; | ||
|
||
const fullBenchmark = shouldDebugMetrics(pluginOptions.debug, sourceFile) ? logMetrics(`Inlining ModuleBlock to be wrapped in a Namespace`, sourceFile.fileName) : undefined; | ||
|
||
const transformationLog = shouldDebugSourceFile(pluginOptions.debug, sourceFile) ? logTransformer("Inlining ModuleBlock to be wrapped in a Namespace", sourceFile, printer) : undefined; | ||
|
||
// Prepare some VisitorOptions | ||
const visitorOptions = { | ||
...options, | ||
intentToAddImportDeclaration, | ||
|
||
childContinuation: <U extends TS.Node>(node: U): U => | ||
typescript.visitEachChild( | ||
node, | ||
nextNode => | ||
visitNode({ | ||
...visitorOptions, | ||
node: nextNode | ||
}), | ||
context | ||
), | ||
|
||
continuation: <U extends TS.Node>(node: U): U => | ||
visitNode({ | ||
...visitorOptions, | ||
node | ||
}) as U | ||
}; | ||
|
||
const result = preserveMeta( | ||
typescript.visitEachChild(sourceFile, nextNode => visitorOptions.continuation(nextNode), context), | ||
sourceFile, | ||
options | ||
); | ||
|
||
transformationLog?.finish(result); | ||
fullBenchmark?.finish(); | ||
|
||
return result; | ||
}; | ||
} |
11 changes: 11 additions & 0 deletions
11
...nline-namespace-module-block-transformer/inline-namespace-module-block-visitor-options.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import {TS} from "../../../../../type/ts"; | ||
import {SourceFileBundlerVisitorOptions} from "../source-file-bundler/source-file-bundler-visitor-options"; | ||
import {InlineNamespaceModuleBlockOptions} from "./inline-namespace-module-block-options"; | ||
|
||
export interface InlineNamespaceModuleBlockVisitorOptions<T extends TS.Node> extends SourceFileBundlerVisitorOptions, InlineNamespaceModuleBlockOptions { | ||
typescript: typeof TS; | ||
node: T; | ||
|
||
childContinuation<U extends TS.Node>(node: U): U; | ||
continuation<U extends TS.Node>(node: U): U; | ||
} |
82 changes: 82 additions & 0 deletions
82
...ransformers/inline-namespace-module-block-transformer/visitor/visit-export-declaration.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import {TS} from "../../../../../../type/ts"; | ||
import {InlineNamespaceModuleBlockVisitorOptions} from "../inline-namespace-module-block-visitor-options"; | ||
import {preserveParents} from "../../../util/clone-node-with-meta"; | ||
import {isNodeFactory} from "../../../util/is-node-factory"; | ||
import {generateIdentifierName} from "../../../util/generate-identifier-name"; | ||
import {addBindingToLexicalEnvironment} from "../../../util/add-binding-to-lexical-environment"; | ||
import {generateUniqueBinding} from "../../../util/generate-unique-binding"; | ||
import {isIdentifierFree} from "../../../util/is-identifier-free"; | ||
import {getOriginalSourceFile} from "../../../util/get-original-source-file"; | ||
|
||
export function visitExportDeclaration(options: InlineNamespaceModuleBlockVisitorOptions<TS.ExportDeclaration>): TS.ExportDeclaration|undefined { | ||
const {node, typescript, compatFactory, host, lexicalEnvironment, sourceFile, intentToAddImportDeclaration} = options; | ||
|
||
if (node.moduleSpecifier == null || !typescript.isStringLiteralLike(node.moduleSpecifier)) { | ||
return node; | ||
} | ||
|
||
// Otherwise, we'll have to generate an ImportDeclaration outside the ModuleBlock and reference it here | ||
|
||
if (node.exportClause == null || typescript.isNamespaceExport?.(node.exportClause)) { | ||
const bindingName = generateIdentifierName(node.moduleSpecifier.text, "namespace"); | ||
addBindingToLexicalEnvironment(lexicalEnvironment, sourceFile.fileName, bindingName); | ||
|
||
const resolveResult = host.resolve(node.moduleSpecifier.text, sourceFile.fileName); | ||
const resolvedFileName = resolveResult?.resolvedAmbientFileName ?? resolveResult?.resolvedFileName; | ||
if (resolvedFileName == null) { | ||
return undefined; | ||
} | ||
const resolvedSourceFile = options.host.getSourceFile(resolvedFileName); | ||
if (resolvedSourceFile == null) { | ||
return undefined; | ||
} | ||
const originalSourceFile = getOriginalSourceFile(node, sourceFile, typescript); | ||
|
||
const exportedBindings = [...(resolvedSourceFile as {symbol?: {exports?: Map<string, unknown>}}).symbol?.exports?.keys() ?? []].map(binding => isIdentifierFree(lexicalEnvironment, binding, originalSourceFile.fileName) ? [binding, binding] : [binding, generateUniqueBinding(lexicalEnvironment, binding)]); | ||
|
||
const namedImports = compatFactory.createNamedImports(exportedBindings.map(([name, deconflictedName]) => | ||
compatFactory.createImportSpecifier( | ||
name === deconflictedName ? undefined : compatFactory.createIdentifier(name), | ||
compatFactory.createIdentifier(deconflictedName) | ||
) | ||
)); | ||
|
||
intentToAddImportDeclaration( | ||
compatFactory.createImportDeclaration( | ||
undefined, | ||
undefined, | ||
isNodeFactory(compatFactory) | ||
? compatFactory.createImportClause(false, undefined, namedImports) | ||
: compatFactory.createImportClause(undefined, namedImports, false), | ||
compatFactory.createStringLiteral(node.moduleSpecifier.text) | ||
) | ||
); | ||
|
||
const namedExports = compatFactory.createNamedExports(exportedBindings.map(([name, deconflictedName]) => compatFactory.createExportSpecifier( | ||
name === deconflictedName ? undefined : compatFactory.createIdentifier(deconflictedName), compatFactory.createIdentifier(name) | ||
))); | ||
|
||
return preserveParents( | ||
isNodeFactory(compatFactory) | ||
? compatFactory.updateExportDeclaration( | ||
node, | ||
node.decorators, | ||
node.modifiers, | ||
node.isTypeOnly, | ||
namedExports, | ||
undefined | ||
) | ||
: compatFactory.updateExportDeclaration( | ||
node, | ||
node.decorators, | ||
node.modifiers, | ||
namedExports, | ||
undefined, | ||
node.isTypeOnly | ||
), | ||
options | ||
); | ||
} | ||
|
||
return node; | ||
} |
10 changes: 10 additions & 0 deletions
10
...ransformers/inline-namespace-module-block-transformer/visitor/visit-import-declaration.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import {TS} from "../../../../../../type/ts"; | ||
import {InlineNamespaceModuleBlockVisitorOptions} from "../inline-namespace-module-block-visitor-options"; | ||
import {cloneNodeWithMeta} from "../../../util/clone-node-with-meta"; | ||
|
||
export function visitImportDeclaration(options: InlineNamespaceModuleBlockVisitorOptions<TS.ImportDeclaration>): undefined { | ||
const {node, intentToAddImportDeclaration} = options; | ||
intentToAddImportDeclaration(cloneNodeWithMeta(node, options)); | ||
|
||
return undefined; | ||
} |
15 changes: 15 additions & 0 deletions
15
...tion-bundler/transformers/inline-namespace-module-block-transformer/visitor/visit-node.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import {TS} from "../../../../../../type/ts"; | ||
import {InlineNamespaceModuleBlockVisitorOptions} from "../inline-namespace-module-block-visitor-options"; | ||
import {visitImportDeclaration} from "./visit-import-declaration"; | ||
import {visitExportDeclaration} from "./visit-export-declaration"; | ||
|
||
export function visitNode({node, ...options}: InlineNamespaceModuleBlockVisitorOptions<TS.Node>): TS.Node|undefined { | ||
if (options.typescript.isImportDeclaration(node)) { | ||
return visitImportDeclaration({...options, node}); | ||
} else if (options.typescript.isExportDeclaration(node)) { | ||
return visitExportDeclaration({...options, node}); | ||
} else { | ||
// Only consider root-level statements here | ||
return node; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.