sdj-esm
Version:
Self Described JSON - ESM
146 lines (123 loc) • 4.67 kB
text/typescript
/*
Copyright (c) 2023-2024 Will Rudolph <@willrudolph.com>
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
import type {ItemJI, IValidator} from "../core/interfaces.js";
import {validTypeLexName} from "../util/func.std.js";
import {autoFailValidator} from "../core/validators.js";
import {isFunction, isNull, isString, isUndefined} from "lodash-es";
import {restrictCoreSD, restrictLimiter, restrictToAllowedKeys} from "../core/restrict.js";
import {ESDJ_CLASS, ESDJ_LIMIT} from "../core/statics.js";
import type {IDescriptionSdj, IItemSdj} from "./class-interfaces.js";
import {rtnSdjItemName} from "../core/sdj-types.js";
/*
SdjItem
sdId: Item id for Entity sdItems ref
sdKey: name for data reference
type: type
Item Limiter Use:
<None>Default Item is valid via type or null/undefined
.REQ Item is required by entity
.REQ_HIDE Item is required but set hidden
.KEY_IDX Item value is pos-int and is key index
*/
export class SdjItem implements IItemSdj {
private readonly _sdId: number;
private readonly _sdKey: string;
private readonly _limiter: ESDJ_LIMIT;
private _type: string;
private _validator: IValidator = autoFailValidator;
private _description?: IDescriptionSdj;
constructor(inItem: ItemJI, description?: IDescriptionSdj | undefined) {
this.description = description;
if (this._description) {
this._description.host.checkClassInst(inItem, ESDJ_CLASS.ITEM, false);
}
SdjItem.VerifyJI(inItem);
this._sdId = inItem.sdId;
this._sdKey = inItem.sdKey;
this._type = inItem.type;
this._limiter = inItem.limiter || ESDJ_LIMIT.NONE;
if (this._description) {
this.initDescription();
}
}
get sdId() {
return this._sdId;
}
get sdKey() {
return this._sdKey;
}
get type() {
return this._type;
}
get limiter(): ESDJ_LIMIT {
return this._limiter;
}
get validator(): IValidator {
return this._validator;
}
get description(): IDescriptionSdj {
if (!this._description) {
throw new ReferenceError("[SDJ] Item has no description;");
}
return this._description;
}
set description(inDesc:IDescriptionSdj | undefined) {
if (!isNull(inDesc) && !isUndefined(inDesc)) {
if (!this._description) {
if (inDesc.host?.checkClassInst && isFunction(inDesc.host.checkClassInst)) {
inDesc.host.checkClassInst(inDesc, ESDJ_CLASS.DESCRIPTION, true);
this._description = inDesc;
if (this._type) {
this.initDescription();
}
} else {
throw new Error("[SDJ] Incorrect or missing description/host;");
}
} else {
throw new Error("[SDJ] an Item is prevented from having its description overwritten once assigned;");
}
}
}
genJI(): ItemJI {
const rtnItemJI: ItemJI = {
sdId: this.sdId,
sdKey: this.sdKey,
type: this._type
};
if (this._limiter !== ESDJ_LIMIT.NONE) {
rtnItemJI.limiter = this._limiter;
}
return rtnItemJI;
}
private initDescription() {
const replaceName: string | undefined = rtnSdjItemName(this._type);
if (this._description) {
if (replaceName) {
this._description.log(`Item '${this.sdKey}' has type ` +
`'${this._type}' which has been replaced as too similar to default '${replaceName}';`);
this._type = replaceName;
}
this._validator = this._description.host.lexiconMgr.getValidator(this._type);
}
}
static VerifyJI(inItem: ItemJI) {
restrictCoreSD(inItem);
if (!inItem.type || !isString(inItem.type)) {
throw new Error(`[SDJ] Item '${inItem.sdKey}' missing 'type' or invalid type;`);
} else if (!validTypeLexName(inItem.type)) {
throw new Error(`[SDJ] Item type:'${inItem.type}' invalid => requires (a-z0-9_-{4});`);
}
if ((inItem.sdId === 0 && (inItem.type !== "sdid" || inItem.sdKey !== "sdId")) ||
(inItem.sdId === 1 && (inItem.type !== "sdkey" || inItem.sdKey !== "sdKey"))) {
throw new Error("[SDJ] Item sdId's 0, 1 reserved for system;");
}
if (inItem.limiter && !restrictLimiter(inItem.limiter)) {
throw new TypeError(`[SDJ] Provided limiter '${inItem.limiter}' is unrecognized;`);
}
restrictToAllowedKeys("ItemJI: " + inItem.sdKey, ["sdId", "sdKey", "type", "limiter"], inItem);
}
}