feat(compiler): generate type parameters for generic type references (#14104)
This commit is contained in:
parent
1079b9381c
commit
69e14b500b
|
@ -77,7 +77,8 @@ export function createAotCompiler(compilerHost: AotCompilerHost, options: AotCom
|
||||||
const importResolver = {
|
const importResolver = {
|
||||||
getImportAs: (symbol: StaticSymbol) => symbolResolver.getImportAs(symbol),
|
getImportAs: (symbol: StaticSymbol) => symbolResolver.getImportAs(symbol),
|
||||||
fileNameToModuleName: (fileName: string, containingFilePath: string) =>
|
fileNameToModuleName: (fileName: string, containingFilePath: string) =>
|
||||||
compilerHost.fileNameToModuleName(fileName, containingFilePath)
|
compilerHost.fileNameToModuleName(fileName, containingFilePath),
|
||||||
|
getTypeArity: (symbol: StaticSymbol) => symbolResolver.getTypeArity(symbol)
|
||||||
};
|
};
|
||||||
const compiler = new AotCompiler(
|
const compiler = new AotCompiler(
|
||||||
compilerHost, resolver, tmplParser, new StyleCompiler(urlResolver),
|
compilerHost, resolver, tmplParser, new StyleCompiler(urlResolver),
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {SummaryResolver} from '../summary_resolver';
|
||||||
import {ValueTransformer, visitValue} from '../util';
|
import {ValueTransformer, visitValue} from '../util';
|
||||||
|
|
||||||
import {StaticSymbol, StaticSymbolCache} from './static_symbol';
|
import {StaticSymbol, StaticSymbolCache} from './static_symbol';
|
||||||
|
import {isNgFactoryFile} from './util';
|
||||||
|
|
||||||
export class ResolvedStaticSymbol {
|
export class ResolvedStaticSymbol {
|
||||||
constructor(public symbol: StaticSymbol, public metadata: any) {}
|
constructor(public symbol: StaticSymbol, public metadata: any) {}
|
||||||
|
@ -83,6 +84,15 @@ export class StaticSymbolResolver {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getImportAs produces a symbol that can be used to import the given symbol.
|
||||||
|
* The import might be different than the symbol if the symbol is exported from
|
||||||
|
* a library with a summary; in which case we want to import the symbol from the
|
||||||
|
* ngfactory re-export instead of directly to avoid introducing a direct dependency
|
||||||
|
* on an otherwise indirect dependency.
|
||||||
|
*
|
||||||
|
* @param staticSymbol the symbol for which to generate a import symbol
|
||||||
|
*/
|
||||||
getImportAs(staticSymbol: StaticSymbol): StaticSymbol {
|
getImportAs(staticSymbol: StaticSymbol): StaticSymbol {
|
||||||
if (staticSymbol.members.length) {
|
if (staticSymbol.members.length) {
|
||||||
const baseSymbol = this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name);
|
const baseSymbol = this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name);
|
||||||
|
@ -98,6 +108,25 @@ export class StaticSymbolResolver {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getTypeArity returns the number of generic type parameters the given symbol
|
||||||
|
* has. If the symbol is not a type the result is null.
|
||||||
|
*/
|
||||||
|
getTypeArity(staticSymbol: StaticSymbol): number /*|null*/ {
|
||||||
|
// If the file is a factory file, don't resolve the symbol as doing so would
|
||||||
|
// cause the metadata for an factory file to be loaded which doesn't exist.
|
||||||
|
// All references to generated classes must include the correct arity whenever
|
||||||
|
// generating code.
|
||||||
|
if (isNgFactoryFile(staticSymbol.filePath)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
let resolvedSymbol = this.resolveSymbol(staticSymbol);
|
||||||
|
while (resolvedSymbol && resolvedSymbol.metadata instanceof StaticSymbol) {
|
||||||
|
resolvedSymbol = this.resolveSymbol(resolvedSymbol.metadata);
|
||||||
|
}
|
||||||
|
return (resolvedSymbol && resolvedSymbol.metadata && resolvedSymbol.metadata.arity) || null;
|
||||||
|
}
|
||||||
|
|
||||||
private _resolveSymbolMembers(staticSymbol: StaticSymbol): ResolvedStaticSymbol {
|
private _resolveSymbolMembers(staticSymbol: StaticSymbol): ResolvedStaticSymbol {
|
||||||
const members = staticSymbol.members;
|
const members = staticSymbol.members;
|
||||||
const baseResolvedSymbol =
|
const baseResolvedSymbol =
|
||||||
|
@ -134,6 +163,7 @@ export class StaticSymbolResolver {
|
||||||
*
|
*
|
||||||
* @param declarationFile the absolute path of the file where the symbol is declared
|
* @param declarationFile the absolute path of the file where the symbol is declared
|
||||||
* @param name the name of the type.
|
* @param name the name of the type.
|
||||||
|
* @param members a symbol for a static member of the named type
|
||||||
*/
|
*/
|
||||||
getStaticSymbol(declarationFile: string, name: string, members?: string[]): StaticSymbol {
|
getStaticSymbol(declarationFile: string, name: string, members?: string[]): StaticSymbol {
|
||||||
return this.staticSymbolCache.get(declarationFile, name, members);
|
return this.staticSymbolCache.get(declarationFile, name, members);
|
||||||
|
|
|
@ -94,10 +94,10 @@ class Serializer extends ValueTransformer {
|
||||||
addOrMergeSummary(summary: Summary<StaticSymbol>) {
|
addOrMergeSummary(summary: Summary<StaticSymbol>) {
|
||||||
let symbolMeta = summary.metadata;
|
let symbolMeta = summary.metadata;
|
||||||
if (symbolMeta && symbolMeta.__symbolic === 'class') {
|
if (symbolMeta && symbolMeta.__symbolic === 'class') {
|
||||||
// For classes, we only keep their statics, but not the metadata
|
// For classes, we only keep their statics and arity, but not the metadata
|
||||||
// of the class itself as that has been captured already via other summaries
|
// of the class itself as that has been captured already via other summaries
|
||||||
// (e.g. DirectiveSummary, ...).
|
// (e.g. DirectiveSummary, ...).
|
||||||
symbolMeta = {__symbolic: 'class', statics: symbolMeta.statics};
|
symbolMeta = {__symbolic: 'class', statics: symbolMeta.statics, arity: symbolMeta.arity};
|
||||||
}
|
}
|
||||||
|
|
||||||
let processedSummary = this.processedSummaryBySymbol.get(summary.symbol);
|
let processedSummary = this.processedSummaryBySymbol.get(summary.symbol);
|
||||||
|
@ -106,11 +106,11 @@ class Serializer extends ValueTransformer {
|
||||||
this.processedSummaries.push(processedSummary);
|
this.processedSummaries.push(processedSummary);
|
||||||
this.processedSummaryBySymbol.set(summary.symbol, processedSummary);
|
this.processedSummaryBySymbol.set(summary.symbol, processedSummary);
|
||||||
}
|
}
|
||||||
// Note: == by purpose to compare with undefined!
|
// Note: == on purpose to compare with undefined!
|
||||||
if (processedSummary.metadata == null && symbolMeta != null) {
|
if (processedSummary.metadata == null && symbolMeta != null) {
|
||||||
processedSummary.metadata = this.processValue(symbolMeta);
|
processedSummary.metadata = this.processValue(symbolMeta);
|
||||||
}
|
}
|
||||||
// Note: == by purpose to compare with undefined!
|
// Note: == on purpose to compare with undefined!
|
||||||
if (processedSummary.type == null && summary.type != null) {
|
if (processedSummary.type == null && summary.type != null) {
|
||||||
processedSummary.type = this.processValue(summary.type);
|
processedSummary.type = this.processValue(summary.type);
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ class Serializer extends ValueTransformer {
|
||||||
if (value instanceof StaticSymbol) {
|
if (value instanceof StaticSymbol) {
|
||||||
const baseSymbol = this.symbolResolver.getStaticSymbol(value.filePath, value.name);
|
const baseSymbol = this.symbolResolver.getStaticSymbol(value.filePath, value.name);
|
||||||
let index = this.indexBySymbol.get(baseSymbol);
|
let index = this.indexBySymbol.get(baseSymbol);
|
||||||
// Note: == by purpose to compare with undefined!
|
// Note: == on purpose to compare with undefined!
|
||||||
if (index == null) {
|
if (index == null) {
|
||||||
index = this.indexBySymbol.size;
|
index = this.indexBySymbol.size;
|
||||||
this.indexBySymbol.set(baseSymbol, index);
|
this.indexBySymbol.set(baseSymbol, index);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const STRIP_SRC_FILE_SUFFIXES = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
const STRIP_SRC_FILE_SUFFIXES = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
||||||
|
const NG_FACTORY = /\.ngfactory\./;
|
||||||
|
|
||||||
export function ngfactoryFilePath(filePath: string): string {
|
export function ngfactoryFilePath(filePath: string): string {
|
||||||
const urlWithSuffix = splitTypescriptSuffix(filePath);
|
const urlWithSuffix = splitTypescriptSuffix(filePath);
|
||||||
|
@ -14,7 +15,11 @@ export function ngfactoryFilePath(filePath: string): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function stripNgFactory(filePath: string): string {
|
export function stripNgFactory(filePath: string): string {
|
||||||
return filePath.replace(/\.ngfactory\./, '.');
|
return filePath.replace(NG_FACTORY, '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isNgFactoryFile(filePath: string): boolean {
|
||||||
|
return NG_FACTORY.test(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function splitTypescriptSuffix(path: string): string[] {
|
export function splitTypescriptSuffix(path: string): string[] {
|
||||||
|
|
|
@ -44,11 +44,7 @@ export class BuiltinType extends Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ExpressionType extends Type {
|
export class ExpressionType extends Type {
|
||||||
constructor(
|
constructor(public value: Expression, modifiers: TypeModifier[] = null) { super(modifiers); }
|
||||||
public value: Expression, public typeParams: Type[] = null,
|
|
||||||
modifiers: TypeModifier[] = null) {
|
|
||||||
super(modifiers);
|
|
||||||
}
|
|
||||||
visitType(visitor: TypeVisitor, context: any): any {
|
visitType(visitor: TypeVisitor, context: any): any {
|
||||||
return visitor.visitExpressionType(this, context);
|
return visitor.visitExpressionType(this, context);
|
||||||
}
|
}
|
||||||
|
@ -881,13 +877,12 @@ export function importExpr(id: CompileIdentifierMetadata, typeParams: Type[] = n
|
||||||
export function importType(
|
export function importType(
|
||||||
id: CompileIdentifierMetadata, typeParams: Type[] = null,
|
id: CompileIdentifierMetadata, typeParams: Type[] = null,
|
||||||
typeModifiers: TypeModifier[] = null): ExpressionType {
|
typeModifiers: TypeModifier[] = null): ExpressionType {
|
||||||
return isPresent(id) ? expressionType(importExpr(id), typeParams, typeModifiers) : null;
|
return isPresent(id) ? expressionType(importExpr(id, typeParams), typeModifiers) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function expressionType(
|
export function expressionType(
|
||||||
expr: Expression, typeParams: Type[] = null,
|
expr: Expression, typeModifiers: TypeModifier[] = null): ExpressionType {
|
||||||
typeModifiers: TypeModifier[] = null): ExpressionType {
|
return isPresent(expr) ? new ExpressionType(expr, typeModifiers) : null;
|
||||||
return isPresent(expr) ? new ExpressionType(expr, typeParams, typeModifiers) : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function literalArr(values: Expression[], type: Type = null): LiteralArrayExpr {
|
export function literalArr(values: Expression[], type: Type = null): LiteralArrayExpr {
|
||||||
|
|
|
@ -24,4 +24,9 @@ export abstract class ImportResolver {
|
||||||
* to generate the import from.
|
* to generate the import from.
|
||||||
*/
|
*/
|
||||||
abstract getImportAs(symbol: StaticSymbol): StaticSymbol /*|null*/;
|
abstract getImportAs(symbol: StaticSymbol): StaticSymbol /*|null*/;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the airty of a type.
|
||||||
|
*/
|
||||||
|
abstract getTypeArity(symbol: StaticSymbol): number /*|null*/;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,8 @@ export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.T
|
||||||
string {
|
string {
|
||||||
const converter = new _TsEmitterVisitor(_debugFilePath, {
|
const converter = new _TsEmitterVisitor(_debugFilePath, {
|
||||||
fileNameToModuleName(filePath: string, containingFilePath: string) { return filePath; },
|
fileNameToModuleName(filePath: string, containingFilePath: string) { return filePath; },
|
||||||
getImportAs(symbol: StaticSymbol) { return null; }
|
getImportAs(symbol: StaticSymbol) { return null; },
|
||||||
|
getTypeArity: symbol => null
|
||||||
});
|
});
|
||||||
const ctx = EmitterVisitorContext.createRoot([]);
|
const ctx = EmitterVisitorContext.createRoot([]);
|
||||||
const asts: any[] = Array.isArray(ast) ? ast : [ast];
|
const asts: any[] = Array.isArray(ast) ? ast : [ast];
|
||||||
|
@ -65,6 +66,8 @@ export class TypeScriptEmitter implements OutputEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor {
|
class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor {
|
||||||
|
private typeExpression = 0;
|
||||||
|
|
||||||
constructor(private _genFilePath: string, private _importResolver: ImportResolver) {
|
constructor(private _genFilePath: string, private _importResolver: ImportResolver) {
|
||||||
super(false);
|
super(false);
|
||||||
}
|
}
|
||||||
|
@ -74,7 +77,9 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
||||||
|
|
||||||
visitType(t: o.Type, ctx: EmitterVisitorContext, defaultType: string = 'any') {
|
visitType(t: o.Type, ctx: EmitterVisitorContext, defaultType: string = 'any') {
|
||||||
if (isPresent(t)) {
|
if (isPresent(t)) {
|
||||||
|
this.typeExpression++;
|
||||||
t.visitType(this, ctx);
|
t.visitType(this, ctx);
|
||||||
|
this.typeExpression--;
|
||||||
} else {
|
} else {
|
||||||
ctx.print(defaultType);
|
ctx.print(defaultType);
|
||||||
}
|
}
|
||||||
|
@ -149,6 +154,17 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
visitInstantiateExpr(ast: o.InstantiateExpr, ctx: EmitterVisitorContext): any {
|
||||||
|
ctx.print(`new `);
|
||||||
|
this.typeExpression++;
|
||||||
|
ast.classExpr.visitExpression(this, ctx);
|
||||||
|
this.typeExpression--;
|
||||||
|
ctx.print(`(`);
|
||||||
|
this.visitAllExpressions(ast.args, ctx, ',');
|
||||||
|
ctx.print(`)`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any {
|
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any {
|
||||||
ctx.pushClass(stmt);
|
ctx.pushClass(stmt);
|
||||||
if (ctx.isExportedVar(stmt.name)) {
|
if (ctx.isExportedVar(stmt.name)) {
|
||||||
|
@ -157,7 +173,9 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
||||||
ctx.print(`class ${stmt.name}`);
|
ctx.print(`class ${stmt.name}`);
|
||||||
if (isPresent(stmt.parent)) {
|
if (isPresent(stmt.parent)) {
|
||||||
ctx.print(` extends `);
|
ctx.print(` extends `);
|
||||||
|
this.typeExpression++;
|
||||||
stmt.parent.visitExpression(this, ctx);
|
stmt.parent.visitExpression(this, ctx);
|
||||||
|
this.typeExpression--;
|
||||||
}
|
}
|
||||||
ctx.println(` {`);
|
ctx.println(` {`);
|
||||||
ctx.incIndent();
|
ctx.incIndent();
|
||||||
|
@ -299,11 +317,6 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
||||||
|
|
||||||
visitExpressionType(ast: o.ExpressionType, ctx: EmitterVisitorContext): any {
|
visitExpressionType(ast: o.ExpressionType, ctx: EmitterVisitorContext): any {
|
||||||
ast.value.visitExpression(this, ctx);
|
ast.value.visitExpression(this, ctx);
|
||||||
if (isPresent(ast.typeParams) && ast.typeParams.length > 0) {
|
|
||||||
ctx.print(`<`);
|
|
||||||
this.visitAllObjects(type => type.visitType(this, ctx), ast.typeParams, ctx, ',');
|
|
||||||
ctx.print(`>`);
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,17 +359,24 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
||||||
}, params, ctx, ',');
|
}, params, ctx, ',');
|
||||||
}
|
}
|
||||||
|
|
||||||
private _resolveStaticSymbol(value: CompileIdentifierMetadata): StaticSymbol {
|
private _resolveStaticSymbol(value: CompileIdentifierMetadata):
|
||||||
|
{name: string, filePath: string, members?: string[], arity?: number} {
|
||||||
const reference = value.reference;
|
const reference = value.reference;
|
||||||
if (!(reference instanceof StaticSymbol)) {
|
if (!(reference instanceof StaticSymbol)) {
|
||||||
throw new Error(`Internal error: unknown identifier ${JSON.stringify(value)}`);
|
throw new Error(`Internal error: unknown identifier ${JSON.stringify(value)}`);
|
||||||
}
|
}
|
||||||
return this._importResolver.getImportAs(reference) || reference;
|
const arity = this._importResolver.getTypeArity(reference) || undefined;
|
||||||
|
const importReference = this._importResolver.getImportAs(reference) || reference;
|
||||||
|
return {
|
||||||
|
name: importReference.name,
|
||||||
|
filePath: importReference.filePath,
|
||||||
|
members: importReference.members, arity
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private _visitIdentifier(
|
private _visitIdentifier(
|
||||||
value: CompileIdentifierMetadata, typeParams: o.Type[], ctx: EmitterVisitorContext): void {
|
value: CompileIdentifierMetadata, typeParams: o.Type[], ctx: EmitterVisitorContext): void {
|
||||||
const {name, filePath, members} = this._resolveStaticSymbol(value);
|
const {name, filePath, members, arity} = this._resolveStaticSymbol(value);
|
||||||
if (filePath != this._genFilePath) {
|
if (filePath != this._genFilePath) {
|
||||||
let prefix = this.importsWithPrefixes.get(filePath);
|
let prefix = this.importsWithPrefixes.get(filePath);
|
||||||
if (isBlank(prefix)) {
|
if (isBlank(prefix)) {
|
||||||
|
@ -372,10 +392,28 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
||||||
} else {
|
} else {
|
||||||
ctx.print(name);
|
ctx.print(name);
|
||||||
}
|
}
|
||||||
if (isPresent(typeParams) && typeParams.length > 0) {
|
|
||||||
|
if (this.typeExpression > 0) {
|
||||||
|
// If we are in a type expreession that refers to a generic type then supply
|
||||||
|
// the required type parameters. If there were not enough type parameters
|
||||||
|
// supplied, supply any as the type. Outside a type expression the reference
|
||||||
|
// should not supply type parameters and be treated as a simple value reference
|
||||||
|
// to the constructor function itself.
|
||||||
|
const suppliedParameters = (typeParams && typeParams.length) || 0;
|
||||||
|
const additionalParameters = (arity || 0) - suppliedParameters;
|
||||||
|
if (suppliedParameters > 0 || additionalParameters > 0) {
|
||||||
ctx.print(`<`);
|
ctx.print(`<`);
|
||||||
|
if (suppliedParameters > 0) {
|
||||||
this.visitAllObjects(type => type.visitType(this, ctx), typeParams, ctx, ',');
|
this.visitAllObjects(type => type.visitType(this, ctx), typeParams, ctx, ',');
|
||||||
|
}
|
||||||
|
if (additionalParameters > 0) {
|
||||||
|
for (let i = 0; i < additionalParameters; i++) {
|
||||||
|
if (i > 0 || suppliedParameters > 0) ctx.print(',');
|
||||||
|
ctx.print('any');
|
||||||
|
}
|
||||||
|
}
|
||||||
ctx.print(`>`);
|
ctx.print(`>`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ class SimpleJsImportGenerator implements ImportResolver {
|
||||||
return importedUrlStr;
|
return importedUrlStr;
|
||||||
}
|
}
|
||||||
getImportAs(symbol: StaticSymbol): StaticSymbol { return null; }
|
getImportAs(symbol: StaticSymbol): StaticSymbol { return null; }
|
||||||
|
getTypeArity(symbol: StaticSymbol): number /*|null*/ { return null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
|
|
|
@ -264,4 +264,5 @@ export class SimpleJsImportGenerator implements ImportResolver {
|
||||||
return importedUrlStr;
|
return importedUrlStr;
|
||||||
}
|
}
|
||||||
getImportAs(symbol: StaticSymbol): StaticSymbol { return null; }
|
getImportAs(symbol: StaticSymbol): StaticSymbol { return null; }
|
||||||
|
getTypeArity(symbol: StaticSymbol): number /*|null*/ { return null; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,4 +75,5 @@ class StubReflectorHost implements StaticSymbolResolverHost {
|
||||||
class StubImportResolver extends ImportResolver {
|
class StubImportResolver extends ImportResolver {
|
||||||
fileNameToModuleName(importedFilePath: string, containingFilePath: string): string { return ''; }
|
fileNameToModuleName(importedFilePath: string, containingFilePath: string): string { return ''; }
|
||||||
getImportAs(symbol: StaticSymbol): StaticSymbol { return null; }
|
getImportAs(symbol: StaticSymbol): StaticSymbol { return null; }
|
||||||
|
getTypeArity(symbol: StaticSymbol): number /*|null*/ { return null; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ class SimpleJsImportGenerator implements ImportResolver {
|
||||||
return importedUrlStr;
|
return importedUrlStr;
|
||||||
}
|
}
|
||||||
getImportAs(symbol: StaticSymbol): StaticSymbol { return null; }
|
getImportAs(symbol: StaticSymbol): StaticSymbol { return null; }
|
||||||
|
getTypeArity(symbol: StaticSymbol): number /*|null*/ { return null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
|
@ -429,11 +430,19 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support expression types', () => {
|
it('should support expression types', () => {
|
||||||
|
expect(
|
||||||
|
emitStmt(o.variable('a').set(o.NULL_EXPR).toDeclStmt(o.expressionType(o.variable('b')))))
|
||||||
|
.toEqual('var a:b = (null as any);');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support expressions with type parameters', () => {
|
||||||
expect(emitStmt(o.variable('a')
|
expect(emitStmt(o.variable('a')
|
||||||
.set(o.NULL_EXPR)
|
.set(o.NULL_EXPR)
|
||||||
.toDeclStmt(o.expressionType(
|
.toDeclStmt(o.importType(externalModuleIdentifier, [o.STRING_TYPE]))))
|
||||||
o.variable('b'), [o.expressionType(o.variable('c'))]))))
|
.toEqual([
|
||||||
.toEqual('var a:b<c> = (null as any);');
|
`import * as import0 from 'somePackage/someOtherPath';`,
|
||||||
|
`var a:import0.someExternalId<string> = (null as any);`
|
||||||
|
].join('\n'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support combined types', () => {
|
it('should support combined types', () => {
|
||||||
|
|
Loading…
Reference in New Issue