Skip to content

Commit 8366801

Browse files
authored
ts-types transformer: update importers with naming collisions (#5968)
1 parent 11ca1c9 commit 8366801

File tree

12 files changed

+96
-26
lines changed

12 files changed

+96
-26
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
declare function _log1(message: string): void;
2+
declare function xyz(message: number): void;
3+
export function log(f: typeof _log1 | typeof xyz): void;
4+
5+
//# sourceMappingURL=types.d.ts.map
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { log as logFn1 } from "./other1";
2+
import { log as logFn2 } from "./other2";
3+
4+
export function log(f: typeof logFn1 | typeof logFn2) {
5+
logFn1("1");
6+
logFn2(1);
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export function log(message: string) {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
function xyz(message: number) {}
2+
export { xyz as log };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"name": "ts-types-importing",
3+
"private": true,
4+
"main": "dist/main.js",
5+
"types": "dist/types.d.ts"
6+
}

packages/core/integration-tests/test/integration/ts-types/importing-collision/yarn.lock

Whitespace-only changes.

packages/core/integration-tests/test/ts-types.js

+38
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,44 @@ describe('typescript types', function() {
6868
assert.equal(dist, expected);
6969
});
7070

71+
it('should generate ts declarations with imports and naming collisions', async function() {
72+
let b = await bundle(
73+
path.join(
74+
__dirname,
75+
'/integration/ts-types/importing-collision/index.ts',
76+
),
77+
);
78+
79+
assertBundles(b, [
80+
{
81+
type: 'js',
82+
assets: ['index.ts', 'other1.ts', 'other2.ts', 'esmodule-helpers.js'],
83+
},
84+
{
85+
type: 'ts',
86+
assets: ['index.ts'],
87+
},
88+
]);
89+
90+
let dist = (
91+
await outputFS.readFile(
92+
path.join(
93+
__dirname,
94+
'/integration/ts-types/importing-collision/dist/types.d.ts',
95+
),
96+
'utf8',
97+
)
98+
).replace(/\r\n/g, '\n');
99+
let expected = await inputFS.readFile(
100+
path.join(
101+
__dirname,
102+
'/integration/ts-types/importing-collision/expected.d.ts',
103+
),
104+
'utf8',
105+
);
106+
assert.equal(dist, expected);
107+
});
108+
71109
it('should generate ts declarations with exports', async function() {
72110
let b = await bundle(
73111
path.join(__dirname, '/integration/ts-types/exporting/index.ts'),

packages/transformers/typescript-types/src/TSModule.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@ export class TSModule {
2323
addImport(local: string, specifier: string, imported: string) {
2424
this.imports.set(local, {specifier, imported});
2525
if (imported !== '*' && imported !== 'default') {
26-
this.names.set(local, imported);
26+
this.names.set(local, local);
2727
}
2828
}
2929

30+
// if not a reexport: imported = local, name = exported
3031
addExport(name: string, imported: string, specifier: ?string) {
3132
this.exports.push({name, specifier, imported});
3233
}

packages/transformers/typescript-types/src/TSModuleGraph.js

+23-13
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
// @flow
22
import type {TSModule, Export} from './TSModule';
3-
import typeof TypeScriptModule from 'typescript'; // eslint-disable-line import/no-extraneous-dependencies
3+
44
import nullthrows from 'nullthrows';
55
import invariant from 'assert';
6+
import ts from 'typescript';
67

78
export class TSModuleGraph {
8-
ts: TypeScriptModule;
99
modules: Map<string, TSModule>;
1010
mainModuleName: string;
1111
mainModule: ?TSModule;
1212

13-
constructor(ts: TypeScriptModule, mainModuleName: string) {
14-
this.ts = ts;
13+
constructor(mainModuleName: string) {
1514
this.modules = new Map();
1615
this.mainModuleName = mainModuleName;
1716
this.mainModule = null;
@@ -29,18 +28,16 @@ export class TSModuleGraph {
2928
}
3029

3130
markUsed(module: TSModule, name: string, context: any): void {
32-
let {ts} = this;
33-
3431
// If name is imported, mark used in the original module
3532
if (module.imports.has(name)) {
3633
module.used.add(name);
37-
let {specifier, imported} = nullthrows(module.imports.get(name));
38-
let m = this.getModule(specifier);
39-
if (!m) {
34+
let resolved = this.resolveImport(module, name);
35+
// Missing or external
36+
if (!resolved || resolved.module === module) {
4037
return;
4138
}
4239

43-
return this.markUsed(m, imported, context);
40+
return this.markUsed(resolved.module, resolved.imported, context);
4441
}
4542

4643
if (module.used.has(name)) {
@@ -112,8 +109,8 @@ export class TSModuleGraph {
112109
// Named export
113110
return {
114111
module: m,
115-
name: m.getName(exportName),
116-
imported: e.imported || exportName,
112+
name: exportName,
113+
imported: e.imported != null ? m.getName(e.imported) : exportName,
117114
};
118115
}
119116

@@ -205,14 +202,22 @@ export class TSModuleGraph {
205202
exportedNames.set(e.name, e.module);
206203
}
207204

205+
let importedSymbolsToUpdate = [];
206+
208207
// Assign unique names across all modules
209208
for (let m of this.modules.values()) {
210209
for (let [orig, name] of m.names) {
211210
if (exportedNames.has(name) && exportedNames.get(name) === m) {
212211
continue;
213212
}
214213

215-
if (!m.used.has(orig) || m.imports.get(orig)) {
214+
if (!m.used.has(orig)) {
215+
continue;
216+
}
217+
218+
if (m.imports.has(orig)) {
219+
// Update imports after all modules's local variables have been renamed
220+
importedSymbolsToUpdate.push([m, orig]);
216221
continue;
217222
}
218223

@@ -224,6 +229,11 @@ export class TSModuleGraph {
224229
}
225230
}
226231

232+
for (let [m, orig] of importedSymbolsToUpdate) {
233+
let imported = nullthrows(this.resolveImport(m, orig));
234+
m.names.set(orig, imported.imported);
235+
}
236+
227237
return exportedNames;
228238
}
229239
}

packages/transformers/typescript-types/src/TSTypesTransformer.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import {Transformer} from '@parcel/plugin';
44
import path from 'path';
55
import SourceMap from '@parcel/source-map';
66
import type {DiagnosticCodeFrame} from '@parcel/diagnostic';
7-
87
import type {CompilerOptions} from 'typescript';
8+
99
import ts from 'typescript';
1010
import {CompilerHost, loadTSConfig} from '@parcel/ts-utils';
1111
import {escapeMarkdown} from '@parcel/diagnostic';
@@ -52,17 +52,17 @@ export default (new Transformer({
5252
let mainModuleName = path
5353
.relative(program.getCommonSourceDirectory(), asset.filePath)
5454
.slice(0, -path.extname(asset.filePath).length);
55-
let moduleGraph = new TSModuleGraph(ts, mainModuleName);
55+
let moduleGraph = new TSModuleGraph(mainModuleName);
5656

5757
let emitResult = program.emit(undefined, undefined, undefined, true, {
5858
afterDeclarations: [
5959
// 1. Build module graph
6060
context => sourceFile => {
61-
return collect(ts, moduleGraph, context, sourceFile);
61+
return collect(moduleGraph, context, sourceFile);
6262
},
6363
// 2. Tree shake and rename types
6464
context => sourceFile => {
65-
return shake(ts, moduleGraph, context, sourceFile);
65+
return shake(moduleGraph, context, sourceFile);
6666
},
6767
],
6868
});

packages/transformers/typescript-types/src/collect.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// @flow
2+
import type {TSModuleGraph} from './TSModuleGraph';
3+
24
import nullthrows from 'nullthrows';
5+
import ts from 'typescript';
36
import {TSModule} from './TSModule';
4-
import type {TSModuleGraph} from './TSModuleGraph';
5-
import typeof TypeScriptModule from 'typescript'; // eslint-disable-line import/no-extraneous-dependencies
67
import {getExportedName, isDeclaration} from './utils';
78

89
export function collect(
9-
ts: TypeScriptModule,
1010
moduleGraph: TSModuleGraph,
1111
context: any,
1212
sourceFile: any,

packages/transformers/typescript-types/src/shake.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// @flow
22
import {TSModule} from './TSModule';
33
import type {TSModuleGraph} from './TSModuleGraph';
4-
import typeof TypeScriptModule from 'typescript'; // eslint-disable-line import/no-extraneous-dependencies
5-
import {getExportedName, isDeclaration} from './utils';
4+
5+
import ts from 'typescript';
66
import nullthrows from 'nullthrows';
7+
import {getExportedName, isDeclaration} from './utils';
78

89
export function shake(
9-
ts: TypeScriptModule,
1010
moduleGraph: TSModuleGraph,
1111
context: any,
1212
sourceFile: any,
@@ -32,7 +32,7 @@ export function shake(
3232
let statements = ts.visitEachChild(node, visit, context).body.statements;
3333

3434
if (isFirstModule) {
35-
statements.unshift(...generateImports(ts, moduleGraph));
35+
statements.unshift(...generateImports(moduleGraph));
3636
}
3737

3838
return statements;
@@ -207,7 +207,7 @@ export function shake(
207207
return ts.visitNode(sourceFile, visit);
208208
}
209209

210-
function generateImports(ts: TypeScriptModule, moduleGraph: TSModuleGraph) {
210+
function generateImports(moduleGraph: TSModuleGraph) {
211211
let importStatements = [];
212212
for (let [specifier, names] of moduleGraph.getAllImports()) {
213213
let defaultSpecifier;

0 commit comments

Comments
 (0)