UNPKG

@opra/common

Version:
134 lines (133 loc) 4.77 kB
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;