Skip to content

Commit 01aed03

Browse files
authored
fix(jsii): Correctly handle singleton enums (#535)
When an enum has only one option, TypeScript handles it in a special way and tries very hard to hide the enum declaration in favor of the sole member. This caused incorrect type names and kinds to be emitted in the JSII assembly, resulting in incorrect behavior. This uses a non-public part of the TSC API (possibly an omission from the hand-written type model), so it includes an additional guard check to fail explicitly in case the API's behavior happens to change in a breaking way. Fixes #231
1 parent e804cab commit 01aed03

File tree

20 files changed

+748
-9
lines changed

20 files changed

+748
-9
lines changed

packages/jsii-calc/lib/compliance.ts

+34
Original file line numberDiff line numberDiff line change
@@ -1692,3 +1692,37 @@ export class WithPrivatePropertyInConstructor {
16921692
return this.privateField === 'Success!';
16931693
}
16941694
}
1695+
1696+
/**
1697+
* Verifies that singleton enums are handled correctly
1698+
*
1699+
* https://github.com/awslabs/jsii/issues/231
1700+
*/
1701+
export class SingletonString {
1702+
private constructor() { }
1703+
1704+
public isSingletonString(value: string): boolean {
1705+
return value === SingletonStringEnum.SingletonString;
1706+
}
1707+
}
1708+
/** A singleton string */
1709+
export enum SingletonStringEnum {
1710+
/** 1337 */
1711+
SingletonString = '3L1T3!'
1712+
}
1713+
/**
1714+
* Verifies that singleton enums are handled correctly
1715+
*
1716+
* https://github.com/awslabs/jsii/issues/231
1717+
*/
1718+
export class SingletonInt {
1719+
private constructor() { }
1720+
public isSingletonInt(value: number): boolean {
1721+
return value === SingletonIntEnum.SingletonInt;
1722+
}
1723+
}
1724+
/** A singleton integer. */
1725+
export enum SingletonIntEnum {
1726+
/** Elite! */
1727+
SingletonInt = 1337
1728+
}

packages/jsii-calc/test/assembly.jsii

+127-1
Original file line numberDiff line numberDiff line change
@@ -7121,6 +7121,132 @@
71217121
],
71227122
"name": "SingleInstanceTwoTypes"
71237123
},
7124+
"jsii-calc.SingletonInt": {
7125+
"assembly": "jsii-calc",
7126+
"docs": {
7127+
"remarks": "https://github.com/awslabs/jsii/issues/231",
7128+
"stability": "experimental",
7129+
"summary": "Verifies that singleton enums are handled correctly."
7130+
},
7131+
"fqn": "jsii-calc.SingletonInt",
7132+
"kind": "class",
7133+
"locationInModule": {
7134+
"filename": "lib/compliance.ts",
7135+
"line": 1718
7136+
},
7137+
"methods": [
7138+
{
7139+
"docs": {
7140+
"stability": "experimental"
7141+
},
7142+
"locationInModule": {
7143+
"filename": "lib/compliance.ts",
7144+
"line": 1720
7145+
},
7146+
"name": "isSingletonInt",
7147+
"parameters": [
7148+
{
7149+
"name": "value",
7150+
"type": {
7151+
"primitive": "number"
7152+
}
7153+
}
7154+
],
7155+
"returns": {
7156+
"type": {
7157+
"primitive": "boolean"
7158+
}
7159+
}
7160+
}
7161+
],
7162+
"name": "SingletonInt"
7163+
},
7164+
"jsii-calc.SingletonIntEnum": {
7165+
"assembly": "jsii-calc",
7166+
"docs": {
7167+
"stability": "experimental",
7168+
"summary": "A singleton integer."
7169+
},
7170+
"fqn": "jsii-calc.SingletonIntEnum",
7171+
"kind": "enum",
7172+
"locationInModule": {
7173+
"filename": "lib/compliance.ts",
7174+
"line": 1725
7175+
},
7176+
"members": [
7177+
{
7178+
"docs": {
7179+
"stability": "experimental",
7180+
"summary": "Elite!"
7181+
},
7182+
"name": "SingletonInt"
7183+
}
7184+
],
7185+
"name": "SingletonIntEnum"
7186+
},
7187+
"jsii-calc.SingletonString": {
7188+
"assembly": "jsii-calc",
7189+
"docs": {
7190+
"remarks": "https://github.com/awslabs/jsii/issues/231",
7191+
"stability": "experimental",
7192+
"summary": "Verifies that singleton enums are handled correctly."
7193+
},
7194+
"fqn": "jsii-calc.SingletonString",
7195+
"kind": "class",
7196+
"locationInModule": {
7197+
"filename": "lib/compliance.ts",
7198+
"line": 1701
7199+
},
7200+
"methods": [
7201+
{
7202+
"docs": {
7203+
"stability": "experimental"
7204+
},
7205+
"locationInModule": {
7206+
"filename": "lib/compliance.ts",
7207+
"line": 1704
7208+
},
7209+
"name": "isSingletonString",
7210+
"parameters": [
7211+
{
7212+
"name": "value",
7213+
"type": {
7214+
"primitive": "string"
7215+
}
7216+
}
7217+
],
7218+
"returns": {
7219+
"type": {
7220+
"primitive": "boolean"
7221+
}
7222+
}
7223+
}
7224+
],
7225+
"name": "SingletonString"
7226+
},
7227+
"jsii-calc.SingletonStringEnum": {
7228+
"assembly": "jsii-calc",
7229+
"docs": {
7230+
"stability": "experimental",
7231+
"summary": "A singleton string."
7232+
},
7233+
"fqn": "jsii-calc.SingletonStringEnum",
7234+
"kind": "enum",
7235+
"locationInModule": {
7236+
"filename": "lib/compliance.ts",
7237+
"line": 1709
7238+
},
7239+
"members": [
7240+
{
7241+
"docs": {
7242+
"stability": "experimental",
7243+
"summary": "1337."
7244+
},
7245+
"name": "SingletonString"
7246+
}
7247+
],
7248+
"name": "SingletonStringEnum"
7249+
},
71247250
"jsii-calc.StableClass": {
71257251
"assembly": "jsii-calc",
71267252
"docs": {
@@ -8648,5 +8774,5 @@
86488774
}
86498775
},
86508776
"version": "0.11.2",
8651-
"fingerprint": "eQpFH3EHC2GlCSnThymTxnuO9HyZBFvsvddZqu1Fy+8="
8777+
"fingerprint": "5TwMNffhxUueZQEAGZG6+JIfS6jcTwCJWc9vixH5aLc="
86528778
}

packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/.jsii

+127-1
Original file line numberDiff line numberDiff line change
@@ -7121,6 +7121,132 @@
71217121
],
71227122
"name": "SingleInstanceTwoTypes"
71237123
},
7124+
"jsii-calc.SingletonInt": {
7125+
"assembly": "jsii-calc",
7126+
"docs": {
7127+
"remarks": "https://github.com/awslabs/jsii/issues/231",
7128+
"stability": "experimental",
7129+
"summary": "Verifies that singleton enums are handled correctly."
7130+
},
7131+
"fqn": "jsii-calc.SingletonInt",
7132+
"kind": "class",
7133+
"locationInModule": {
7134+
"filename": "lib/compliance.ts",
7135+
"line": 1718
7136+
},
7137+
"methods": [
7138+
{
7139+
"docs": {
7140+
"stability": "experimental"
7141+
},
7142+
"locationInModule": {
7143+
"filename": "lib/compliance.ts",
7144+
"line": 1720
7145+
},
7146+
"name": "isSingletonInt",
7147+
"parameters": [
7148+
{
7149+
"name": "value",
7150+
"type": {
7151+
"primitive": "number"
7152+
}
7153+
}
7154+
],
7155+
"returns": {
7156+
"type": {
7157+
"primitive": "boolean"
7158+
}
7159+
}
7160+
}
7161+
],
7162+
"name": "SingletonInt"
7163+
},
7164+
"jsii-calc.SingletonIntEnum": {
7165+
"assembly": "jsii-calc",
7166+
"docs": {
7167+
"stability": "experimental",
7168+
"summary": "A singleton integer."
7169+
},
7170+
"fqn": "jsii-calc.SingletonIntEnum",
7171+
"kind": "enum",
7172+
"locationInModule": {
7173+
"filename": "lib/compliance.ts",
7174+
"line": 1725
7175+
},
7176+
"members": [
7177+
{
7178+
"docs": {
7179+
"stability": "experimental",
7180+
"summary": "Elite!"
7181+
},
7182+
"name": "SingletonInt"
7183+
}
7184+
],
7185+
"name": "SingletonIntEnum"
7186+
},
7187+
"jsii-calc.SingletonString": {
7188+
"assembly": "jsii-calc",
7189+
"docs": {
7190+
"remarks": "https://github.com/awslabs/jsii/issues/231",
7191+
"stability": "experimental",
7192+
"summary": "Verifies that singleton enums are handled correctly."
7193+
},
7194+
"fqn": "jsii-calc.SingletonString",
7195+
"kind": "class",
7196+
"locationInModule": {
7197+
"filename": "lib/compliance.ts",
7198+
"line": 1701
7199+
},
7200+
"methods": [
7201+
{
7202+
"docs": {
7203+
"stability": "experimental"
7204+
},
7205+
"locationInModule": {
7206+
"filename": "lib/compliance.ts",
7207+
"line": 1704
7208+
},
7209+
"name": "isSingletonString",
7210+
"parameters": [
7211+
{
7212+
"name": "value",
7213+
"type": {
7214+
"primitive": "string"
7215+
}
7216+
}
7217+
],
7218+
"returns": {
7219+
"type": {
7220+
"primitive": "boolean"
7221+
}
7222+
}
7223+
}
7224+
],
7225+
"name": "SingletonString"
7226+
},
7227+
"jsii-calc.SingletonStringEnum": {
7228+
"assembly": "jsii-calc",
7229+
"docs": {
7230+
"stability": "experimental",
7231+
"summary": "A singleton string."
7232+
},
7233+
"fqn": "jsii-calc.SingletonStringEnum",
7234+
"kind": "enum",
7235+
"locationInModule": {
7236+
"filename": "lib/compliance.ts",
7237+
"line": 1709
7238+
},
7239+
"members": [
7240+
{
7241+
"docs": {
7242+
"stability": "experimental",
7243+
"summary": "1337."
7244+
},
7245+
"name": "SingletonString"
7246+
}
7247+
],
7248+
"name": "SingletonStringEnum"
7249+
},
71247250
"jsii-calc.StableClass": {
71257251
"assembly": "jsii-calc",
71267252
"docs": {
@@ -8648,5 +8774,5 @@
86488774
}
86498775
},
86508776
"version": "0.11.2",
8651-
"fingerprint": "eQpFH3EHC2GlCSnThymTxnuO9HyZBFvsvddZqu1Fy+8="
8777+
"fingerprint": "5TwMNffhxUueZQEAGZG6+JIfS6jcTwCJWc9vixH5aLc="
86528778
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using Amazon.JSII.Runtime.Deputy;
2+
3+
namespace Amazon.JSII.Tests.CalculatorNamespace
4+
{
5+
/// <summary>Verifies that singleton enums are handled correctly.</summary>
6+
/// <remarks>
7+
/// https://github.com/awslabs/jsii/issues/231
8+
/// stability: Experimental
9+
/// </remarks>
10+
[JsiiClass(nativeType: typeof(SingletonInt), fullyQualifiedName: "jsii-calc.SingletonInt")]
11+
public class SingletonInt : DeputyBase
12+
{
13+
protected SingletonInt(ByRefValue reference): base(reference)
14+
{
15+
}
16+
17+
protected SingletonInt(DeputyProps props): base(props)
18+
{
19+
}
20+
21+
/// <remarks>stability: Experimental</remarks>
22+
[JsiiMethod(name: "isSingletonInt", returnsJson: "{\"type\":{\"primitive\":\"boolean\"}}", parametersJson: "[{\"name\":\"value\",\"type\":{\"primitive\":\"number\"}}]")]
23+
public virtual bool IsSingletonInt(double value)
24+
{
25+
return InvokeInstanceMethod<bool>(new object[]{value});
26+
}
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using Amazon.JSII.Runtime.Deputy;
2+
3+
namespace Amazon.JSII.Tests.CalculatorNamespace
4+
{
5+
/// <summary>A singleton integer.</summary>
6+
/// <remarks>stability: Experimental</remarks>
7+
[JsiiEnum(nativeType: typeof(SingletonIntEnum), fullyQualifiedName: "jsii-calc.SingletonIntEnum")]
8+
public enum SingletonIntEnum
9+
{
10+
/// <summary>Elite!</summary>
11+
/// <remarks>stability: Experimental</remarks>
12+
[JsiiEnumMember(name: "SingletonInt")]
13+
SingletonInt
14+
}
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using Amazon.JSII.Runtime.Deputy;
2+
3+
namespace Amazon.JSII.Tests.CalculatorNamespace
4+
{
5+
/// <summary>Verifies that singleton enums are handled correctly.</summary>
6+
/// <remarks>
7+
/// https://github.com/awslabs/jsii/issues/231
8+
/// stability: Experimental
9+
/// </remarks>
10+
[JsiiClass(nativeType: typeof(SingletonString), fullyQualifiedName: "jsii-calc.SingletonString")]
11+
public class SingletonString : DeputyBase
12+
{
13+
protected SingletonString(ByRefValue reference): base(reference)
14+
{
15+
}
16+
17+
protected SingletonString(DeputyProps props): base(props)
18+
{
19+
}
20+
21+
/// <remarks>stability: Experimental</remarks>
22+
[JsiiMethod(name: "isSingletonString", returnsJson: "{\"type\":{\"primitive\":\"boolean\"}}", parametersJson: "[{\"name\":\"value\",\"type\":{\"primitive\":\"string\"}}]")]
23+
public virtual bool IsSingletonString(string value)
24+
{
25+
return InvokeInstanceMethod<bool>(new object[]{value});
26+
}
27+
}
28+
}

0 commit comments

Comments
 (0)