Skip to content

Commit 58b1a8b

Browse files
committed
prefix external runtime type names with __ɵΩ
so that external type names don't clash with user defined type names when inlined
1 parent fa184dd commit 58b1a8b

File tree

2 files changed

+87
-40
lines changed

2 files changed

+87
-40
lines changed

packages/type-compiler/src/compiler.ts

+44-19
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,8 @@ export class ReflectionTransformer implements CustomTransformer {
536536
protected reflectionMode?: typeof reflectionModes[number];
537537
protected reflectionOptions?: ReflectionOptions;
538538

539+
protected isMaybeEmbeddingExternalLibraryImport: boolean = false;
540+
539541
/**
540542
* Types added to this map will get a type program directly under it.
541543
* This is for types used in the very same file.
@@ -545,6 +547,8 @@ export class ReflectionTransformer implements CustomTransformer {
545547
{ name: EntityName, sourceFile: SourceFile, compiled?: Statement[] }
546548
>();
547549

550+
protected externalRuntimeTypeNames = new Set<string>();
551+
548552
/**
549553
* Types added to this map will get a type program at the top root level of the program.
550554
* This is for imported types, which need to be inlined into the current file, as we do not emit type imports (TS will omit them).
@@ -1808,7 +1812,7 @@ export class ReflectionTransformer implements CustomTransformer {
18081812
if (isIdentifier(narrowed.exprName)) {
18091813
const resolved = this.resolveDeclaration(narrowed.exprName);
18101814
if (resolved && findSourceFile(resolved.declaration) !== this.sourceFile && resolved.importDeclaration) {
1811-
expression = this.resolveImport(resolved.declaration, resolved.importDeclaration, narrowed.exprName, expression, program);
1815+
expression = this.resolveImportExpression(resolved.declaration, resolved.importDeclaration, narrowed.exprName, expression, program);
18121816
}
18131817
}
18141818
program.pushOp(ReflectionOp.typeof, program.pushStack(this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, expression)));
@@ -2005,44 +2009,67 @@ export class ReflectionTransformer implements CustomTransformer {
20052009
// return node;
20062010
// }
20072011

2008-
public getDeclarationVariableName(typeName: EntityName): Identifier {
2012+
protected getRuntimeTypeName(typeName: string): string {
2013+
if (this.externalRuntimeTypeNames.has(typeName)) {
2014+
return `__ɵΩ${typeName}`;
2015+
}
2016+
return `__Ω${typeName}`;
2017+
}
2018+
2019+
protected getDeclarationVariableName(typeName: EntityName): Identifier {
20092020
if (isIdentifier(typeName)) {
2010-
return this.f.createIdentifier('__Ω' + getIdentifierName(typeName));
2021+
return this.f.createIdentifier(this.getRuntimeTypeName(getIdentifierName(typeName)));
20112022
}
20122023

20132024
function joinQualifiedName(name: EntityName): string {
20142025
if (isIdentifier(name)) return getIdentifierName(name);
20152026
return joinQualifiedName(name.left) + '_' + getIdentifierName(name.right);
20162027
}
20172028

2018-
return this.f.createIdentifier('__Ω' + joinQualifiedName(typeName));
2029+
return this.f.createIdentifier(this.getRuntimeTypeName(joinQualifiedName(typeName)));
20192030
}
20202031

2021-
protected resolveImport<T extends Expression>(declaration: Node, importDeclaration: ImportDeclaration, typeName: Identifier, expression: T, program: CompilerProgram): CallExpression | T {
2032+
protected addExternalLibraryImportEmbedDeclaration(declaration: Node, sourceFile: SourceFile, typeName: EntityName): void {
2033+
this.isMaybeEmbeddingExternalLibraryImport = true;
2034+
2035+
this.externalRuntimeTypeNames.add(getEntityName(typeName));
2036+
2037+
this.embedDeclarations.set(declaration, {
2038+
name: typeName,
2039+
sourceFile,
2040+
});
2041+
}
2042+
2043+
protected resolveImportExpression<T extends Expression>(declaration: Node, importDeclaration: ImportDeclaration, typeName: Identifier, expression: T, program: CompilerProgram): CallExpression | T {
20222044
ensureImportIsEmitted(importDeclaration, typeName);
20232045

2024-
if (isTypeAliasDeclaration(declaration)) return expression;
2046+
if (isTypeAliasDeclaration(declaration)) {
2047+
this.isMaybeEmbeddingExternalLibraryImport = false;
2048+
return expression;
2049+
}
20252050

20262051
// check if the referenced declaration has reflection disabled
20272052
const declarationReflection = this.findReflectionConfig(declaration, program);
20282053
if (declarationReflection.mode !== 'never') {
20292054
const declarationSourceFile = importDeclaration.getSourceFile();
20302055

2056+
if (this.isMaybeEmbeddingExternalLibraryImport) {
2057+
this.addExternalLibraryImportEmbedDeclaration(declaration, declarationSourceFile, typeName);
2058+
return this.wrapWithAssignType(expression, this.getDeclarationVariableName(typeName));
2059+
}
2060+
20312061
const runtimeTypeName = this.getDeclarationVariableName(typeName);
20322062

20332063
const builtType = isBuiltType(runtimeTypeName, declarationSourceFile);
20342064

20352065
if (!builtType && this.shouldInlineExternalLibraryImport(importDeclaration, typeName, declarationReflection)) {
2036-
this.embedDeclarations.set(declaration, {
2037-
name: typeName,
2038-
sourceFile: declarationSourceFile,
2039-
});
2040-
// if (!isTypeAliasDeclaration(declaration)) {
2041-
return this.wrapWithAssignType(expression, runtimeTypeName);
2042-
// }
2066+
this.addExternalLibraryImportEmbedDeclaration(declaration, declarationSourceFile, typeName);
2067+
return this.wrapWithAssignType(expression, this.getDeclarationVariableName(typeName));
20432068
}
20442069
}
20452070

2071+
this.isMaybeEmbeddingExternalLibraryImport = false;
2072+
20462073
return expression;
20472074
}
20482075

@@ -2166,7 +2193,7 @@ export class ReflectionTransformer implements CustomTransformer {
21662193
if (isModuleDeclaration(declaration) && resolved.importDeclaration) {
21672194
let expression: SerializedEntityNameAsExpression | CallExpression = serializeEntityNameAsExpression(this.f, typeName);
21682195
if (isIdentifier(typeName)) {
2169-
expression = this.resolveImport(declaration, resolved.importDeclaration, typeName, expression, program)
2196+
expression = this.resolveImportExpression(declaration, resolved.importDeclaration, typeName, expression, program)
21702197
}
21712198

21722199
//we can not infer from module declaration, so do `typeof T` in runtime
@@ -2257,11 +2284,9 @@ export class ReflectionTransformer implements CustomTransformer {
22572284
const builtType = isBuiltType(runtimeTypeName, found);
22582285
if (!builtType) {
22592286
if (!this.shouldInlineExternalLibraryImport(resolved.importDeclaration, typeName, declarationReflection)) return;
2260-
this.embedDeclarations.set(declaration, {
2261-
name: typeName,
2262-
sourceFile: declarationSourceFile
2263-
});
2287+
this.addExternalLibraryImportEmbedDeclaration(declaration, declarationSourceFile, typeName);
22642288
} else {
2289+
this.isMaybeEmbeddingExternalLibraryImport = false;
22652290
//check if the referenced file has reflection info emitted. if not, any is emitted for that reference
22662291
const reflection = this.findReflectionFromPath(found.fileName);
22672292
if (reflection.mode === 'never') {
@@ -2323,7 +2348,7 @@ export class ReflectionTransformer implements CustomTransformer {
23232348

23242349
let body: Identifier | PropertyAccessExpression | CallExpression = isIdentifier(typeName) ? typeName : this.createAccessorForEntityName(typeName);
23252350
if (resolved.importDeclaration && isIdentifier(typeName)) {
2326-
body = this.resolveImport(resolved.declaration, resolved.importDeclaration, typeName, body, program);
2351+
body = this.resolveImportExpression(resolved.declaration, resolved.importDeclaration, typeName, body, program);
23272352
}
23282353
program.pushFrame();
23292354
if (type.typeArguments) {

packages/type-compiler/tests/inline-external-imports.spec.ts

+43-21
Original file line numberDiff line numberDiff line change
@@ -300,25 +300,26 @@ test('class type var', () => {
300300
},
301301
});
302302

303-
// TODO: how to resolve the typeof imports? -> __assignType(Subscriber_1.Subscriber, __ΩSubscriber)
304-
// "use strict";
305-
// Object.defineProperty(exports, "__esModule", { value: true });
306-
// exports.__ΩUnsubscribable = exports.__ΩSubscribable = exports.__ΩSubscription = exports.__ΩObserver = exports.__ΩTeardownLogic = exports.__ΩSubscriber = exports.__ΩOperator = exports.__ΩObservable = void 0;
307-
// const __ΩObservable = ['T', () => Observable, 'source', () => __ΩOperator, 'operator', () => Observable, 'this', () => __assignType(Subscriber_1.Subscriber, __ΩSubscriber), 'subscriber', () => __ΩTeardownLogic, '', 'subscribe', 'constructor', 'args', 'create', () => __ΩOperator, () => Observable, 'lift', () => __ΩPartial, () => __ΩObserver, 'observer', () => __assignType(Subscription_1.Subscription, __ΩSubscription), 'value', 'next', 'forEach', () => Observable, 'pipe', 'toPromise', () => __ΩSubscribable, 'Observable', 'b!PP"7"-J3#P"e"!o$#-J3%PPPe$!7&2\'Pe$!7(2)n*/+2,8"0-P"@2."/+3/sPe"!"o0#2%8P"7102Pe"!o4"o3"258P760,PPe#!27$/+28$`09PPe#!7:0;PPe#!-J`0<5e!!o="x"w>y'];
308-
// exports.__ΩObservable = __ΩObservable;
309-
// const __ΩOperator = ['T', 'R', () => Subscriber_2.Subscriber, 'subscriber', 'source', () => __ΩTeardownLogic, 'call', 'b!b"PPPe$"7#2$"2%n&1\'My'];
310-
// exports.__ΩOperator = __ΩOperator;
311-
// const __ΩSubscriber = ['T', () => Subscription_2.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => Subscriber, 'create', 'isStopped', () => Subscriber, () => __ΩObserver, 'destination', () => Subscriber, () => __ΩObserver, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ΩObserver, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\'8P$/$2(8Pe#!7)0*s)3+<PP"7,"o-"J3.<PPP"7/"o0"J2.8"01Pe"!228$0%P"238$0\'P$0(P$04Pe"!22$05<P"23$06<P$07<5e!!o8"x"w9y'];
312-
// exports.__ΩSubscriber = __ΩSubscriber;
313-
// const __ΩTeardownLogic = [() => Subscription_3.Subscription, () => __ΩUnsubscribable, '', 'PP7!n"P$/#$Jy'];
314-
// exports.__ΩTeardownLogic = __ΩTeardownLogic;
303+
console.log(res.app);
304+
305+
// TODO: how to resolve the typeof imports? -> __assignType(Subscriber_1.Subscriber, __ɵΩSubscriber)
306+
//
307+
// exports.__ΩUnsubscribable = exports.__ɵΩSubscribable = exports.__ɵΩSubscription = exports.__ɵΩObserver = exports.__ɵΩTeardownLogic = exports.__ɵΩSubscriber = exports.__ɵΩOperator = exports.__ɵΩObservable = void 0;
308+
// const __ɵΩObservable = ['T', () => Observable, 'source', () => __ΩOperator, 'operator', () => Observable, 'this', () => __assignType(Subscriber_1.Subscriber, __ɵΩSubscriber), 'subscriber', () => __ΩTeardownLogic, '', 'subscribe', 'constructor', 'args', 'create', () => __ɵΩOperator, () => Observable, 'lift', () => __ΩPartial, () => __ΩObserver, 'observer', () => __assignType(Subscription_1.Subscription, __ɵΩSubscription), 'value', 'next', 'forEach', () => Observable, 'pipe', 'toPromise', () => __ΩSubscribable, 'Observable', 'b!PP"7"-J3#P"e"!o$#-J3%PPPe$!7&2\'Pe$!7(2)n*/+2,8"0-P"@2."/+3/sPe"!"o0#2%8P"7102Pe"!o4"o3"258P760,PPe#!27$/+28$`09PPe#!7:0;PPe#!-J`0<5e!!o="x"w>y'];
309+
// exports.__ɵΩObservable = __ɵΩObservable;
310+
// const __ɵΩOperator = ['T', 'R', () => Subscriber_2.Subscriber, 'subscriber', 'source', () => __ɵΩTeardownLogic, 'call', 'b!b"PPPe$"7#2$"2%n&1\'My'];
311+
// exports.__ɵΩOperator = __ɵΩOperator;
312+
// const __ɵΩSubscriber = ['T', () => Subscription_2.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => Subscriber, 'create', 'isStopped', () => Subscriber, () => __ɵΩObserver, 'destination', () => Subscriber, () => __ɵΩObserver, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩObserver, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\'8P$/$2(8Pe#!7)0*s)3+<PP"7,"o-"J3.<PPP"7/"o0"J2.8"01Pe"!228$0%P"238$0\'P$0(P$04Pe"!22$05<P"23$06<P$07<5e!!o8"x"w9y'];
313+
// exports.__ɵΩSubscriber = __ɵΩSubscriber;
314+
// const __ɵΩTeardownLogic = [() => Subscription_3.Subscription, () => __ΩUnsubscribable, '', 'PP7!n"P$/#$Jy'];
315+
// exports.__ɵΩTeardownLogic = __ɵΩTeardownLogic;
315316
// const __ΩPartial = ['T', 'l+e#!e"!fRb!Pde"!gN#"y'];
316-
// const __ΩObserver = ['T', 'value', '', 'next', 'err', 'error', 'complete', 'b!PPe#!2"$/#4$P"2%$/#4&P$/#4\'My'];
317-
// exports.__ΩObserver = __ΩObserver;
318-
// const __ΩSubscription = [() => Subscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ΩTeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ΩTeardownLogic, 'remove', 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\'Pn(2)$0*Pn,$o+#2)$0-5x"w.y'];
319-
// exports.__ΩSubscription = __ΩSubscription;
320-
// const __ΩSubscribable = ['T', () => __ΩPartial, () => __ΩObserver, 'observer', () => __ΩUnsubscribable, 'subscribe', 'b!PPe#!o#"o""2$n%1&My'];
321-
// exports.__ΩSubscribable = __ΩSubscribable;
317+
// const __ɵΩObserver = ['T', 'value', '', 'next', 'err', 'error', 'complete', 'b!PPe#!2"$/#4$P"2%$/#4&P$/#4\'My'];
318+
// exports.__ɵΩObserver = __ɵΩObserver;
319+
// const __ɵΩSubscription = [() => Subscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ɵΩTeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ɵΩTeardownLogic, 'remove', 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\'Pn(2)$0*Pn,$o+#2)$0-5x"w.y'];
320+
// exports.__ɵΩSubscription = __ɵΩSubscription;
321+
// const __ɵΩSubscribable = ['T', () => __ΩPartial, () => __ɵΩObserver, 'observer', () => __ΩUnsubscribable, 'subscribe', 'b!PPe#!o#"o""2$n%1&My'];
322+
// exports.__ɵΩSubscribable = __ɵΩSubscribable;
322323
// const __ΩUnsubscribable = ['unsubscribe', 'PP$1!My'];
323324
// exports.__ΩUnsubscribable = __ΩUnsubscribable;
324325
// const __ΩExclude = ['T', 'U', 'l6!Re$!RPe#!e$"qk#%QRb!b"Pde"!p)y'];
@@ -327,11 +328,32 @@ test('class type var', () => {
327328
// return fn;
328329
// }
329330
// const rxjs_1 = require("rxjs");
330-
// const __ΩA = [() => __assignType(rxjs_1.Observable, __ΩObservable), 'P#7!y'];
331+
// const __ΩA = [() => __assignType(rxjs_1.Observable, __ɵΩObservable), 'P#7!y'];
331332

332-
expect(res.app).toContain('const __ΩObservable = [');
333-
expect(res.app).toContain('() => __assignType(rxjs_1.Observable, __ΩObservable)');
333+
expect(res.app).toContain('const __ɵΩObservable = [');
334+
expect(res.app).toContain('() => __assignType(rxjs_1.Observable, __ɵΩObservable)');
335+
// FIXME: why isn't it being prefixed with `ɵ`?
336+
expect(res.app).toContain('const __ɵΩUnsubscribable = [');
334337
})
338+
339+
test('runtime type name clashing', () => {
340+
const res = transpile({
341+
app: `import { Observable } from 'rxjs';
342+
343+
type Subscribable = any;
344+
345+
type A = Observable<unknown>;
346+
`
347+
}, undefined, {
348+
inlineExternalLibraryImports: {
349+
'rxjs': ['Observable'],
350+
},
351+
});
352+
353+
expect(res.app).toContain('const __ɵΩSubscribable = [');
354+
expect(res.app).toContain('const __ΩSubscribable = [');
355+
})
356+
335357
test('class typeOf', () => {
336358
const res = transpileAndRun({
337359
app: `import { Observable } from 'rxjs';

0 commit comments

Comments
 (0)