packages/jsii-reflect/lib/interface.ts (92 lines of code) (raw):

import * as jsii from '@jsii/spec'; import { Assembly } from './assembly'; import { Method } from './method'; import { Property } from './property'; import { ReferenceType } from './reference-type'; import { TypeSystem } from './type-system'; export class InterfaceType extends ReferenceType { /** Caches the result of `getInterfaces`. */ // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility readonly #interfaces = new Map<boolean, readonly InterfaceType[]>(); public constructor( public system: TypeSystem, public assembly: Assembly, public readonly spec: jsii.InterfaceType, ) { super(system, assembly, spec); } /** * True if this interface only contains properties. Different backends might * have idiomatic ways to allow defining concrete instances such interfaces. * For example, in Java, the generator will produce a PoJo and a builder * which will allow users to create a concrete object with data which * adheres to this interface. */ public get datatype(): boolean { return this.isDataType(); } /** * Lists all interfaces this interface extends. * @param inherited include all interfaces implemented by all super interfaces (default: false) */ public getInterfaces(inherited = false): InterfaceType[] { if (!this.spec.interfaces) { return []; } if (this.#interfaces.has(inherited)) { return Array.from(this.#interfaces.get(inherited)!); } const result = new Set<InterfaceType>(); for (const iface of this.spec.interfaces) { const ifaceType = this.system.findInterface(iface); if (!result.has(ifaceType) && inherited) { ifaceType.getInterfaces(inherited).forEach((i) => result.add(i)); } result.add(ifaceType); } this.#interfaces.set(inherited, Array.from(result)); // Returning a copy of the array, distinct from the one we memoized, for safety. return Array.from(result); } /** * Lists all properties in this class. * @param inherited include all properties inherited from base classes (default: false) */ public getProperties(inherited = false): { [name: string]: Property } { return Object.fromEntries(this._getProperties(inherited, this)); } /** * List all methods in this class. * @param inherited include all methods inherited from base classes (default: false) */ public getMethods(inherited = false): { [name: string]: Method } { return Object.fromEntries(this._getMethods(inherited, this)); } public isDataType(): this is InterfaceType { return !!this.spec.datatype; } public isInterfaceType(): this is InterfaceType { return true; } private _getProperties( inherited: boolean, parentType: ReferenceType, ): Map<string, Property> { const result = new Map<string, Property>(); if (inherited) { for (const parent of this.getInterfaces()) { for (const [key, value] of parent._getProperties( inherited, parentType, )) { result.set(key, value); } } } for (const p of this.spec.properties ?? []) { result.set( p.name, new Property(this.system, this.assembly, parentType, this, p), ); } return result; } private _getMethods( inherited: boolean, parentType: ReferenceType, ): Map<string, Method> { const methods = new Map<string, Method>(); if (inherited) { for (const parent of this.getInterfaces()) { for (const [key, value] of parent._getMethods(inherited, parentType)) { methods.set(key, value); } } } for (const m of this.spec.methods ?? []) { methods.set( m.name, new Method(this.system, this.assembly, parentType, this, m), ); } return methods; } }