UNPKG

@opra/common

Version:
122 lines (121 loc) 3.98 kB
import 'reflect-metadata'; import { omitUndefined } from '@jsopen/objects'; import { asMutable } from 'ts-gems'; import { vg } from 'valgen'; import { cloneObject } from '../../helpers/index.js'; import { OpraSchema } from '../../schema/index.js'; import { DATATYPE_METADATA, DECORATOR } from '../constants.js'; import { DataType } from './data-type.js'; /** * @class EnumType */ export const EnumType = function (...args) { // Injector if (!this) return EnumType[DECORATOR].apply(undefined, args); // Constructor const [owner, initArgs, context] = args; DataType.call(this, owner, initArgs, context); const _this = asMutable(this); _this.kind = OpraSchema.EnumType.Kind; if (initArgs.base) { // noinspection SuspiciousTypeOfGuard if (!(initArgs.base instanceof EnumType)) { throw new TypeError(`"${initArgs.base.kind}" can't be set as base for a "${_this.kind}"`); } _this.base = initArgs.base; } _this.instance = initArgs.instance; _this.ownAttributes = cloneObject(initArgs.attributes || {}); _this.attributes = _this.base ? cloneObject(_this.base.attributes) : {}; for (const [k, el] of Object.entries(_this.ownAttributes)) { _this.attributes[k] = el; } }; /** * @class EnumType */ class EnumTypeClass extends DataType { extendsFrom(baseType) { if (!(baseType instanceof DataType)) baseType = this.node.getDataType(baseType); if (!(baseType instanceof EnumType)) return false; if (baseType === this) return true; return !!this.base?.extendsFrom(baseType); } generateCodec() { return vg.isEnum(Object.keys(this.attributes)); } toJSON(options) { const superJson = super.toJSON(options); const baseName = this.base ? this.node.getDataTypeNameWithNs(this.base) : undefined; return omitUndefined({ ...superJson, kind: this.kind, base: baseName, attributes: cloneObject(this.ownAttributes), }); } _locateBase(callback) { if (!this.base) return; if (callback(this.base)) return this.base; if (this.base._locateBase) return this.base._locateBase(callback); } } EnumType.prototype = EnumTypeClass.prototype; Object.assign(EnumType, EnumTypeClass); /** * */ function EnumTypeFactory(enumSource, ...args) { const base = args.length >= 2 ? args[0] : undefined; const options = args.length >= 2 ? args[1] : args[0]; let attributes = {}; let out = enumSource; if (Array.isArray(enumSource)) { if (base) { if (!Array.isArray(base)) throw new TypeError('Both "target" and "base" arguments should be array'); out = [...base, ...enumSource]; } attributes = {}; enumSource.forEach(k => { const description = options?.meanings?.[k]; attributes[k] = omitUndefined({ description }); }); } else { if (base) { if (Array.isArray(base)) throw new TypeError('Both "target" and "base" arguments should be enum object'); out = { ...base, ...enumSource }; } Object.keys(enumSource).forEach(k => { const description = options?.meanings?.[k]; attributes[enumSource[k]] = omitUndefined({ alias: k, description }); }); } const metadata = { kind: OpraSchema.EnumType.Kind, attributes, base: options?.base, name: options?.name, description: options?.description, }; Object.defineProperty(enumSource, DATATYPE_METADATA, { value: metadata, enumerable: false, configurable: true, writable: true, }); return out; } EnumType.prototype = EnumTypeClass.prototype; EnumType[DECORATOR] = EnumTypeFactory;