diff --git a/packages/@jsii/spec/lib/assembly.ts b/packages/@jsii/spec/lib/assembly.ts index b9477241a0..67f396a2f5 100644 --- a/packages/@jsii/spec/lib/assembly.ts +++ b/packages/@jsii/spec/lib/assembly.ts @@ -506,6 +506,7 @@ export interface NamedTypeReference { */ fqn: FQN; } + export function isNamedTypeReference( ref: TypeReference | undefined, ): ref is NamedTypeReference { @@ -746,7 +747,8 @@ export function isMethod(callable: Callable): callable is Method { /** * Represents a type definition (not a type reference). */ -export type Type = TypeBase & (ClassType | EnumType | InterfaceType); +export type Type = TypeBase & + (ClassType | EnumType | InterfaceType | NamedUnionType); /** * Common attributes of a type definition. @@ -795,6 +797,7 @@ export enum TypeKind { Class = 'class', Enum = 'enum', Interface = 'interface', + NamedUnion = 'union', } /** @@ -918,6 +921,24 @@ export function isEnumType(type: Type | undefined): type is EnumType { return type?.kind === TypeKind.Enum; } +/** + * Represents a named type union. + */ +export interface NamedUnionType extends TypeBase { + kind: TypeKind.NamedUnion; + + /** + * Candidate types for the union. + */ + types: TypeReference[]; +} + +export function isNamedUnionType( + type: Type | undefined, +): type is NamedUnionType { + return type?.kind === TypeKind.NamedUnion; +} + /** * Return whether this type is a class or interface type */ diff --git a/packages/@scope/jsii-calc-lib/test/assembly.jsii b/packages/@scope/jsii-calc-lib/test/assembly.jsii index 9fb1cd290e..ab9b6e0c47 100644 --- a/packages/@scope/jsii-calc-lib/test/assembly.jsii +++ b/packages/@scope/jsii-calc-lib/test/assembly.jsii @@ -322,6 +322,10 @@ "stability": "deprecated", "summary": "Creates a Number object." }, + "locationInModule": { + "filename": "lib/index.ts", + "line": 35 + }, "parameters": [ { "docs": { @@ -626,6 +630,10 @@ "initializer": { "docs": { "stability": "deprecated" + }, + "locationInModule": { + "filename": "lib/submodule/index.ts", + "line": 11 } }, "kind": "class", @@ -668,5 +676,5 @@ } }, "version": "0.0.0", - "fingerprint": "w6/8Kda6/JitSbpMK3LGPK5JGRxJ50gflR5S4sUEHKk=" + "fingerprint": "fVfpIK7xUajlT1zkHIJ8uYJPvy0gLgEe5BM8afu1mVg=" } diff --git a/packages/jsii-calc/lib/compliance.ts b/packages/jsii-calc/lib/compliance.ts index e5f763fa62..2a9f68c68b 100644 --- a/packages/jsii-calc/lib/compliance.ts +++ b/packages/jsii-calc/lib/compliance.ts @@ -1020,7 +1020,7 @@ export class NodeStandardLibrary { /** * Returns the current os.platform() from the "os" node module. */ - public get osPlatform() { + public get osPlatform(): string { return os.platform(); } diff --git a/packages/jsii-calc/test/assembly.jsii b/packages/jsii-calc/test/assembly.jsii index f3a438b09c..76cf5bb936 100644 --- a/packages/jsii-calc/test/assembly.jsii +++ b/packages/jsii-calc/test/assembly.jsii @@ -517,6 +517,10 @@ "stability": "experimental", "summary": "Creates a BinaryOperation." }, + "locationInModule": { + "filename": "lib/calculator.ts", + "line": 43 + }, "parameters": [ { "docs": { @@ -1145,6 +1149,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2451 + }, "parameters": [ { "name": "scope", @@ -1479,6 +1487,10 @@ "stability": "experimental", "summary": "Creates a BinaryOperation." }, + "locationInModule": { + "filename": "lib/calculator.ts", + "line": 43 + }, "parameters": [ { "docs": { @@ -1576,6 +1588,10 @@ "stability": "experimental", "summary": "Creates a Calculator object." }, + "locationInModule": { + "filename": "lib/calculator.ts", + "line": 279 + }, "parameters": [ { "docs": { @@ -2047,6 +2063,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1915 + }, "parameters": [ { "name": "map", @@ -2230,6 +2250,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1864 + }, "parameters": [ { "name": "int", @@ -2549,6 +2573,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1654 + }, "parameters": [ { "name": "consumer", @@ -2718,6 +2746,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2432 + }, "parameters": [ { "name": "delegate", @@ -3045,6 +3077,10 @@ "initializer": { "docs": { "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1792 } }, "kind": "class", @@ -3146,6 +3182,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 303 + }, "parameters": [ { "name": "arg1", @@ -3233,6 +3273,10 @@ "initializer": { "docs": { "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2292 } }, "kind": "class", @@ -3290,6 +3334,10 @@ "deprecated": "this constructor is \"just\" okay", "stability": "deprecated" }, + "locationInModule": { + "filename": "lib/stability.ts", + "line": 91 + }, "parameters": [ { "name": "readonlyString", @@ -4261,6 +4309,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/stability.ts", + "line": 22 + }, "parameters": [ { "name": "readonlyString", @@ -4394,6 +4446,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1357 + }, "parameters": [ { "name": "success", @@ -4488,6 +4544,10 @@ }, "stability": "experimental" }, + "locationInModule": { + "filename": "lib/stability.ts", + "line": 125 + }, "parameters": [ { "name": "readonlyString", @@ -6611,6 +6671,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/erasures.ts", + "line": 15 + }, "parameters": [ { "name": "property", @@ -7884,6 +7948,10 @@ "stability": "experimental", "summary": "Creates a BinaryOperation." }, + "locationInModule": { + "filename": "lib/calculator.ts", + "line": 43 + }, "parameters": [ { "docs": { @@ -8016,6 +8084,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/calculator.ts", + "line": 94 + }, "parameters": [ { "name": "operand", @@ -8252,6 +8324,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1232 + }, "parameters": [ { "name": "_param1", @@ -8403,6 +8479,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 494 + }, "parameters": [ { "name": "generator", @@ -8619,6 +8699,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1101 + }, "parameters": [ { "name": "delegate", @@ -8667,6 +8751,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 296 + }, "parameters": [ { "name": "arg1", @@ -8783,6 +8871,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1670 + }, "parameters": [ { "name": "optionalStruct", @@ -9096,6 +9188,10 @@ "stability": "experimental", "summary": "Creates a Power operation." }, + "locationInModule": { + "filename": "lib/calculator.ts", + "line": 218 + }, "parameters": [ { "docs": { @@ -9590,6 +9686,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 968 + }, "parameters": [ { "name": "self", @@ -9658,6 +9758,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 976 + }, "parameters": [ { "name": "props", @@ -10374,6 +10478,10 @@ "docs": { "stability": "stable" }, + "locationInModule": { + "filename": "lib/stability.ts", + "line": 57 + }, "parameters": [ { "name": "readonlyString", @@ -10556,6 +10664,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 682 + }, "parameters": [ { "name": "value", @@ -11224,6 +11336,10 @@ "initializer": { "docs": { "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/calculator.ts", + "line": 195 } }, "kind": "class", @@ -11282,6 +11398,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1975 + }, "parameters": [ { "docs": { @@ -11430,6 +11550,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1960 + }, "parameters": [ { "docs": { @@ -11916,6 +12040,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/calculator.ts", + "line": 94 + }, "parameters": [ { "name": "operand", @@ -12027,6 +12155,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/submodules.ts", + "line": 9 + }, "parameters": [ { "name": "delegate", @@ -12162,6 +12294,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 588 + }, "parameters": [ { "name": "obj", @@ -12267,6 +12403,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 673 + }, "parameters": [ { "name": "method", @@ -12325,6 +12465,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 659 + }, "parameters": [ { "docs": { @@ -12592,6 +12736,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1747 + }, "parameters": [ { "name": "privateField", @@ -12790,6 +12938,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/submodule/my-class.ts", + "line": 11 + }, "parameters": [ { "name": "props", @@ -12984,6 +13136,10 @@ "initializer": { "docs": { "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/submodule/child/index.ts", + "line": 40 } }, "kind": "class", @@ -13023,6 +13179,10 @@ "initializer": { "docs": { "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/submodule/child/index.ts", + "line": 27 } }, "kind": "class", @@ -13218,5 +13378,5 @@ } }, "version": "0.0.0", - "fingerprint": "5Tv5ECDhqPZgUeGoaL8LTa8pvOZnosdszen+rYjvQ8s=" + "fingerprint": "KrxhHrcWUKwxL1npAlOFVhDgFnYyrYUdmZw4cPNNAw0=" } diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/.jsii b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/.jsii index 9fb1cd290e..ab9b6e0c47 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/.jsii +++ b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/.jsii @@ -322,6 +322,10 @@ "stability": "deprecated", "summary": "Creates a Number object." }, + "locationInModule": { + "filename": "lib/index.ts", + "line": 35 + }, "parameters": [ { "docs": { @@ -626,6 +630,10 @@ "initializer": { "docs": { "stability": "deprecated" + }, + "locationInModule": { + "filename": "lib/submodule/index.ts", + "line": 11 } }, "kind": "class", @@ -668,5 +676,5 @@ } }, "version": "0.0.0", - "fingerprint": "w6/8Kda6/JitSbpMK3LGPK5JGRxJ50gflR5S4sUEHKk=" + "fingerprint": "fVfpIK7xUajlT1zkHIJ8uYJPvy0gLgEe5BM8afu1mVg=" } diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/.jsii b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/.jsii index f3a438b09c..76cf5bb936 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/.jsii +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/.jsii @@ -517,6 +517,10 @@ "stability": "experimental", "summary": "Creates a BinaryOperation." }, + "locationInModule": { + "filename": "lib/calculator.ts", + "line": 43 + }, "parameters": [ { "docs": { @@ -1145,6 +1149,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2451 + }, "parameters": [ { "name": "scope", @@ -1479,6 +1487,10 @@ "stability": "experimental", "summary": "Creates a BinaryOperation." }, + "locationInModule": { + "filename": "lib/calculator.ts", + "line": 43 + }, "parameters": [ { "docs": { @@ -1576,6 +1588,10 @@ "stability": "experimental", "summary": "Creates a Calculator object." }, + "locationInModule": { + "filename": "lib/calculator.ts", + "line": 279 + }, "parameters": [ { "docs": { @@ -2047,6 +2063,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1915 + }, "parameters": [ { "name": "map", @@ -2230,6 +2250,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1864 + }, "parameters": [ { "name": "int", @@ -2549,6 +2573,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1654 + }, "parameters": [ { "name": "consumer", @@ -2718,6 +2746,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2432 + }, "parameters": [ { "name": "delegate", @@ -3045,6 +3077,10 @@ "initializer": { "docs": { "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1792 } }, "kind": "class", @@ -3146,6 +3182,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 303 + }, "parameters": [ { "name": "arg1", @@ -3233,6 +3273,10 @@ "initializer": { "docs": { "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2292 } }, "kind": "class", @@ -3290,6 +3334,10 @@ "deprecated": "this constructor is \"just\" okay", "stability": "deprecated" }, + "locationInModule": { + "filename": "lib/stability.ts", + "line": 91 + }, "parameters": [ { "name": "readonlyString", @@ -4261,6 +4309,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/stability.ts", + "line": 22 + }, "parameters": [ { "name": "readonlyString", @@ -4394,6 +4446,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1357 + }, "parameters": [ { "name": "success", @@ -4488,6 +4544,10 @@ }, "stability": "experimental" }, + "locationInModule": { + "filename": "lib/stability.ts", + "line": 125 + }, "parameters": [ { "name": "readonlyString", @@ -6611,6 +6671,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/erasures.ts", + "line": 15 + }, "parameters": [ { "name": "property", @@ -7884,6 +7948,10 @@ "stability": "experimental", "summary": "Creates a BinaryOperation." }, + "locationInModule": { + "filename": "lib/calculator.ts", + "line": 43 + }, "parameters": [ { "docs": { @@ -8016,6 +8084,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/calculator.ts", + "line": 94 + }, "parameters": [ { "name": "operand", @@ -8252,6 +8324,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1232 + }, "parameters": [ { "name": "_param1", @@ -8403,6 +8479,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 494 + }, "parameters": [ { "name": "generator", @@ -8619,6 +8699,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1101 + }, "parameters": [ { "name": "delegate", @@ -8667,6 +8751,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 296 + }, "parameters": [ { "name": "arg1", @@ -8783,6 +8871,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1670 + }, "parameters": [ { "name": "optionalStruct", @@ -9096,6 +9188,10 @@ "stability": "experimental", "summary": "Creates a Power operation." }, + "locationInModule": { + "filename": "lib/calculator.ts", + "line": 218 + }, "parameters": [ { "docs": { @@ -9590,6 +9686,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 968 + }, "parameters": [ { "name": "self", @@ -9658,6 +9758,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 976 + }, "parameters": [ { "name": "props", @@ -10374,6 +10478,10 @@ "docs": { "stability": "stable" }, + "locationInModule": { + "filename": "lib/stability.ts", + "line": 57 + }, "parameters": [ { "name": "readonlyString", @@ -10556,6 +10664,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 682 + }, "parameters": [ { "name": "value", @@ -11224,6 +11336,10 @@ "initializer": { "docs": { "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/calculator.ts", + "line": 195 } }, "kind": "class", @@ -11282,6 +11398,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1975 + }, "parameters": [ { "docs": { @@ -11430,6 +11550,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1960 + }, "parameters": [ { "docs": { @@ -11916,6 +12040,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/calculator.ts", + "line": 94 + }, "parameters": [ { "name": "operand", @@ -12027,6 +12155,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/submodules.ts", + "line": 9 + }, "parameters": [ { "name": "delegate", @@ -12162,6 +12294,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 588 + }, "parameters": [ { "name": "obj", @@ -12267,6 +12403,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 673 + }, "parameters": [ { "name": "method", @@ -12325,6 +12465,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 659 + }, "parameters": [ { "docs": { @@ -12592,6 +12736,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 1747 + }, "parameters": [ { "name": "privateField", @@ -12790,6 +12938,10 @@ "docs": { "stability": "experimental" }, + "locationInModule": { + "filename": "lib/submodule/my-class.ts", + "line": 11 + }, "parameters": [ { "name": "props", @@ -12984,6 +13136,10 @@ "initializer": { "docs": { "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/submodule/child/index.ts", + "line": 40 } }, "kind": "class", @@ -13023,6 +13179,10 @@ "initializer": { "docs": { "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/submodule/child/index.ts", + "line": 27 } }, "kind": "class", @@ -13218,5 +13378,5 @@ } }, "version": "0.0.0", - "fingerprint": "5Tv5ECDhqPZgUeGoaL8LTa8pvOZnosdszen+rYjvQ8s=" + "fingerprint": "KrxhHrcWUKwxL1npAlOFVhDgFnYyrYUdmZw4cPNNAw0=" } diff --git a/packages/jsii-reflect/lib/assembly.ts b/packages/jsii-reflect/lib/assembly.ts index 11fc26f5c4..cd2828b496 100644 --- a/packages/jsii-reflect/lib/assembly.ts +++ b/packages/jsii-reflect/lib/assembly.ts @@ -221,7 +221,7 @@ export class Assembly extends ModuleLike { break; default: - throw new Error('Unknown type kind'); + throw new Error(`Unsupported type kind: ${typeSpec.kind}`); } if (submodule != null) { diff --git a/packages/jsii/lib/assembler.ts b/packages/jsii/lib/assembler.ts index 0300d283f2..98d927923e 100644 --- a/packages/jsii/lib/assembler.ts +++ b/packages/jsii/lib/assembler.ts @@ -383,7 +383,11 @@ export class Assembler implements Emitter { private async _getFQN(type: ts.Type): Promise { const singleValuedEnum = isSingleValuedEnum(type, this._typeChecker); - const tsFullName = this._typeChecker.getFullyQualifiedName(type.symbol); + const symbol = type.isUnion() + ? type.aliasSymbol ?? type.symbol + : type.symbol; + + const tsFullName = this._typeChecker.getFullyQualifiedName(symbol); const tsName = singleValuedEnum ? // If it's a single-valued enum, we need to remove the last qualifier to get back to the enum. tsFullName.replace(/\.[^.]+$/, '') @@ -391,10 +395,10 @@ export class Assembler implements Emitter { let node = singleValuedEnum ? // If it's a single-valued enum, we need to move to the parent to have the enum declaration - type.symbol.valueDeclaration.parent - : type.symbol.valueDeclaration; - if (!node && type.symbol.declarations.length > 0) { - node = type.symbol.declarations[0]; + symbol.valueDeclaration.parent + : symbol.valueDeclaration; + if (!node && symbol.declarations.length > 0) { + node = symbol.declarations[0]; } const groups = /^"([^"]+)"\.(.*)$/.exec(tsName); @@ -417,7 +421,7 @@ export class Assembler implements Emitter { return `unknown.${typeName}`; } - const submodule = this._submoduleMap.get(type.symbol); + const submodule = this._submoduleMap.get(symbol); if (submodule != null) { const submoduleNs = this._submodules.get(submodule)!.fqnResolutionPrefix; return `${submoduleNs}.${typeName}`; @@ -426,7 +430,7 @@ export class Assembler implements Emitter { const fqn = `${pkg.name}.${typeName}`; if ( pkg.name !== this.projectInfo.name && - !this._dereference({ fqn }, type.symbol.valueDeclaration) + !this._dereference({ fqn }, symbol.valueDeclaration) ) { this._diagnostic( node, @@ -808,6 +812,12 @@ export class Assembler implements Emitter { ); } return allTypes; + } else if (ts.isTypeAliasDeclaration(node)) { + // export type name = ...; + jsiiType = await this._visitTypeAlias( + this._typeChecker.getTypeAtLocation(node), + context, + ); } else { this._diagnostic( node, @@ -870,7 +880,7 @@ export class Assembler implements Emitter { jsiiType.locationInModule = this.declarationLocation(node); const type = this._typeChecker.getTypeAtLocation(node); - if (type.symbol.exports) { + if ((type.aliasSymbol ?? type.symbol).exports) { const nestedContext = context.appendNamespace(type.symbol.name); const visitedNodes = this._typeChecker .getExportsOfModule(type.symbol) @@ -1267,7 +1277,9 @@ export class Assembler implements Emitter { ts.ModifierFlags.Private) === 0 ) { - jsiiType.initializer = {}; + jsiiType.initializer = { + locationInModule: this.declarationLocation(ctorDeclaration), + }; if (signature) { for (const param of signature.getParameters()) { jsiiType.initializer.parameters = @@ -1543,6 +1555,36 @@ export class Assembler implements Emitter { return Promise.resolve(jsiiType); } + private async _visitTypeAlias( + type: ts.Type, + ctx: EmitContext, + ): Promise { + if (!type.isUnion()) { + this._diagnostic( + type.symbol.declarations[0], + ts.DiagnosticCategory.Message, + `Ignoring type alias declaration (only type union aliases are supported)`, + ); + return Promise.resolve(undefined); + } + const symbol = type.aliasSymbol ?? type.symbol; + return { + assembly: this.projectInfo.name, + fqn: `${[this.projectInfo.name, ...ctx.namespace].join('.')}.${ + symbol.name + }`, + kind: spec.TypeKind.NamedUnion, + types: await Promise.all( + type.types.map((type) => + this._typeReference(type, symbol.declarations[0]), + ), + ), + name: symbol.name, + namespace: ctx.namespace.length > 0 ? ctx.namespace.join('.') : undefined, + docs: this._visitDocumentation(symbol, ctx), + }; + } + /** * Return docs for a symbol */ @@ -1929,6 +1971,7 @@ export class Assembler implements Emitter { )}`, ); } + if (isProhibitedMemberName(symbol.name)) { this._diagnostic( symbol.valueDeclaration, @@ -1947,7 +1990,7 @@ export class Assembler implements Emitter { | ts.ParameterPropertyDeclaration; const property: spec.Property = { ...(await this._optionalValue( - this._typeChecker.getTypeOfSymbolAtLocation(symbol, signature), + this._typeChecker.getTypeAtLocation(signature.type ?? signature), signature, )), abstract: _isAbstract(symbol, type) || undefined, @@ -2012,7 +2055,9 @@ export class Assembler implements Emitter { const parameter: spec.Parameter = { ...(await this._optionalValue( - this._typeChecker.getTypeAtLocation(paramSymbol.valueDeclaration), + this._typeChecker.getTypeAtLocation( + paramDeclaration.type ?? paramDeclaration, + ), paramSymbol.valueDeclaration, )), name: paramSymbol.name, @@ -2065,11 +2110,15 @@ export class Assembler implements Emitter { return { type: primitiveType }; } - if (type.isUnion() && !_isEnumLike(type)) { + if (type.isUnion() && type.aliasSymbol == null && !_isEnumLike(type)) { return _unionType.call(this); } - if (!type.symbol) { + const symbol = type.isUnion() + ? type.aliasSymbol ?? type.symbol + : type.symbol; + + if (!symbol) { this._diagnostic( declaration, ts.DiagnosticCategory.Error, @@ -2078,15 +2127,15 @@ export class Assembler implements Emitter { return { type: spec.CANONICAL_ANY }; } - if (type.symbol.name === 'Array') { + if (symbol.name === 'Array') { return { type: await _arrayType.call(this) }; } - if (type.symbol.name === '__type' && type.symbol.members) { + if (symbol.name === '__type' && symbol.members) { return { type: await _mapType.call(this) }; } - if (type.symbol.escapedName === 'Promise') { + if (symbol.escapedName === 'Promise') { const typeRef = type as ts.TypeReference; if (!typeRef.typeArguments || typeRef.typeArguments.length !== 1) { this._diagnostic( diff --git a/packages/jsii/lib/helpers.ts b/packages/jsii/lib/helpers.ts index 1b5fe12d17..93d2d41cc4 100644 --- a/packages/jsii/lib/helpers.ts +++ b/packages/jsii/lib/helpers.ts @@ -33,6 +33,8 @@ export async function sourceToAssemblyHelper( }); const emitResult = await compiler.emit(); + expect(emitResult.emitSkipped).toBeFalsy(); + const errors = emitResult.diagnostics.filter( (d) => d.category === DiagnosticCategory.Error, ); diff --git a/packages/jsii/package.json b/packages/jsii/package.json index 2182390cca..56423f1898 100644 --- a/packages/jsii/package.json +++ b/packages/jsii/package.json @@ -63,7 +63,8 @@ "jest": "^26.1.0", "jest-expect-message": "^1.0.2", "jsii-build-tools": "^0.0.0", - "prettier": "^2.0.5" + "prettier": "^2.0.5", + "ts-jest": "^26.1.3" }, "jest": { "collectCoverage": true, @@ -87,7 +88,10 @@ ], "testEnvironment": "node", "testMatch": [ - "**/?(*.)+(spec|test).js" - ] + "**/?(*.)+(spec|test).ts" + ], + "transform": { + "\\.ts$": "ts-jest" + } } } diff --git a/packages/jsii/test/named-unions.test.ts b/packages/jsii/test/named-unions.test.ts new file mode 100644 index 0000000000..d355dc34f1 --- /dev/null +++ b/packages/jsii/test/named-unions.test.ts @@ -0,0 +1,80 @@ +import { PrimitiveType } from '@jsii/spec'; +import { sourceToAssemblyHelper } from '../lib'; + +// ---------------------------------------------------------------------- +test('test parsing aliased union', async () => { + const assembly = await sourceToAssemblyHelper(` + /** A fancy type union */ + export type StringOrNumber = string | number; + `); + + expect(assembly.types?.['testpkg.StringOrNumber']).toEqual({ + assembly: 'testpkg', + docs: { summary: 'A fancy type union.' }, + fqn: 'testpkg.StringOrNumber', + kind: 'union', + types: [ + { primitive: PrimitiveType.String }, + { primitive: PrimitiveType.Number }, + ], + locationInModule: { filename: 'index.ts', line: 3 }, + name: 'StringOrNumber', + }); +}); + +// ---------------------------------------------------------------------- +test('test using aliased union', async () => { + const assembly = await sourceToAssemblyHelper(` + export namespace submodule { + export type StringOrNumber = string | number; + } + + export class Foo { + public constructor(public readonly stringOrNumber?: submodule.StringOrNumber) {} + + public method(defaultValue: submodule.StringOrNumber): submodule.StringOrNumber { + return this.stringOrNumber ?? defaultValue; + } + } + `); + + expect(assembly.types?.['testpkg.Foo']).toEqual({ + assembly: 'testpkg', + fqn: 'testpkg.Foo', + kind: 'class', + initializer: { + locationInModule: { filename: 'index.ts', line: 7 }, + parameters: [ + { + name: 'stringOrNumber', + optional: true, + type: { fqn: 'testpkg.submodule.StringOrNumber' }, + }, + ], + }, + methods: [ + { + locationInModule: { filename: 'index.ts', line: 9 }, + name: 'method', + parameters: [ + { + name: 'defaultValue', + type: { fqn: 'testpkg.submodule.StringOrNumber' }, + }, + ], + returns: { type: { fqn: 'testpkg.submodule.StringOrNumber' } }, + }, + ], + properties: [ + { + immutable: true, + locationInModule: { filename: 'index.ts', line: 7 }, + name: 'stringOrNumber', + optional: true, + type: { fqn: 'testpkg.submodule.StringOrNumber' }, + }, + ], + locationInModule: { filename: 'index.ts', line: 6 }, + name: 'Foo', + }); +});