Skip to content

Commit

Permalink
Fix; V2.0.4
Browse files Browse the repository at this point in the history
  • Loading branch information
shrinktofit committed Oct 29, 2020
1 parent c0571c9 commit f9cc0ee
Show file tree
Hide file tree
Showing 12 changed files with 25,875 additions and 23,698 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"args": [
"--input",
"./test/declarations/cc-before-rollup.d.ts",
"./test/declarations/module-cc.d.ts",
"./test/declarations/virtual-cc.d.ts",
"--root-dir=./test/declarations",
"--root",
"index",
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tfig",
"version": "2.0.2",
"version": "2.0.4",
"description": "Yet another tool to generate .d.ts bundle.",
"main": "build/gift.js",
"types": "build/gift.d.ts",
Expand Down
16 changes: 15 additions & 1 deletion source/gift.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,22 @@ export function rollupTypes(options: IOptions) {
return rModule;
});

const visitModules = (
moduleMeta: distributeExports.ModuleMeta,
fx: (moduleMeta: distributeExports.ModuleMeta) => void,
) => {
fx(moduleMeta);
for (const mainExport of moduleMeta.mainExports) {
if (mainExport.children) {
for (const child of mainExport.children) {
visitModules(child, fx);
}
}
}
};

for (const distribution of exportDistribution) {
addAliasExports(distribution);
visitModules(distribution, addAliasExports);
}

const nameResolver = new NameResolver();
Expand Down
109 changes: 62 additions & 47 deletions source/module-interop.ts
Original file line number Diff line number Diff line change
@@ -1,67 +1,94 @@

import ts from 'typescript';
import { Entity } from './r-concepts';

export class ModuleInteropRecord {
constructor(name: string) {
this._myName = name;
constructor(entity: Entity) {
this._entity = entity;
}

get record(): Readonly<ModuleInteropRecord['_record']> {
get record() {
return this._record;
}

get selfExports() {
return this._selfExports;
}

public addNamedImport(from: string, importName: string, exportName: string) {
/**
* @param from
* @param importName
* @param asName
*/
public addNamedImport(from: string, importName: string, asName?: string): string {
const interop = this._getInterop(from);
const isImportExportNameSame = importName === exportName;
for (const { propertyName, name } of interop.imports) {
if (isImportExportNameSame) {
if (name.text === importName) {
return;
}
if (!asName) {
const sameImport = interop.imports.find(
(namedImportRecord) => namedImportRecord.importName === importName);
if (sameImport) {
return sameImport.asName;
} else {
if (propertyName && propertyName.text === importName &&
name.text === exportName) {
return;
}
asName = this._generateUniqueImportName(importName);
}
}
interop.imports.push(isImportExportNameSame ?
ts.createImportSpecifier(undefined, ts.createIdentifier(importName)):
ts.createImportSpecifier(ts.createIdentifier(exportName), ts.createIdentifier(importName)),
);
if (!interop.imports.some(
(namedImportRecord) => namedImportRecord.asName === asName && namedImportRecord.importName === importName)) {
interop.imports.push({ importName, asName });
}
return asName;
}

public addNamedExportFrom(from: string, importName: string, exportName: string) {
public addNamedExportFrom(from: string, importName: string, asName: string) {
const interop = this._getInterop(from);
const isImportExportNameSame = importName === exportName;
if (!interop.exports.some((specifier) => this._isEqualExportSpecifier(specifier, importName, exportName))) {
interop.exports.push(isImportExportNameSame ?
ts.createExportSpecifier(undefined, ts.createIdentifier(importName)):
ts.createExportSpecifier(ts.createIdentifier(exportName), ts.createIdentifier(importName)),
);
if (!interop.exports.some(
(namedExportRecord) => namedExportRecord.asName === asName && namedExportRecord.importName === importName)) {
interop.exports.push({ importName, asName });
}
}

public addNamedExport(localName: string, exportName: string) {
if (!this._selfExports.some((specifier) => this._isEqualExportSpecifier(specifier, localName, exportName))) {
this._selfExports.push((localName === exportName) ?
ts.createExportSpecifier(undefined, ts.createIdentifier(localName)):
ts.createExportSpecifier(ts.createIdentifier(exportName), ts.createIdentifier(localName)),
);
public addNamedExport(importName: string, asName: string) {
if (!this._selfExports.some(
(namedExportRecord) => namedExportRecord.asName === asName && namedExportRecord.importName === importName)) {
this._selfExports.push({ importName, asName });
}
}

private _myName: string;
private _selfExports: ts.ExportSpecifier[] = [];
private _entity: Entity;
private _selfExports: { asName: string, importName: string }[] = [];
private _record: Map<string, {
specifier: string;
imports: ts.ImportSpecifier[];
exports: ts.ExportSpecifier[];
imports: { asName: string, importName: string }[];
exports: { asName: string, importName: string }[];
}> = new Map();
private _interopNames = new Set<string>();

private _generateUniqueImportName(preferredName: string) {
let tryingName = preferredName;
while (tryingName === '__private' || this._hasName(tryingName)) {
tryingName = `_${tryingName}`;
}
return tryingName;
}

private _hasName(name: string) {
return this._entity.namespaceTraits!.children.some((childEntity) => childEntity.name === name) ||
this._hasNameInInterop(name);
}

private _hasNameInInterop(name: string) {
for (const [, {imports, exports}] of this._record) {
if (imports.some(({asName}) => asName === name)) {
return true;
}
if (exports.some(({asName}) => asName === name)) {
return true;
}
}
if (this._selfExports.some(({asName}) => asName === name)) {
return true;
}
return false;
}

private _getInterop(from: string) {
let interop = this._record.get(from);
Expand All @@ -80,16 +107,4 @@ export class ModuleInteropRecord {
private _optimizeModuleSpecifierTo(to: string): string {
return to;
}

private _isEqualExportSpecifier(
specifier: ts.ExportSpecifier, localOrImportName: string, exportName: string) {
if (specifier.name.text !== localOrImportName) {
return false;
}
if (localOrImportName === exportName) {
return !specifier.propertyName || specifier.propertyName.text === exportName;
} else {
return specifier.propertyName && specifier.propertyName.text === exportName;
}
}
}
6 changes: 4 additions & 2 deletions source/name-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class NameResolver {

export namespace NameResolver {
export interface ResolveResult {
module?: string;
module?: rConcepts.Entity;
namespaces?: string[];
name: string;
}
Expand Down Expand Up @@ -66,6 +66,8 @@ export function resolveRelativePath(from: rConcepts.NamespaceTraits, to: rConcep
// However the 'A' may also has a (nested) namespace named "a.b....".
// So the conflict occurs.
// In such case, we have to prefer the longest path to avoid conflict.
// Known issue: when resolve "A B ..." from "A C ..."
// And C has member named B, the result is wrong.
let iNoConflict = iUnmatchedNamespace;
if (iNoConflict < toFullPath.length) {
while (iNoConflict > 0) {
Expand All @@ -80,7 +82,7 @@ export function resolveRelativePath(from: rConcepts.NamespaceTraits, to: rConcep

if (iNoConflict === 0) {
// Module mismatch
result.module = toFullPath[0].name;
result.module = toFullPath[0];
++iNoConflict;
}

Expand Down
Loading

0 comments on commit f9cc0ee

Please sign in to comment.