@opra/common
Version:
Opra common package
122 lines (121 loc) • 3.98 kB
JavaScript
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;