UNPKG

@open-kappa/myjson

Version:

A simple JSON management library.

231 lines 7.65 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MyJsonFlex = void 0; const myjsonImpl_1 = require("./myjsonImpl"); /** Key for symbol name. */ const KEY_NAME = "_okmj_flex_impl"; /** * @brief A special kind of JSON object. * It has some mandatory fields, and other optionals, as long as they respect a * validator. * It is inspired by C "flex" structs, i.e. structs with some fields ending with * an array: * ```c * struct FlexExample * { * int a; * double b; * unsigned flex[0]; * }; * ``` */ class MyJsonFlex extends myjsonImpl_1.MyJsonBaseObject { /** * @brief Constructor. * @param {Element} element The validator for flex elements. If it is * mandatory, then the list cannot be empty. * @param {boolean} isMandatory True if the object must appear in the * hierarchy. * @param {string} name The name of the object. */ constructor(element, isMandatory, name) { super(isMandatory, name); const anySelf = this; anySelf[Symbol.for(KEY_NAME)] = new myjsonImpl_1.MyJsonFlexProperties(element); } /** * @brief Return the internal validator element of the flex object. * It uses a symbol to hide the properties to "usual" javascript methods. * @private * @return {Element} The validator. */ _getValidatorElement() { const anySelf = this; return anySelf[Symbol.for(KEY_NAME)].element; } /** * @brief Parse a JSON object. * @param {any} json The JSON to parse. * @throws {Error} If a validation error occurrs. */ parseJsonImpl(json) { const self = this; self._ensureMandatory(json); self._parseJson(json); } /** * @brief Ensure that mandatory properties exists. * @param {any} json The json to validate. * @throws {Error} If the check fails. */ _ensureMandatory(json) { const self = this; function ensureMandatory(key, value) { if (!value.isMandatory()) { return false; } else if (!(value.getJsonName() in json)) { self._throwValidatorError("MyJsonFlex.parseJson(): missing mandatory key: " + key); } return false; } self.forEach(ensureMandatory); const element = self._getValidatorElement(); if (!element.isMandatory()) return; if (self.getSize() < Object.keys(json).length) return; self._throwValidatorError("MyJsonFlex.parseJson(): expecting at least one optional element."); } /** * @brief Do actual parsing. * @param {any} json The json to parse. * @throws {Error} If the parsing fails. */ _parseJson(json) { const self = this; const keys = Object.keys(json); const set = new Set(); const element = self._getValidatorElement(); for (let i = 0; i < keys.length; ++i) { const key = keys[i]; if (set.has(key)) { self._throwValidatorError("MyJsonFlex.parseJson(): duplicated key " + key); } set.add(key); const jsonValue = json[key]; if (self.has(key)) { const el = self.get(key); el.parseJson(jsonValue); } else { const el = element.clone(); el.parseJson(jsonValue); self.set(key, el); } } } // @todo move as utility, since here it is unused _parseRecurse(key, jsonValue) { const self = this; const type = typeof jsonValue; switch (type) { case "boolean": { const newValue = new myjsonImpl_1.MyJsonValue(false, false, key); newValue.parseJson(jsonValue); self.set(key, newValue); break; } case "number": { const newValue = new myjsonImpl_1.MyJsonValue(0, false, key); newValue.parseJson(jsonValue); self.set(key, newValue); break; } case "object": { const newValue = new MyJsonFlex(self._getValidatorElement().clone(), false, key); newValue.parseJson(jsonValue); self.set(key, newValue); break; } case "string": { const newValue = new myjsonImpl_1.MyJsonValue("", false, key); newValue.parseJson(jsonValue); self.set(key, newValue); break; } case "bigint": case "function": case "symbol": case "undefined": default: self._throwValidatorError("unexpected JSON type: " + type); } } /** * @brief Clear the object content. */ clearImpl() { const self = this; const anySelf = self; function deleter(key, el) { if (!el.isMandatory()) { delete anySelf[key]; } else { el.clear(); } return false; } self.forEach(deleter); } /** * @brief Clone this object. * @return {MyJsonFlex<Element>} The copy. */ clone() { const self = this; const ret = new MyJsonFlex(self._getValidatorElement().clone(), self.isMandatory(), self.getJsonName()); self._cloneImpl(ret); return ret; } /** * @brief Check if two JSON objects are equals. * @param {MyJson} other The other object of comparison. * @return {boolean} True if they are equals. */ isEqual(other) { const self = this; if (!(other instanceof MyJsonFlex)) return false; return self._isEqualImpl(other); } /** * @brief Execute the given callback on each element. * The callback takes the key, the element, and the whole object. * It returns true to break the loop before having rolled on all elements. * @param {(key:string,value:MyJson,obj:MyJsonFlex<Element>)=>boolean} func * The callback. * @param {any | null | undefined} [funcThis=null] The optional "this" for * the callback. */ forEach(func, funcThis = null) { return super._forEachImpl(func, funcThis); } /** * @brief Merge the two objects. * Already existent keys are merged recursively. * @param {MyJson} other The other object to merge. * @throws {Error} If the two objects cannot be merged. */ merge(other) { const self = this; if (!(other instanceof MyJsonFlex)) { self._throwValidatorError("Invalid other instance."); } const otherObj = other; if (!self._getValidatorElement().isEqual(otherObj._getValidatorElement())) { self._throwValidatorError("Invalid other type instance."); } self._mergeImpl(otherObj); } /** * @brief Add a new child element. * This is a build-time support method. * @param {MyJson} element The child element. * @return {MyJson} This. * @throws {Error} If element cannot be added. */ add(element) { super.add(element); return this; } } exports.MyJsonFlex = MyJsonFlex; exports.default = MyJsonFlex; //# sourceMappingURL=MyJsonFlex.js.map