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() {}
}