packages/jsii-calc/lib/compliance.ts (2,025 lines of code) (raw):

import * as base from '@scope/jsii-calc-base'; import { EnumFromScopedModule, IDoublable, IFriendly, MyFirstStruct, Number as LibNumber, StructWithOnlyOptionals, NumericValue, } from '@scope/jsii-calc-lib'; import * as crypto from 'crypto'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; import { promisify } from 'util'; import { IFriendlyRandomGenerator, IRandomNumberGenerator, Multiply, } from './calculator'; /* eslint-disable @typescript-eslint/no-namespace, @typescript-eslint/member-ordering, */ // eslint-disable-next-line @typescript-eslint/no-require-imports,@typescript-eslint/no-var-requires const bundled = require('@fixtures/jsii-calc-bundled'); const readFile = promisify(fs.readFile); export enum AllTypesEnum { MY_ENUM_VALUE, YOUR_ENUM_VALUE = 100, THIS_IS_GREAT, } export enum StringEnum { A = 'A!', B = 'B?', C = 'C.', } export class EnumDispenser { public static randomStringLikeEnum(): StringEnum { // Haha! I lied, it's not random!! *EVIL LAUGHTER* return StringEnum.B; } public static randomIntegerLikeEnum(): AllTypesEnum { // Haha! I lied, it's not random!! *EVIL LAUGHTER* return AllTypesEnum.YOUR_ENUM_VALUE; } private constructor() {} } /** * This class includes property for all types supported by jsii. The setters will validate * that the value set is of the expected type and throw otherwise. */ export class AllTypes { // boolean private boolValue = false; public get booleanProperty() { return this.boolValue; } public set booleanProperty(value: boolean) { if (typeof value !== 'boolean') { throw new Error('not a boolean'); } this.boolValue = value; } // string private stringValue = 'first value'; public get stringProperty() { return this.stringValue; } public set stringProperty(value: string) { if (typeof value !== 'string') { throw new Error('not a string'); } this.stringValue = value; } // number private numberValue = 0; public get numberProperty() { return this.numberValue; } public set numberProperty(value: number) { if (typeof value !== 'number') { throw new Error('not a number'); } this.numberValue = value; } // date private dateValue = new Date(); public get dateProperty(): Date { return this.dateValue; } public set dateProperty(value: Date) { // https://stackoverflow.com/a/643827/737957 if (Object.prototype.toString.call(value) !== '[object Date]') { throw new Error(`not a date: ${value as any} type=${typeof value}`); } this.dateValue = value; } // json private jsonValue: object = {}; public get jsonProperty(): object { return this.jsonValue; } public set jsonProperty(value: object) { if (typeof value !== 'object') { throw new Error('not an object'); } this.jsonValue = value; } // map private mapValue: { [key: string]: LibNumber } = {}; public get mapProperty(): { [key: string]: LibNumber } { return this.mapValue; } public set mapProperty(value: { [key: string]: LibNumber }) { if (typeof value !== 'object') { throw new Error('not a map'); } this.mapValue = value; } // array private arrayValue: string[] = []; public get arrayProperty(): string[] { return this.arrayValue; } public set arrayProperty(value: string[]) { if (!Array.isArray(value)) { throw new Error('not an array'); } this.arrayValue = value; } // non-typed (any) public anyProperty: any; public anyArrayProperty: any[] = []; public anyMapProperty: { [key: string]: any } = {}; // non-typed (unknown) public unknownProperty: unknown; public unknownArrayProperty: unknown[] = []; public unknownMapProperty: { [key: string]: unknown } = {}; // unions public unionProperty: string | number | LibNumber | Multiply = 'foo'; public unionArrayProperty: Array<NumericValue | number> = []; public unionMapProperty: { [key: string]: LibNumber | number | string } = {}; // enum public optionalEnumValue?: StringEnum; private enumValue: AllTypesEnum = AllTypesEnum.THIS_IS_GREAT; public get enumProperty() { return this.enumValue; } public set enumProperty(value: AllTypesEnum) { this.enumValue = value; switch (value) { case AllTypesEnum.MY_ENUM_VALUE: case AllTypesEnum.YOUR_ENUM_VALUE: case AllTypesEnum.THIS_IS_GREAT: return; default: throw new Error(`Invalid enum: ${value as any}`); } } public get enumPropertyValue(): number { return this.enumValue.valueOf(); } public enumMethod(value: StringEnum) { return value; } public anyOut(): any { const ret = new LibNumber(42); Object.defineProperty(ret, 'tag', { value: "you're it", }); return ret; } public anyIn(inp: any) { if (inp.tag !== "you're it") { throw new Error( `Not the same object that I gave you, got: ${JSON.stringify(inp)}`, ); } } } // // Return an object literal from JavaScript which conforms to a class (effectively treating // the class as an interface). We want the native code to be able to wrap the resulting object // in a native class. // export class JSObjectLiteralToNative { public returnLiteral(): JSObjectLiteralToNativeClass { return { propA: 'Hello', propB: 102, }; } } export class JSObjectLiteralToNativeClass { public propA = 'A'; public propB = 0; } /** * Verify that object references can be passed inside collections. */ export class ObjectRefsInCollections { /** * Returns the sum of all values */ public sumFromArray(values: NumericValue[]) { let sum = 0; for (const val of values) { sum += val.value; } return sum; } /** * Returns the sum of all values in a map */ public sumFromMap(values: { [key: string]: NumericValue }) { let sum = 0; for (const key of Object.keys(values)) { sum += values[key].value; } return sum; } } export class RuntimeTypeChecking { /** * Used to verify verification of number of method arguments. */ public methodWithOptionalArguments(arg1: number, arg2: string, arg3?: Date) { base.StaticConsumer.consume(arg1, arg2, arg3); } public methodWithDefaultedArguments( arg1 = 2, arg2?: string, arg3: Date = new Date(), ) { base.StaticConsumer.consume(arg1, arg2, arg3); } public methodWithOptionalAnyArgument(arg?: any) { base.StaticConsumer.consume(arg); } } export class OptionalConstructorArgument { public constructor( public readonly arg1: number, public readonly arg2: string, public readonly arg3?: Date, ) {} } export class DefaultedConstructorArgument { public constructor( public readonly arg1: number = 2, public readonly arg2?: string, public readonly arg3: Date = new Date(), ) {} } export namespace DerivedClassHasNoProperties { export class Base { public prop = ''; } export class Derived extends Base {} } export class AsyncVirtualMethods { public async callMe() { return ( (await this.overrideMe(10)) + this.dontOverrideMe() + (await this.overrideMeToo()) ); } public async overrideMe(mult: number) { return Promise.resolve(12 * mult); } public async overrideMeToo() { return Promise.resolve(0); } /** * Just calls "overrideMeToo" */ public async callMe2() { return this.overrideMeToo(); } /** * This method calls the "callMe" async method indirectly, which will then * invoke a virtual method. This is a "double promise" situation, which * means that callbacks are not going to be available immediate, but only * after an "immediates" cycle. */ public async callMeDoublePromise() { return new Promise<number>((ok, ko) => { setImmediate(() => { this.callMe().then(ok, ko); }); }); } public dontOverrideMe() { return 8; } } export class SyncVirtualMethods { public callerIsMethod() { return this.virtualMethod(10); } public get callerIsProperty() { return this.virtualMethod(10); } public set callerIsProperty(x: number) { this.virtualMethod(x); } public async callerIsAsync() { return Promise.resolve(this.virtualMethod(10)); } public virtualMethod(n: number): number { return n * 2; } // read-write property public theProperty = 'initial value'; public modifyValueOfTheProperty(value: string) { this.theProperty = value; } public retrieveValueOfTheProperty() { return this.theProperty; } // read-only property public readonly readonlyProperty: string = 'readonly-property-initial-value'; public retrieveReadOnlyProperty() { return this.readonlyProperty; } // property backed by functions public get otherProperty() { return 'other property'; } public set otherProperty(value: string) { this.valueOfOtherProperty = value; } public valueOfOtherProperty = ''; public modifyOtherProperty(value: string) { this.otherProperty = value; } public retrieveOtherProperty() { return this.otherProperty; } // property with a short name (makes sure for example that java's // convertion of getA to "a" is not assuming that the length is > 1). public a = 0; public readA() { return this.a; } public writeA(value: number) { this.a = value; } } export class VirtualMethodPlayground { public async serialSumAsync(count: number) { return Promise.all( new Array(count).map((_, idx) => this.overrideMeAsync(idx)), ).then((promises) => promises.reduce((acc, elt) => acc + elt, 0)); } public async parallelSumAsync(count: number) { const all = new Array<Promise<number>>(); for (let i = 0; i < count; ++i) { all.push(this.overrideMeAsync(i)); } const result = await Promise.all(all); return result.reduce((x, i) => x + i, 0); } public sumSync(count: number) { let sum = 0; for (let i = 0; i < count; ++i) { sum += this.overrideMeSync(i); } return sum; } public async overrideMeAsync(index: number) { return Promise.resolve(10 * index); } public overrideMeSync(index: number) { return 10 * index; } } export class DoubleTrouble implements IFriendlyRandomGenerator { public next() { return 12; } public hello() { return 'world'; } } export class Polymorphism { public sayHello(friendly: IFriendly) { return `oh, ${friendly.hello()}`; } } /** * This allows us to test that a reference can be stored for objects that * implement interfaces. */ export class NumberGenerator { public constructor(public generator: IRandomNumberGenerator) {} public nextTimes100() { return this.generator.next() * 100; } public isSameGenerator(gen: IRandomNumberGenerator) { return this.generator === gen; } } export class JSObjectLiteralForInterface { public giveMeFriendly(): IFriendly { return { hello: () => 'I am literally friendly!', }; } public giveMeFriendlyGenerator(): IFriendlyRandomGenerator { return { hello: () => 'giveMeFriendlyGenerator', next: () => 42, }; } } export class GreetingAugmenter { public betterGreeting(friendly: IFriendly): string { return `${friendly.hello()} Let me buy you a drink!`; } } /** * A struct which derives from another struct. */ export interface DerivedStruct extends MyFirstStruct { /** * An example of a non primitive property. */ readonly nonPrimitive: DoubleTrouble; readonly bool: boolean; readonly anotherRequired: Date; readonly optionalArray?: string[]; readonly optionalAny?: any; /** * This is optional. */ readonly anotherOptional?: { [key: string]: NumericValue }; } export class GiveMeStructs { /** * Returns the "anumber" from a MyFirstStruct struct; */ public readFirstNumber(first: MyFirstStruct) { return first.anumber; } /** * Returns the boolean from a DerivedStruct struct. */ public readDerivedNonPrimitive(derived: DerivedStruct) { return derived.nonPrimitive; } /** * Accepts a struct of type DerivedStruct and returns a struct of type FirstStruct. */ public derivedToFirst(derived: DerivedStruct) { return derived as MyFirstStruct; } public get structLiteral(): StructWithOnlyOptionals { return { optional1: 'optional1FromStructLiteral', optional3: false, }; } } export interface IInterfaceWithProperties { readonly readOnlyString: string; readWriteString: string; } export interface IInterfaceWithPropertiesExtension extends IInterfaceWithProperties { foo: number; } export class UsesInterfaceWithProperties { public constructor(public readonly obj: IInterfaceWithProperties) {} public justRead() { return this.obj.readOnlyString; } public writeAndRead(value: string) { this.obj.readWriteString = value; return this.obj.readWriteString; } public readStringAndNumber(ext: IInterfaceWithPropertiesExtension) { return `base=${ext.readOnlyString} child=${ext.foo} keys=[${Object.keys( ext, ).join(',')}]`; } } export class AllowedMethodNames { /** * getXxx() is not allowed (see negatives), but getXxx(a, ...) is okay. */ public getFoo(withParam: string) { return withParam; } public getBar(_p1: string, _p2: number) { return; } /** * setFoo(x) is not allowed (see negatives), but setXxx(a, b, ...) is okay. */ public setFoo(_x: string, _y: number) { return; } public setBar(_x: string, _y: number, _z: boolean) { return; } } export interface IReturnsNumber { obtainNumber(): IDoublable; readonly numberProp: LibNumber; } export class OverrideReturnsObject { public test(obj: IReturnsNumber) { return obj.obtainNumber().doubleValue + obj.numberProp.doubleValue; } } export class Thrower { public throwError() { this.doThrowError(); } private doThrowError() { throw new Error(); } } export class VariadicMethod { private readonly prefix: number[]; /** * @param prefix a prefix that will be use for all values returned by `#asArray`. */ public constructor(...prefix: number[]) { this.prefix = prefix; } /** * @param first the first element of the array to be returned (after the `prefix` provided at construction time). * @param others other elements to be included in the array. */ public asArray(first: number, ...others: number[]): number[] { return [...this.prefix, first, ...others]; } } export class VariadicInvoker { public constructor(private readonly method: VariadicMethod) {} public asArray(...values: number[]): number[] { const [first, ...rest] = values; return this.method.asArray(first, ...rest); } } export class Statics { public constructor(public readonly value: string) {} /** * Jsdocs for static method * @param name The name of the person to say hello to */ public static staticMethod(name: string) { return `hello ,${name}!`; } public justMethod() { return this.value; } /** * Jsdocs for static property. */ public static readonly Foo = 'hello'; /** * Constants may also use all-caps. */ public static readonly BAR = 1234; /** * Constants can also use camelCase. */ public static readonly zooBar: { [name: string]: string } = { hello: 'world', }; private static _instance?: Statics; /** * Jsdocs for static getter. */ public static get instance(): Statics { this._instance ??= new Statics('default'); return this._instance; } /** * Jsdocs for static setter. */ public static set instance(val: Statics) { this._instance = val; } public static nonConstStatic = 100; // this should not be represented as a constant in target languages public static readonly ConstObj = new DoubleTrouble(); // should be initialized statically } // https://en.wikipedia.org/wiki/List_of_Java_keywords export class JavaReservedWords { public abstract() { return; } public assert() { return; } public boolean() { return; } public break() { return; } public byte() { return; } public case() { return; } public catch() { return; } public char() { return; } public class() { return; } public const() { return; } public continue() { return; } public default() { return; } public double() { return; } public do() { return; } public else() { return; } public enum() { return; } public extends() { return; } public false() { return; } public final() { return; } public finally() { return; } public float() { return; } public for() { return; } public goto() { return; } public if() { return; } public implements() { return; } public import() { return; } public instanceof() { return; } public int() { return; } public interface() { return; } public long() { return; } public native() { return; } public new() { return; } public null() { return; } public package() { return; } public private() { return; } public protected() { return; } public public() { return; } public return() { return; } public short() { return; } public static() { return; } public strictfp() { return; } public super() { return; } public switch() { return; } public synchronized() { return; } public this() { return; } public throw() { return; } public throws() { return; } public transient() { return; } public true() { return; } public try() { return; } public void() { return; } public volatile() { return; } public while = 'hello'; } // https://en.wikipedia.org/wiki/List_of_Java_keywords export interface IJavaReservedWordsInAnInterface { abstract(): void; assert(): void; boolean(): void; break(): void; byte(): void; case(): void; catch(): void; char(): void; class(): void; const(): void; continue(): void; default(): void; double(): void; do(): void; else(): void; enum(): void; extends(): void; false(): void; final(): void; finally(): void; float(): void; for(): void; goto(): void; if(): void; implements(): void; import(): void; instanceof(): void; int(): void; interface(): void; long(): void; native(): void; null(): void; package(): void; private(): void; protected(): void; public(): void; return(): void; short(): void; static(): void; strictfp(): void; super(): void; switch(): void; synchronized(): void; this(): void; throw(): void; throws(): void; transient(): void; true(): void; try(): void; void(): void; volatile(): void; readonly while: string; } export class PythonReservedWords { public and() { return; } public as() { return; } public assert() { return; } public async() { return; } public await() { return; } public break() { return; } public class() { return; } public continue() { return; } public def() { return; } public del() { return; } public elif() { return; } public else() { return; } public except() { return; } public finally() { return; } public for() { return; } public from() { return; } public global() { return; } public if() { return; } public import() { return; } public in() { return; } public is() { return; } public lambda() { return; } public nonlocal() { return; } public not() { return; } public or() { return; } public pass() { return; } public raise() { return; } public return() { return; } public try() { return; } public while() { return; } public with() { return; } public yield() { return; } } // "self" is technically not a keyword in Python. It's the conventional name of // the "this instance" reference. We can slugify this to our heart's content, // without much impact on the developer experience - but it needs to happen! export namespace PythonSelf { export class ClassWithSelf { public constructor(public readonly self: string) {} public method(self: number): string { return self.toString(); } } export class ClassWithSelfKwarg { public constructor(public readonly props: StructWithSelf) {} } export interface StructWithSelf { readonly self: string; } export interface IInterfaceWithSelf { method(self: number): string; } } export interface UnionProperties { readonly foo?: string | number; readonly bar: AllTypes | string | number; } export class UseBundledDependency { public value() { return bundled; } } /** * Test fixture to verify that jsii modules can use the node standard library. */ export class NodeStandardLibrary { /** * Reads a local resource file (resource.txt) asynchronously. * @returns "Hello, resource!" */ public async fsReadFile() { const value = await readFile(path.join(__dirname, 'resource.txt')); return value.toString(); } /** * Sync version of fsReadFile. * @returns "Hello, resource! SYNC!" */ public fsReadFileSync() { return `${fs .readFileSync(path.join(__dirname, 'resource.txt')) .toString()} SYNC!`; } /** * Returns the current os.platform() from the "os" node module. */ public get osPlatform(): string { return os.platform(); } /** * Uses node.js "crypto" module to calculate sha256 of a string. * @returns "6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50" */ public cryptoSha256() { const hash = crypto.createHash('sha256'); hash.update('some data to hash'); return hash.digest('hex'); } } /** * Depend on a type from jsii-calc-base as a test for awslabs/jsii#128 */ export class UseCalcBase { public hello(): base.Base { return { typeName: () => 'hello', }; } } export interface ImplictBaseOfBase extends base.BaseProps { readonly goo: Date; } /** * See awslabs/jsii#138 */ export class ReferenceEnumFromScopedPackage { public foo?: EnumFromScopedModule = EnumFromScopedModule.VALUE2; public loadFoo(): EnumFromScopedModule | undefined { return this.foo; } public saveFoo(value: EnumFromScopedModule) { this.foo = value; } } /** * awslabs/jsii#208 * Interface within a namespace */ export namespace InterfaceInNamespaceOnlyInterface { // it's a special case when only an interface is exported from a namespace export interface Hello { readonly foo: number; } } export namespace InterfaceInNamespaceIncludesClasses { export class Foo { public bar?: string; } export interface Hello { readonly foo: number; } } /** * awslabs/jsii#175 * Interface proxies (and builders) do not respect optional arguments in methods */ export interface IInterfaceWithOptionalMethodArguments { hello(arg1: string, arg2?: number): void; } export class OptionalArgumentInvoker { public constructor( private readonly delegate: IInterfaceWithOptionalMethodArguments, ) {} public invokeWithoutOptional() { return this.delegate.hello('Howdy'); } public invokeWithOptional() { return this.delegate.hello('Howdy', 1337); } } /** * awslabs/jsii#220 * Abstract return type */ export interface IInterfaceImplementedByAbstractClass { readonly propFromInterface: string; } export abstract class AbstractClassBase { public abstract readonly abstractProperty: string; } export abstract class AbstractClass extends AbstractClassBase implements IInterfaceImplementedByAbstractClass { public nonAbstractMethod() { return 42; } public abstract abstractMethod(name: string): string; public get propFromInterface() { return 'propFromInterfaceValue'; } } class ConcreteClass extends AbstractClass { public abstractMethod(name: string) { return `Hello, ${name}!!`; } public get abstractProperty() { return 'Hello, dude!'; } } export class AbstractClassReturner { public giveMeAbstract(): AbstractClass { return new ConcreteClass(); } public giveMeInterface(): IInterfaceImplementedByAbstractClass { return new ConcreteClass(); } public get returnAbstractFromProperty(): AbstractClassBase { return { abstractProperty: 'hello-abstract-property', }; } } export interface IMutableObjectLiteral { value: string; } export class ClassWithMutableObjectLiteralProperty { public mutableObject: IMutableObjectLiteral = { value: 'default' }; } export class DoNotOverridePrivates { private privateMethod(): string { return 'privateMethod'; } private privateProperty = 'privateProperty'; public privateMethodValue() { return this.privateMethod(); } public privatePropertyValue() { return this.privateProperty; } public changePrivatePropertyValue(newValue: string) { this.privateProperty = newValue; } } /** * Class that implements interface properties automatically, but using a private constructor */ export class ClassWithPrivateConstructorAndAutomaticProperties implements IInterfaceWithProperties { public static create(readOnlyString: string, readWriteString: string) { return new ClassWithPrivateConstructorAndAutomaticProperties( readOnlyString, readWriteString, ); } private constructor( public readonly readOnlyString: string, public readWriteString: string, ) {} } export interface IInterfaceWithMethods { readonly value: string; doThings(): void; } /** * Even though this interface has only properties, it is disqualified from being a datatype * because it inherits from an interface that is not a datatype. */ export interface IInterfaceThatShouldNotBeADataType extends IInterfaceWithMethods { readonly otherValue: string; } /** * jsii#284: do not recognize "any" as an optional argument */ export class DoNotRecognizeAnyAsOptional { public method( _requiredAny: any, _optionalAny?: any, _optionalString?: string, ) { return; } } /** * jsii#282, aws-cdk#157: null should be treated as "undefined" */ export class NullShouldBeTreatedAsUndefined { public changeMeToUndefined? = 'hello'; public constructor(_param1: string, optional?: any) { if (optional !== undefined) { throw new Error( 'Expecting second constructor argument to be "undefined"', ); } } public giveMeUndefined(value?: any) { if (value !== undefined) { throw new Error( `I am disappointed. I expected undefined and got: ${JSON.stringify( value, )}`, ); } } public giveMeUndefinedInsideAnObject( input: NullShouldBeTreatedAsUndefinedData, ) { if (input.thisShouldBeUndefined !== undefined) { throw new Error( `I am disappointed. I expected undefined in "thisShouldBeUndefined" and got: ${JSON.stringify( input, )}`, ); } const array = input.arrayWithThreeElementsAndUndefinedAsSecondArgument; if (array.length !== 3) { throw new Error( `Expecting "arrayWithThreeElementsAndUndefinedAsSecondArgument" to have three elements: ${JSON.stringify( input, )}`, ); } if (array[1] !== undefined) { throw new Error( `Expected arrayWithThreeElementsAndUndefinedAsSecondArgument[1] to be undefined: ${JSON.stringify( input, )}`, ); } } public verifyPropertyIsUndefined() { if (this.changeMeToUndefined !== undefined) { throw new Error( `Expecting property "changeMeToUndefined" to be undefined, and it is: ${this.changeMeToUndefined}`, ); } } } export interface NullShouldBeTreatedAsUndefinedData { readonly thisShouldBeUndefined?: any; readonly arrayWithThreeElementsAndUndefinedAsSecondArgument: any[]; } export class DontComplainAboutVariadicAfterOptional { public optionalAndVariadic(optional?: string, ...things: string[]) { return `${optional} and ${things.join(',')}`; } } /** * jsii#298: show default values in sphinx documentation, and respect newlines. **/ export interface LoadBalancedFargateServiceProps { /** * The number of cpu units used by the task. * Valid values, which determines your range of valid values for the memory parameter: * 256 (.25 vCPU) - Available memory values: 0.5GB, 1GB, 2GB * 512 (.5 vCPU) - Available memory values: 1GB, 2GB, 3GB, 4GB * 1024 (1 vCPU) - Available memory values: 2GB, 3GB, 4GB, 5GB, 6GB, 7GB, 8GB * 2048 (2 vCPU) - Available memory values: Between 4GB and 16GB in 1GB increments * 4096 (4 vCPU) - Available memory values: Between 8GB and 30GB in 1GB increments * * This default is set in the underlying FargateTaskDefinition construct. * * @default 256 */ readonly cpu?: string; /** * The amount (in MiB) of memory used by the task. * * This field is required and you must use one of the following values, which determines your range of valid values * for the cpu parameter: * * 0.5GB, 1GB, 2GB - Available cpu values: 256 (.25 vCPU) * * 1GB, 2GB, 3GB, 4GB - Available cpu values: 512 (.5 vCPU) * * 2GB, 3GB, 4GB, 5GB, 6GB, 7GB, 8GB - Available cpu values: 1024 (1 vCPU) * * Between 4GB and 16GB in 1GB increments - Available cpu values: 2048 (2 vCPU) * * Between 8GB and 30GB in 1GB increments - Available cpu values: 4096 (4 vCPU) * * This default is set in the underlying FargateTaskDefinition construct. * * @default 512 */ readonly memoryMiB?: string; /** * The container port of the application load balancer attached to your Fargate service. Corresponds to container port mapping. * * @default 80 */ readonly containerPort?: number; /** * Determines whether the Application Load Balancer will be internet-facing * * @default true */ readonly publicLoadBalancer?: boolean; /** * Determines whether your Fargate Service will be assigned a public IP address. * * @default false */ readonly publicTasks?: boolean; } /** * Helps ensure the JSII kernel & runtime cooperate correctly when an un-exported instance of a class is returned with * a declared type that is an exported interface, and the instance inherits from an exported class. * * @returns an instance of an un-exported class that extends `ExportedBaseClass`, declared as `IPrivatelyImplemented`. * * @see https://github.com/aws/jsii/issues/320 */ export class ReturnsPrivateImplementationOfInterface { public get privateImplementation(): IPrivatelyImplemented { return new PrivateImplementation(); } } export interface IPrivatelyImplemented { readonly success: boolean; } export class ExportedBaseClass { public constructor(public readonly success: boolean) {} } class PrivateImplementation extends ExportedBaseClass implements IPrivatelyImplemented { public constructor() { super(true); } } /** * Host runtime version should be set via JSII_AGENT */ export class JsiiAgent { /** * Returns the value of the JSII_AGENT environment variable. */ public static get value(): string | undefined { return process.env.JSII_AGENT; } } // To support module augmentation classes must support multiple declaration sites // (the tail of which must be interfaces) // eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging export class AugmentableClass { public methodOne(): void { console.log('methodOne'); } } // eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging export interface AugmentableClass { methodTwo(): void; } // Ensure the JSII kernel tags instances with the "most appropriate" FQN type label, so that runtimes are able to // correctly choose the implementation proxy that should be used. Failure to do so could cause situations where userland // needs to up-cast an instance to an incompatible type, which certain runtimes (such as Java) will prevent. // @See https://github.com/aws/jsii/issues/345 export class PublicClass { public hello(): void { return; } } export interface IPublicInterface { bye(): string; } export interface IPublicInterface2 { ciao(): string; } export class InbetweenClass extends PublicClass implements IPublicInterface2 { public ciao(): string { return 'ciao'; } } class PrivateClass extends InbetweenClass implements IPublicInterface { public bye(): string { return 'bye'; } } class HiddenClass implements IPublicInterface, IPublicInterface2 { public bye(): string { return 'bye'; } public ciao(): string { return 'ciao'; } } class HiddenSubclass extends HiddenClass {} export class Constructors { public static makeClass(): PublicClass { return new PrivateClass(); // Wire type should be InbetweenClass } public static makeInterface(): IPublicInterface { return new PrivateClass(); // Wire type should be IPublicInterface } public static makeInterface2(): IPublicInterface2 { return new PrivateClass(); // Wire type should be InbetweenClass } public static makeInterfaces(): IPublicInterface[] { return [new PrivateClass()]; // Wire type should be IPublicInterface[] } public static hiddenInterface(): IPublicInterface { return new HiddenClass(); // Wire type should be IPublicInterface } public static hiddenInterfaces(): IPublicInterface[] { return [new HiddenClass()]; // Wire type should be IPublicInterface[] } public static hiddenSubInterfaces(): IPublicInterface[] { return [new HiddenSubclass()]; // Wire type should be IPublicInterface[] } } /** * Test that a single instance can be returned under two different FQNs * * JSII clients can instantiate 2 different strongly-typed wrappers for the same * object. Unfortunately, this will break object equality, but if we didn't do * this it would break runtime type checks in the JVM or CLR. */ export class SingleInstanceTwoTypes { private readonly instance = new PrivateClass(); public interface1(): InbetweenClass { return this.instance; } public interface2(): IPublicInterface { return this.instance; } } // fixture to verify that null/undefined values in object hashes are treated // as "unset". see awslabs/aws-cdk#965. export interface EraseUndefinedHashValuesOptions { readonly option1?: string; readonly option2?: string; } export class EraseUndefinedHashValues { /** * Returns `true` if `key` is defined in `opts`. Used to check that undefined/null hash values * are being erased when sending values from native code to JS. */ public static doesKeyExist( opts: EraseUndefinedHashValuesOptions, key: string, ): boolean { return key in opts; } /** * We expect "prop2" to be erased */ public static prop2IsUndefined(): { [key: string]: any } { return { prop1: 'value1', prop2: undefined, }; } /** * We expect "prop1" to be erased */ public static prop1IsNull(): { [key: string]: any } { return { prop1: null, prop2: 'value2', }; } } // internal can be used to represent members that can only be accessed from the current module export class StripInternal { public youSeeMe = 'hello'; /** * This is an internal thing * @internal */ public _youDontSeeMeAlthoughIamPublic = 'world'; } /** * @internal */ export class InternalClass { public iAmNotHere = 'yes'; } /** * @internal */ export interface InternalInterface { readonly prop: string; } /** * @internal */ export enum InternalEnum { Member1 = 12, Member2 = 23, } export interface IInterfaceWithInternal { visible(): void; /** @internal */ _hidden(): void; } export class ImplementsInterfaceWithInternal implements IInterfaceWithInternal { public visible() { return; } /** @internal */ public _hidden() { return; } /** @internal */ public _alsoHidden() { return; } /** @internal */ public _propertiesToo?: string; } export class ImplementsInterfaceWithInternalSubclass extends ImplementsInterfaceWithInternal { /** @internal */ public _alsoHidden() { return; } /** * @internal */ public _propertiesToo?: string; } // // hidden interface erasure // if a class/interface uses a hidden (private/internal) interface as base, the base will // be erased from the API // interface IPrivateInterface { private: string; } export interface ExtendsInternalInterface extends InternalInterface { readonly boom: boolean; } export class ImplementInternalInterface implements InternalInterface { public prop = 'implement me'; } export class ImplementsPrivateInterface implements IPrivateInterface { public private = 'i came from private into the light'; } export interface IExtendsPrivateInterface extends IPrivateInterface { readonly moreThings: string[]; } // // hidden (private/internal) base interface erasure will copy non-hidden bases from // hidden to consuming type. // export interface IAnotherPublicInterface { a: string; } /** @internal */ export interface IAnotherInternalInterface extends IAnotherPublicInterface { b: string; } export interface INonInternalInterface extends IAnotherInternalInterface { c: string; } /** @internal */ export interface IInternalInterfaceThatExtendsTheNonInternalOne extends INonInternalInterface { d: string; } interface IPrivateInterfaceThatExtendsTheNonInternalOne extends INonInternalInterface { e: string; } export class ClassThatImplementsTheInternalInterface implements IInternalInterfaceThatExtendsTheNonInternalOne, INonInternalInterface { public a = 'a'; public b = 'b'; public c = 'c'; public d = 'd'; } export class ClassThatImplementsThePrivateInterface implements IPrivateInterfaceThatExtendsTheNonInternalOne { public a = 'a'; public b = 'b'; public c = 'c'; public e = 'e'; } export class ConsumersOfThisCrazyTypeSystem { public consumeAnotherPublicInterface(obj: IAnotherPublicInterface) { return obj.a; } public consumeNonInternalInterface(obj: INonInternalInterface): any { return { a: obj.a, b: obj.b, c: obj.c }; } } // // Ensure the JSII kernel can pass "this" out to JSII remotes from within the constructor (this is dirty, but possible) // export abstract class PartiallyInitializedThisConsumer { public abstract consumePartiallyInitializedThis( obj: ConstructorPassesThisOut, dt: Date, ev: AllTypesEnum, ): string; } export class ConstructorPassesThisOut { public constructor(consumer: PartiallyInitializedThisConsumer) { const result = consumer.consumePartiallyInitializedThis( this, new Date(0), AllTypesEnum.THIS_IS_GREAT, ); if (result !== 'OK') { throw new Error(`Expected OK but received ${result}`); } } } // // Consumes a possibly empty struct and verifies it is turned to undefined when passed // See: https://github.com/aws/jsii/issues/411 // export class OptionalStructConsumer { public readonly parameterWasUndefined: boolean; public readonly fieldValue?: string; public constructor(optionalStruct?: OptionalStruct) { this.parameterWasUndefined = optionalStruct === undefined; this.fieldValue = optionalStruct && optionalStruct.field; } } export interface OptionalStruct { readonly field?: string; } /** * This class has docs. * * The docs are great. They're a bunch of tags. * * @example * * function anExample() { * } * * @see https://aws.amazon.com/ * @customAttribute hasAValue * @stable */ export class ClassWithDocs {} /** * This is used to validate the ability to use `this` from within a static context. * * https://github.com/awslabs/aws-cdk/issues/2304 */ export class StaticContext { private static _staticVariable = true; public static canAccessStaticContext(): boolean { return this.staticContextAvailable(); } private static staticContextAvailable() { return true; } public static get staticVariable() { return this._staticVariable; } public static set staticVariable(value: boolean) { this._staticVariable = value; } private constructor() {} } /** * This test is used to validate the runtimes can return correctly from a void callback. * * - Implement `overrideMe` (method does not have to do anything). * - Invoke `callMe` * - Verify that `methodWasCalled` is `true`. */ export abstract class VoidCallback { private _methodWasCalled = false; public get methodWasCalled(): boolean { return this._methodWasCalled; } public callMe(): void { this.overrideMe(); this._methodWasCalled = true; } protected abstract overrideMe(): void; } /** * Verifies that private property declarations in constructor arguments are hidden. */ export class WithPrivatePropertyInConstructor { public constructor(private readonly privateField: string = 'Success!') {} public get success() { return this.privateField === 'Success!'; } } /** * Verifies that singleton enums are handled correctly * * https://github.com/aws/jsii/issues/231 */ export class SingletonString { private constructor() {} public isSingletonString(value: string): boolean { return value === SingletonStringEnum.SINGLETON_STRING.valueOf(); } } /** A singleton string */ export enum SingletonStringEnum { /** 1337 */ SINGLETON_STRING = '3L1T3!', } /** * Verifies that singleton enums are handled correctly * * https://github.com/aws/jsii/issues/231 */ export class SingletonInt { private constructor() {} public isSingletonInt(value: number): boolean { return value === SingletonIntEnum.SINGLETON_INT.valueOf(); } } /** A singleton integer. */ export enum SingletonIntEnum { /** Elite! */ SINGLETON_INT = 1337, } /** * Verifies proper type handling through dynamic overrides. */ export class DataRenderer { public render( data: MyFirstStruct = { anumber: 42, astring: 'bazinga!' }, ): string { return this.renderMap(data); } public renderArbitrary(data: { [key: string]: any }): string { return this.renderMap(data); } public renderMap(map: { [key: string]: any }): string { return JSON.stringify(map, null, 2); } } export interface TopLevelStruct { /** * This is a required field */ readonly required: string; /** * You don't have to pass this */ readonly optional?: string; /** * A union to really stress test our serialization */ readonly secondLevel: SecondLevelStruct | number; } export interface SecondLevelStruct { /** * It's long and required */ readonly deeperRequiredProp: string; /** * It's long, but you'll almost never pass it. */ readonly deeperOptionalProp?: string; } export interface DiamondInheritanceBaseLevelStruct { readonly baseLevelProperty: string; } export interface DiamondInheritanceFirstMidLevelStruct extends DiamondInheritanceBaseLevelStruct { readonly firstMidLevelProperty: string; } export interface DiamondInheritanceSecondMidLevelStruct extends DiamondInheritanceBaseLevelStruct { readonly secondMidLevelProperty: string; } export interface DiamondInheritanceTopLevelStruct extends DiamondInheritanceFirstMidLevelStruct, DiamondInheritanceSecondMidLevelStruct { readonly topLevelProperty: string; } export interface StructWithJavaReservedWords { readonly default: string; readonly assert?: string; // These properties are designed to break the naive implementation of equals() and hashcode() using the standard template readonly result?: string; readonly that?: string; } export class ClassWithJavaReservedWords { public readonly int: string; public constructor(int: string) { this.int = int; } public import(assert: string): string { return this.int + assert; } } /** * Just because we can. * * @stability external */ export class StructPassing { public static roundTrip( _positional: number, input: TopLevelStruct, ): TopLevelStruct { return { required: input.required, optional: input.optional, secondLevel: input.secondLevel, }; } public static howManyVarArgsDidIPass( _positional: number, ...inputs: TopLevelStruct[] ): number { return inputs.length; } } /** * We can return arrays of interfaces * See aws/aws-cdk#2362 */ export class InterfacesMaker { public static makeInterfaces(count: number): IDoublable[] { const output = new Array<IDoublable>(); for (let i = 0; i < count; i++) { output.push({ doubleValue: i * 2 }); } return output; } private constructor() {} } export class ClassWithCollections { public map: { [key: string]: string }; public array: string[]; public static staticMap: { [key: string]: string } = { key1: 'value1', key2: 'value2', }; public static staticArray: string[] = ['one', 'two']; public constructor(map: { [key: string]: string }, array: string[]) { this.map = map; this.array = array; } public static createAList(): string[] { return ['one', 'two']; } public static createAMap(): { [key: string]: string } { return { key1: 'value1', key2: 'value2' }; } } /** * @see https://github.com/aws/jsii/issues/903 */ export class OverridableProtectedMember { protected readonly overrideReadOnly: string = 'Baz'; protected overrideReadWrite = 'zinga!'; public valueFromProtected(): string { return this.overrideMe(); } public switchModes(): void { this.overrideReadWrite = 'zaar...'; } protected overrideMe(): string { return this.overrideReadOnly + this.overrideReadWrite; } } /** * We can generate fancy builders in Java for classes which take a mix of positional & struct parameters */ export class SupportsNiceJavaBuilderWithRequiredProps { public readonly propId?: string; public readonly bar: number; /** * @param id some identifier of your choice * @param props some properties */ public constructor( public readonly id: number, props: SupportsNiceJavaBuilderProps, ) { this.propId = props.id; this.bar = props.bar; } } export class SupportsNiceJavaBuilder extends SupportsNiceJavaBuilderWithRequiredProps { public readonly rest: string[]; /** * * @param id some identifier * @param defaultBar the default value of `bar` * @param props some props once can provide * @param rest a variadic continuation */ public constructor( public readonly id: number, defaultBar = 1337, props?: SupportsNiceJavaBuilderProps, ...rest: string[] ) { super(id, props ?? { bar: defaultBar }); this.rest = rest; } } export interface SupportsNiceJavaBuilderProps { /** * An `id` field here is terrible API design, because the constructor of `SupportsNiceJavaBuilder` already has a * parameter named `id`. But here we are, doing it like we didn't care. */ readonly id?: string; /** * Some number, like 42. */ readonly bar: number; } /** * We can return an anonymous interface implementation from an override without losing the interface * declarations. */ export interface IAnonymousImplementationProvider { provideAsInterface(): IAnonymouslyImplementMe; provideAsClass(): Implementation; } export class AnonymousImplementationProvider implements IAnonymousImplementationProvider { private readonly instance = new PrivateType(); public provideAsClass(): Implementation { return this.instance; } public provideAsInterface(): IAnonymouslyImplementMe { return this.instance; } } export class Implementation { public readonly value = 1337; } export interface IAnonymouslyImplementMe { readonly value: number; verb(): string; } class PrivateType extends Implementation implements IAnonymouslyImplementMe { public verb() { return 'to implement'; } } /** * We can serialize and deserialize structs without silently ignoring optional fields. */ export interface StructA { readonly requiredString: string; readonly optionalString?: string; readonly optionalNumber?: number; } /** * This intentionally overlaps with StructA (where only requiredString is provided) to test htat * the kernel properly disambiguates those. */ export interface StructB { readonly requiredString: string; readonly optionalBoolean?: boolean; readonly optionalStructA?: StructA; } export class StructUnionConsumer { public static isStructA(struct: StructA | StructB): struct is StructA { const keys = new Set(Object.keys(struct)); switch (keys.size) { case 1: return keys.has('requiredString'); case 2: return ( keys.has('requiredString') && (keys.has('optionalNumber') || keys.has('optionalString')) ); case 3: return ( keys.has('requiredString') && keys.has('optionalNumber') && keys.has('optionalString') ); default: return false; } } public static isStructB(struct: StructA | StructB): struct is StructB { const keys = new Set(Object.keys(struct)); switch (keys.size) { case 1: return keys.has('requiredString'); case 2: return ( keys.has('requiredString') && (keys.has('optionalBoolean') || keys.has('optionalStructA')) ); case 3: return ( keys.has('requiredString') && keys.has('optionalBoolean') && keys.has('optionalStructA') ); default: return false; } } public static provideStruct(which: 'A' | 'B'): StructA | StructB { switch (which) { case 'A': return { requiredString: 'required', optionalNumber: 1337 }; case 'B': return { requiredString: 'required', optionalStructA: this.provideStruct('A'), }; default: throw new Error(`Illegal value for which: ${which as any}`); } } private constructor() {} } /** * Test calling back to consumers that implement interfaces * * Check that if a JSII consumer implements IConsumerWithInterfaceParam, they can call * the method on the argument that they're passed... */ export class ConsumerCanRingBell { /** * ...if the interface is implemented using an object literal. * * Returns whether the bell was rung. */ public static staticImplementedByObjectLiteral(ringer: IBellRinger) { let rung = false; ringer.yourTurn({ ring() { rung = true; }, }); return rung; } /** * ...if the interface is implemented using a public class. * * Return whether the bell was rung. */ public static staticImplementedByPublicClass(ringer: IBellRinger) { const bell = new Bell(); ringer.yourTurn(bell); return bell.rung; } /** * ...if the interface is implemented using a private class. * * Return whether the bell was rung. */ public static staticImplementedByPrivateClass(ringer: IBellRinger) { const bell = new PrivateBell(); ringer.yourTurn(bell); return bell.rung; } /** * If the parameter is a concrete class instead of an interface * * Return whether the bell was rung. */ public static staticWhenTypedAsClass(ringer: IConcreteBellRinger) { const bell = new Bell(); ringer.yourTurn(bell); return bell.rung; } /** * ...if the interface is implemented using an object literal. * * Returns whether the bell was rung. */ public implementedByObjectLiteral(ringer: IBellRinger) { let rung = false; ringer.yourTurn({ ring() { rung = true; }, }); return rung; } /** * ...if the interface is implemented using a public class. * * Return whether the bell was rung. */ public implementedByPublicClass(ringer: IBellRinger) { const bell = new Bell(); ringer.yourTurn(bell); return bell.rung; } /** * ...if the interface is implemented using a private class. * * Return whether the bell was rung. */ public implementedByPrivateClass(ringer: IBellRinger) { const bell = new PrivateBell(); ringer.yourTurn(bell); return bell.rung; } /** * If the parameter is a concrete class instead of an interface * * Return whether the bell was rung. */ public whenTypedAsClass(ringer: IConcreteBellRinger) { const bell = new Bell(); ringer.yourTurn(bell); return bell.rung; } } /** * Takes the object parameter as an interface */ export interface IBellRinger { yourTurn(bell: IBell): void; } /** * Takes the object parameter as a calss */ export interface IConcreteBellRinger { yourTurn(bell: Bell): void; } export interface IBell { ring(): void; } export class Bell implements IBell { public rung = false; public ring() { this.rung = true; } } class PrivateBell implements IBell { public rung = false; public ring() { this.rung = true; } } /** * This is here to check that we can pass a nested struct into a kwargs by specifying it as an * in-line dictionary. This is cheating with the (current) declared types, but this is the "more * idiomatic" way for Pythonists. */ export interface RootStruct { /** * May not be empty. */ readonly stringProp: string; readonly nestedStruct?: NestedStruct; } export interface NestedStruct { /** * When provided, must be > 0. */ readonly numberProp: number; } export class RootStructValidator { public static validate(struct: RootStruct): void { if (!struct.stringProp) { throw new Error('Missing required field: stringProp'); } if (struct.nestedStruct) { if (struct.nestedStruct.numberProp <= 0) { throw new Error('numberProp must be > 0'); } } } private constructor() {} } /** * Returns a subclass of a known class which implements an interface. */ export interface IReturnJsii976 { readonly foo: number; } export class BaseJsii976 {} export class SomeTypeJsii976 { public static returnReturn(): IReturnJsii976 { class Derived extends BaseJsii976 implements IReturnJsii976 { public readonly foo = 333; } return new Derived(); } public static returnAnonymous(): any { class Derived implements IReturnJsii976 { public readonly foo = 1337; } return new Derived(); } } /** https://github.com/aws/jsii/issues/982 */ export interface ParentStruct982 { readonly foo: string; } export interface ChildStruct982 extends ParentStruct982 { readonly bar: number; } /** * 1. call #takeThis() -> An ObjectRef will be provisioned for the value (it'll be re-used!) * 2. call #takeThisToo() -> The ObjectRef from before will need to be down-cased to the ParentStruct982 type */ export class Demonstrate982 { private static readonly value = { foo: 'foo', bar: 1337, }; /** It's dangerous to go alone! */ public static takeThis(): ChildStruct982 { return this.value; } /** It's dangerous to go alone! */ public static takeThisToo(): ParentStruct982 { return this.value; } } /** * Verifies that null/undefined can be returned for optional collections. * * This source of collections is disappointing - it'll always give you nothing :( */ export class DisappointingCollectionSource { /** Some List of strings, maybe? (Nah, just a billion dollars mistake!) */ public static readonly maybeList?: string[] = undefined; /** Some Map of strings to numbers, maybe? (Nah, just a billion dollars mistake!) */ public static readonly maybeMap?: { [key: string]: number } = undefined; private constructor() {} } /** * Make sure that setters are properly called on objects with interfaces */ export interface IObjectWithProperty { property: string; wasSet(): boolean; } export class ObjectWithPropertyProvider { public static provide(): IObjectWithProperty { class Impl implements IObjectWithProperty { private _property = ''; private _wasSet = false; public get property() { return this._property; } public set property(value: string) { this._property = value; this._wasSet = true; } public wasSet() { return this._wasSet; } } return new Impl(); } private constructor() {} } /** * Make sure structs are un-decorated on the way in. * * @see https://github.com/aws/aws-cdk/issues/5066 */ export class JsonFormatter { public static stringify(value?: any): string | undefined { return JSON.stringify(value, null, 2); } public static anyNull(): any { return null; } public static anyUndefined(): any { return undefined; } public static anyFunction(): any { return () => 'boom'; } public static anyDate(): any { return new Date('2019-11-18T13:01:20.515Z'); } public static anyNumber(): any { return 123; } public static anyZero(): any { return 0; } public static anyString(): any { return 'foo'; } public static anyEmptyString(): any { return ''; } public static anyBooleanTrue(): any { return true; } public static anyBooleanFalse(): any { return false; } public static anyArray(): any { return [1, 2, 3, new LibNumber(123), { foo: 'bar' }]; } public static anyHash(): any { return { hello: 1234, world: new LibNumber(122) }; } public static anyRef(): any { return new LibNumber(444); } private constructor() {} } /** * This tries to confuse Jackson by having overloaded property setters. * * @see https://github.com/aws/aws-cdk/issues/4080 */ export class ConfusingToJackson { public static makeInstance(): ConfusingToJackson { return new ConfusingToJackson(); } public static makeStructInstance(): ConfusingToJacksonStruct { return {}; } public unionProperty?: Array<IFriendly | AbstractClass> | IFriendly; private constructor() {} } export interface ConfusingToJacksonStruct { readonly unionProperty?: Array<IFriendly | AbstractClass> | IFriendly; } /** * Verifies that a "pure" implementation of an interface works correctly */ export interface IStructReturningDelegate { returnStruct(): StructB; } export class ConsumePureInterface { public constructor(private readonly delegate: IStructReturningDelegate) {} public workItBaby() { return this.delegate.returnStruct(); } } /** * Verifies that, in languages that do keyword lifting (e.g: Python), having a * struct member with the same name as a positional parameter results in the * correct code being emitted. * * See: https://github.com/aws/aws-cdk/issues/4302 */ export interface StructParameterType { readonly scope: string; readonly props?: boolean; } export class AmbiguousParameters { public constructor( public readonly scope: Bell, public readonly props: StructParameterType, ) {} } /** * Verifies that collections of interfaces or structs are correctly handled. * * See: https://github.com/aws/jsii/issues/1196 */ export class InterfaceCollections { public static listOfStructs(): StructA[] { return [{ requiredString: "Hello, I'm String!" }]; } public static mapOfStructs(): { [name: string]: StructA } { return { A: { requiredString: "Hello, I'm String!" }, }; } public static listOfInterfaces(): IBell[] { return [ { ring: () => { return; }, }, ]; } public static mapOfInterfaces(): { [name: string]: IBell } { return { A: { ring: () => { return; }, }, }; } private constructor() {} } /** * Checks that optional result from interface method code generates correctly */ export interface IOptionalMethod { optional(): string | undefined; } /** * Checks the "same instance" isomorphism is preserved within the constructor. * * Create a subclass of this, and assert that `this.myself()` actually returns * `this` from within the constructor. */ export abstract class Isomorphism { public myself(): Isomorphism { return this; } } /** * Checks the current file permissions are cool (no funky UMASK down-scoping happened) * * @see https://github.com/aws/jsii/issues/1765 */ export class UmaskCheck { /** * This should return 0o644 (-rw-r--r--) */ public static mode(): number { // The bit-masking is to remove the file type information from .mode return fs.statSync(__filename).mode & 0o0777; } private constructor() {} } /** * See https://github.com/aws/aws-cdk/issues/7977 */ export abstract class BurriedAnonymousObject { public check(): boolean { const anonymousObject = { method() { return true; }, }; const result = this.giveItBack({ anonymousObject }); return anonymousObject === result.anonymousObject; } /** * Implement this method and have it return it's parameter. * * @param value the value that should be returned. * * @returns `value` */ public abstract giveItBack(value: any): any; } /** * Ensures we can override a dynamic property that was inherited. */ export class DynamicPropertyBearer { public constructor(public valueStore: string) {} public get dynamicProperty(): string { return this.valueStore; } public set dynamicProperty(value: string) { this.valueStore = value; } } export class DynamicPropertyBearerChild extends DynamicPropertyBearer { public constructor(public readonly originalValue: string) { super(originalValue); } /** * Sets `this.dynamicProperty` to the new value, and returns the old value. * * @param newValue the new value to be set. * * @returns the old value that was set. */ public overrideValue(newValue: string): string { const oldValue = this.dynamicProperty; this.dynamicProperty = newValue; return oldValue; } } /** * Validates that nested classes get correct code generation for the occasional * forward reference. */ export class LevelOne { public constructor(public readonly props: LevelOneProps) {} } export interface LevelOneProps { readonly prop: LevelOne.PropProperty; } export namespace LevelOne { export interface PropProperty { readonly prop: PropBooleanValue; } export interface PropBooleanValue { readonly value: boolean; } } /** * Static methods that override parent class are technically overrides (the * inheritance of statics is part of the ES6 specification), but certain other * languages such as Java do not carry statics in the inheritance chain at all, * so they cannot be overridden, only hidden. * * The difference is fairly minor (for typical use-cases, the end result is the * same), however this has implications on what the generated code should look * like. */ export class StaticHelloParent { public static get property(): number { return 1337; } public static method(): void { /* A static method */ } } export class StaticHelloChild extends StaticHelloParent { public static get property(): number { return 42; } public static method(): void { /* An ES6 Override */ } private constructor() { super(); } } // -------------------------------------------------- // enums within structs export interface StructWithEnum { /** * An enum value */ readonly foo: StringEnum; /** * Optional enum value (of type integer) * @default AllTypesEnum.YOUR_ENUM_VALUE */ readonly bar?: AllTypesEnum; } export class TestStructWithEnum { /** * Returns true if `foo` is `StringEnum.A`. */ public isStringEnumA(input: StructWithEnum) { return input.foo === StringEnum.A && !input.bar; } /** * Returns true if `foo` is `StringEnum.B` and `bar` is `AllTypesEnum.THIS_IS_GREAT`. */ public isStringEnumB(input: StructWithEnum) { return ( input.foo === StringEnum.B && input.bar === AllTypesEnum.THIS_IS_GREAT ); } /** * Returns `foo: StringEnum.C` and `bar: AllTypesEnum.MY_ENUM_VALUE`. */ public get structWithFooBar(): StructWithEnum { return { foo: StringEnum.C, bar: AllTypesEnum.MY_ENUM_VALUE, }; } /** * Returns `foo: StringEnum.A`. */ public get structWithFoo(): StructWithEnum { return { foo: StringEnum.A, }; } } /** * Docstrings with period * @see https://github.com/aws/jsii/issues/2638 */ export class Issue2638 { /** * First sentence. Second sentence. Third sentence. */ public constructor() { return; } } export class Issue2638B { public constructor() { return; // no docs } } /** * A class named "Default" * * @see https://github.com/aws/jsii/issues/2637 */ export class Default { public pleaseCompile() { return; } } /** * In TypeScript it is possible to have two methods with the same name but * different capitalization. * * @see https://github.com/aws/jsii/issues/2508 */ export class TwoMethodsWithSimilarCapitalization { public toIsoString() { return 'toIsoString'; } /** * @deprecated python requires that all alternatives are deprecated */ public toISOString() { return 'toISOString'; } /** * @deprecated python requires that all alternatives are deprecated */ public toIsOString() { return 'toIsoString'; } public readonly fooBar = 123; /** * @deprecated YES */ public readonly fooBAR = 111; } export class ClassWithCollectionOfUnions { public constructor( public unionProperty: Array<Record<string, StructA | StructB>>, ) {} } export interface StructWithCollectionOfUnionts { readonly unionProperty: Array<Record<string, StructA | StructB>>; } export class ClassWithNestedUnion { public constructor( public unionProperty: Array< Array<StructA | StructB> | Record<string, StructA | StructB> >, ) {} } export class VariadicTypeUnion { public union: Array<StructA | StructB>; public constructor(...union: Array<StructA | StructB>) { this.union = union; } } /** * Validate that namespaces being shadowed by local variables does not cause * type checking issues. * * @see https://github.com/aws/aws-cdk/issues/22975 */ export class ParamShadowsScope { // @scope/* packages are under the "scope." namespace in Python. public useScope(scope: LibNumber) { return scope; } } /** * Validate that parameters named "str" or "builtins" do not shadow the actual * type names in Python. */ export class ParamShadowsBuiltins { /** * @param builtins should be set to something that is NOT a valid expression in Python (e.g: "${NOPE}"") * @param str should be set to something that is NOT a valid expression in Python (e.g: "${NOPE}"") * @param props should be set to valid values. */ public constructor( builtins: string, str: string, props: ParamShadowsBuiltinsProps, ) { this.consumeArgs(builtins, str, props); } private consumeArgs(..._args: unknown[]) { return; } } export interface ParamShadowsBuiltinsProps { readonly stringProperty: string; readonly booleanProperty: boolean; readonly structProperty: StructA; } export class PromiseNothing { public static async promiseIt(): Promise<void> { return Promise.resolve(); } public async instancePromiseIt(): Promise<void> { return PromiseNothing.promiseIt(); } } export class AnyPropertyAccess { /** * Sets obj[resultProp] to `${obj[propA]}+${obj[propB]}`. * * @param obj the receiver object. * @param propA the first property to read. * @param propB the second property to read. * @param resultProp the property to write into. */ public static mutateProperties( obj: any, propA: string, propB: string, resultProp: string, ) { obj[resultProp] = `${obj[propA]}+${obj[propB]}`; } private constructor() {} }