@opra/common
Version:
Opra common package
134 lines (133 loc) • 4.77 kB
JavaScript
import 'reflect-metadata';
import { omitUndefined } from '@jsopen/objects';
import { asMutable } from 'ts-gems';
import { isAny } from 'valgen';
import { cloneObject } from '../../helpers/index.js';
import { OpraSchema } from '../../schema/index.js';
import { DECORATOR } from '../constants.js';
import { AttributeDecoratorFactory, SimpleTypeDecoratorFactory, } from '../decorators/simple-type.decorator.js';
import { DataType } from './data-type.js';
/**
* SimpleType constructor
*/
export const SimpleType = function (...args) {
// Decorator
if (!this)
return SimpleType[DECORATOR](...args);
// Constructor
const [owner, initArgs, context] = args;
DataType.call(this, owner, initArgs, context);
const _this = asMutable(this);
_this.kind = OpraSchema.SimpleType.Kind;
if (initArgs.base) {
// noinspection SuspiciousTypeOfGuard
if (!(initArgs.base instanceof SimpleType)) {
throw new TypeError(`"${initArgs.base.kind}" can't be set as base for a "${this.kind}"`);
}
_this.base = initArgs.base;
}
_this.properties = initArgs.properties;
_this.ownNameMappings = { ...initArgs.nameMappings };
_this.nameMappings = {
..._this.base?.nameMappings,
...initArgs.nameMappings,
};
_this.ownAttributes = cloneObject(initArgs.attributes || {});
_this.attributes = _this.base ? cloneObject(_this.base.attributes) : {};
if (_this.ownAttributes) {
for (const [k, el] of Object.entries(_this.ownAttributes)) {
if (_this.attributes[k]?.sealed)
throw new TypeError(`Sealed attribute "${k}" can not be overwritten`);
_this.attributes[k] = el;
}
}
_this._generateDecoder = initArgs.generateDecoder;
_this._generateEncoder = initArgs.generateEncoder;
};
/**
*
* @class SimpleType
*/
class SimpleTypeClass extends DataType {
_generateDecoder;
_generateEncoder;
properties;
extend(properties) {
Object.setPrototypeOf(properties, this);
return properties;
}
extendsFrom(baseType) {
if (!(baseType instanceof DataType))
baseType = this.node.getDataType(baseType);
if (!(baseType instanceof SimpleType))
return false;
if (baseType === this)
return true;
return !!this.base?.extendsFrom(baseType);
}
generateCodec(codec, options, properties) {
const prop = {
...this.properties,
...properties,
};
if (codec === 'decode') {
let t = this;
while (t) {
if (t._generateDecoder)
return t._generateDecoder(prop, {
dataType: this,
element: options?.documentElement || this.owner,
scope: options?.scope,
});
t = this.base;
}
return isAny;
}
let t = this;
while (t) {
if (t._generateEncoder)
return t._generateEncoder(prop, {
dataType: this,
element: options?.documentElement || this.owner,
scope: options?.scope,
});
t = this.base;
}
return isAny;
}
toJSON(options) {
const superJson = super.toJSON(options);
const baseName = this.base
? this.node.getDataTypeNameWithNs(this.base)
: undefined;
const attributes = omitUndefined(this.ownAttributes);
let properties;
if (this.properties && typeof this.properties.toJSON === 'function') {
properties = this.properties.toJSON(this.properties, this.owner, options);
}
else
properties = this.properties ? cloneObject(this.properties) : {};
const out = {
...superJson,
kind: this.kind,
base: baseName,
attributes: attributes && Object.keys(attributes).length ? attributes : undefined,
properties: Object.keys(properties).length ? properties : undefined,
};
if (Object.keys(this.ownNameMappings).length)
out.nameMappings = { ...this.ownNameMappings };
return omitUndefined(out, true);
}
_locateBase(callback) {
if (!this.base)
return;
if (callback(this.base))
return this.base;
if (this.base._locateBase)
return this.base._locateBase(callback);
}
}
SimpleType.prototype = SimpleTypeClass.prototype;
Object.assign(SimpleType, SimpleTypeDecoratorFactory);
SimpleType[DECORATOR] = SimpleTypeDecoratorFactory;
SimpleType.Attribute = AttributeDecoratorFactory;