@opra/common
Version:
Opra common package
125 lines (124 loc) • 4.55 kB
JavaScript
import 'reflect-metadata';
import { omitUndefined } from '@jsopen/objects';
import { asMutable } from 'ts-gems';
import { OpraSchema } from '../../schema/index.js';
import { DocumentInitContext } from '../common/document-init-context.js';
import { DECORATOR } from '../constants.js';
import { ComplexTypeDecorator } from '../decorators/complex-type.decorator.js';
import { ApiField } from './api-field.js';
import { ComplexTypeBase } from './complex-type-base.js';
import { DataType } from './data-type.js';
/**
* ComplexType constructor
*/
export const ComplexType = function (...args) {
// Decorator
if (!this)
return ComplexType[DECORATOR].apply(undefined, args);
// Constructor
const [owner, initArgs] = args;
const context = args[2] || new DocumentInitContext({ maxErrors: 0 });
ComplexTypeBase.call(this, owner, initArgs, context);
const _this = asMutable(this);
_this.kind = OpraSchema.ComplexType.Kind;
_this.discriminatorField = initArgs.discriminatorField;
_this.discriminatorValue = initArgs.discriminatorValue;
if (initArgs.base) {
context.enter('.base', () => {
// noinspection SuspiciousTypeOfGuard
if (!(initArgs.base instanceof ComplexTypeBase)) {
throw new TypeError(`"${initArgs.base.kind}" can't be set as base for a "${this.kind}"`);
}
_this.base = initArgs.base;
_this.additionalFields = _this.base.additionalFields;
_this.keyField = _this.base.keyField;
/** Copy fields from base */
for (const v of _this.base.fields('*')) {
_this._fields.set(v.name, new ApiField(this, v));
}
});
}
if (initArgs.additionalFields !== undefined)
_this.additionalFields = initArgs.additionalFields;
if (initArgs.keyField !== undefined)
_this.keyField = initArgs.keyField;
_this.ctor = initArgs.ctor || _this.base?.ctor;
/** Add own fields */
if (initArgs.fields) {
context.enter('.fields', () => {
for (const [k, v] of Object.entries(initArgs.fields)) {
const field = new ApiField(this, {
...v,
name: k,
});
this._fields.set(field.name, field);
}
});
}
};
/**
*
* @class ComplexType
*/
class ComplexTypeClass extends ComplexTypeBase {
extendsFrom(baseType) {
if (!(baseType instanceof DataType))
baseType = this.node.getDataType(baseType);
if (!(baseType instanceof ComplexTypeBase))
return false;
if (baseType === this)
return true;
return !!this.base?.extendsFrom(baseType);
}
toJSON(options) {
const superJson = super.toJSON(options);
const baseName = this.base
? this.node.getDataTypeNameWithNs(this.base)
: undefined;
const out = {
...superJson,
kind: this.kind,
base: this.base
? baseName
? baseName
: this.base.toJSON(options)
: undefined,
discriminatorField: this.discriminatorField,
discriminatorValue: this.discriminatorValue,
};
if (this.additionalFields) {
if (this.additionalFields instanceof DataType) {
const typeName = this.node.getDataTypeNameWithNs(this.additionalFields);
out.additionalFields = typeName
? typeName
: this.additionalFields.toJSON(options);
}
else
out.additionalFields = this.additionalFields;
}
if (this._fields.size) {
const fields = {};
let i = 0;
for (const field of this._fields.values()) {
if (field.origin === this && field.inScope(options?.scope)) {
fields[field.name] = field.toJSON(options);
i++;
}
}
if (i)
out.fields = fields;
}
return omitUndefined(out);
}
_locateBase(callback) {
if (!this.base)
return;
if (callback(this.base))
return this.base;
if (this.base._locateBase)
return this.base._locateBase(callback);
}
}
ComplexType.prototype = ComplexTypeClass.prototype;
Object.assign(ComplexType, ComplexTypeDecorator);
ComplexType[DECORATOR] = ComplexTypeDecorator;