Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
function _inehritanceDoesNotChangeContracts(validator: Validator, assembly: spec.Assembly, diagnostic: DiagnosticEmitter) {
for (const type of _allTypes(assembly)) {
if (spec.isClassType(type)) {
for (const method of type.methods ?? []) {
_validateMethodOverride(method, type);
}
for (const property of type.properties ?? []) {
_validatePropertyOverride(property, type);
}
}
if (spec.isClassOrInterfaceType(type) && (type.interfaces?.length ?? 0) > 0) {
for (const method of type.methods ?? []) {
// Overrides "win" over implementations
if (method.overrides) { continue; }
_validateMethodImplementation(method, type);
}
for (const property of type.properties ?? []) {
_validatePropertyImplementation(property, type);
}
function isAssignable(actualTypeFqn: string, requiredType: spec.NamedTypeReference, lookup: TypeLookup): boolean {
// The empty object is assignable to everything
if (actualTypeFqn === EMPTY_OBJECT_FQN) { return true; }
if (requiredType.fqn === actualTypeFqn) {
return true;
}
const actualType = lookup(actualTypeFqn);
if (spec.isClassType(actualType)) {
if (actualType.base && isAssignable(actualType.base, requiredType, lookup)) {
return true;
}
}
if (spec.isClassOrInterfaceType(actualType) && actualType.interfaces) {
return actualType.interfaces.find(iface => isAssignable(iface, requiredType, lookup)) != null;
}
return false;
}
function _validateMethodImplementation(method: spec.Method, type: spec.ClassType | spec.InterfaceType): boolean {
if (!type.interfaces) {
// Abstract classes may not directly implement all members, need to check their supertypes...
if (spec.isClassType(type) && type.base && type.abstract) {
return _validateMethodImplementation(method, _dereference(type.base, assembly, validator) as spec.ClassType);
}
return false;
}
for (const iface of type.interfaces) {
const ifaceType = _dereference(iface, assembly, validator) as spec.InterfaceType;
const implemented = (ifaceType.methods ?? []).find(m => m.name === method.name);
if (implemented) {
_assertSignaturesMatch(implemented, method, `${type.fqn}#${method.name}`, `implementing ${ifaceType.fqn}`);
method.overrides = iface;
return true;
}
if (_validateMethodImplementation(method, ifaceType)) {
return true;
}
}
private _tryTypeInfoForProperty(property: string, classFqn: string, interfaces: string[] = []): spec.Property | undefined {
for (const fqn of [classFqn, ...interfaces]) {
if (fqn === wire.EMPTY_OBJECT_FQN) { continue; }
const typeInfo = this._typeInfoForFqn(fqn);
let properties;
let bases;
if (spec.isClassType(typeInfo)) {
const classTypeInfo = typeInfo as spec.ClassType;
properties = classTypeInfo.properties;
bases = classTypeInfo.base ? [classTypeInfo.base] : [];
} else if (spec.isInterfaceType(typeInfo)) {
const interfaceTypeInfo = typeInfo as spec.InterfaceType;
properties = interfaceTypeInfo.properties;
bases = interfaceTypeInfo.interfaces ?? [];
} else {
throw new Error(`Type of kind ${typeInfo.kind} does not have properties`);
}
for (const p of properties ?? []) {
if (p.name === property) {
return p;
}
}
function propertiesOf(t: spec.Type, lookup: TypeLookup): {[name: string]: spec.Property} {
if (!spec.isClassOrInterfaceType(t)) { return {}; }
let ret: { [name: string]: spec.Property } = {};
if (t.interfaces) {
for (const iface of t.interfaces) {
ret = { ...ret, ...propertiesOf(lookup(iface), lookup) };
}
}
if (spec.isClassType(t) && t.base) {
ret = { ...ret, ...propertiesOf(lookup(t.base), lookup) };
}
for (const prop of t.properties ?? []) {
ret[prop.name] = prop;
}
return ret;
}
this._deferUntilTypesAvailable(fqn, [ref], base.symbol.valueDeclaration, (deref) => {
if (!spec.isClassType(deref)) {
this._diagnostic(base.symbol.valueDeclaration,
ts.DiagnosticCategory.Error,
`Base type of ${jsiiType.fqn} is not a class (${spec.describeTypeReference(ref)})`);
}
});
jsiiType.base = ref.fqn;