UNPKG

deneric2

Version:

Zero-dependency JSON-to-Entity parser with schema support

253 lines (251 loc) 7.82 kB
// src/utils.ts function parsePath(path) { if (!path) return []; const result = []; const regex = /[^.[\]]+/g; let match; while ((match = regex.exec(path)) !== null) { result.push(match[0]); } return result; } function get(obj, path) { if (obj == null) return void 0; const keys = parsePath(path); let current = obj; for (const key of keys) { if (current == null) return void 0; current = current[key]; } return current; } function set(obj, path, value) { if (obj == null || typeof obj !== "object") return obj; const keys = parsePath(path); if (keys.length === 0) return obj; let current = obj; for (let i = 0; i < keys.length - 1; i++) { const key = keys[i]; const nextKey = keys[i + 1]; if (current[key] == null || typeof current[key] !== "object") { current[key] = /^\d+$/.test(nextKey) ? [] : {}; } current = current[key]; } current[keys[keys.length - 1]] = value; return obj; } function cloneDeep(value) { if (value === null || value === void 0) return value; if (typeof value !== "object") return value; if (Array.isArray(value)) { return value.map((item) => cloneDeep(item)); } if (value instanceof Date) { return new Date(value.getTime()); } if (value instanceof RegExp) { return new RegExp(value.source, value.flags); } const result = Object.create(Object.getPrototypeOf(value)); for (const key of Object.keys(value)) { result[key] = cloneDeep(value[key]); } return result; } function isPlainObject(value) { if (value === null || value === void 0) return false; if (typeof value !== "object") return false; if (Array.isArray(value)) return false; const proto = Object.getPrototypeOf(value); return proto === Object.prototype || proto === null; } // src/Deneric.ts var COMMON_DATA_TYPES = [String, Number, Boolean, Array, Object]; var DENERIC_SCHEMA_PATH = "__deneric_schema"; var ComplexDataType = class { constructor() { this.isArray = false; this.isMap = false; } }; var ArrayDataType = class extends ComplexDataType { constructor(itemType) { super(); this.itemType = itemType; this.isArray = true; } }; var MapDataType = class extends ComplexDataType { constructor(itemType) { super(); this.itemType = itemType; this.isMap = true; } }; var Utils = Object.freeze({ getValue(data, dataPath) { if (!!dataPath) { return get(data, dataPath); } return data; }, getValueFromJson(data, dataType, defaultValue, strict) { if (dataType.prototype instanceof Deneric) { return new dataType(data); } if (dataType instanceof ComplexDataType) { const complexDataType = dataType; if (complexDataType.isArray) { return Array.isArray(data) ? data.map((item) => Utils.getValueFromJson(item, complexDataType.itemType, Utils.getDefaultValue(complexDataType.itemType), strict)) : defaultValue; } if (complexDataType.isMap && isPlainObject(data)) { return Object.keys(data).reduce((prev, key) => { set(prev, key, Utils.getValueFromJson(Utils.getValue(data, key), complexDataType.itemType, Utils.getDefaultValue(complexDataType.itemType), strict)); return prev; }, {}); } return defaultValue; } const dataIsNil = data === null || data === void 0; if (!COMMON_DATA_TYPES.includes(dataType)) { return dataIsNil ? defaultValue : data; } if (strict) { switch (dataType) { case String: return typeof data === "string" ? data : defaultValue; case Number: return typeof data === "number" ? data : defaultValue; case Boolean: return typeof data === "boolean" ? data : defaultValue; case Array: return Array.isArray(data) ? data : defaultValue; case Object: return isPlainObject(data) ? data : defaultValue; } } if (!strict && !dataIsNil) { switch (dataType) { case String: return String(data); case Number: return Number(data); case Boolean: return Boolean(data); case Array: return [].concat(data); case Object: return Object(data); } } return defaultValue; }, getValueFromDeneric(data, dataType, defaultValue) { switch (dataType) { case String: return typeof data === "string" ? data : defaultValue; case Number: return typeof data === "number" ? data : defaultValue; case Boolean: return typeof data === "boolean" ? data : defaultValue; case Array: return Array.isArray(data) ? data : defaultValue; case Object: return isPlainObject(data) ? cloneDeep(data) : defaultValue; } if (dataType instanceof ComplexDataType) { const complexDataType = dataType; if (complexDataType.isArray) { return Array.isArray(data) ? data.map((item) => Utils.getValueFromDeneric(item, complexDataType.itemType, Utils.getDefaultValue(complexDataType.itemType))) : defaultValue; } if (complexDataType.isMap) { data = isPlainObject(data) ? data : {}; return Object.keys(data).reduce((prev, key) => { set(prev, key, Utils.getValueFromDeneric(data[key], complexDataType.itemType, Utils.getDefaultValue(complexDataType.itemType))); return prev; }, {}); } } if (dataType.prototype instanceof Deneric) { return data.toJson(); } return data; }, getDefaultValue(dataType) { if (dataType instanceof ComplexDataType) { const complexDataType = dataType; if (complexDataType.isArray) { return []; } if (complexDataType.isMap) { return {}; } } switch (dataType) { case String: return ""; case Number: return 0; case Boolean: return false; case Array: return []; case Object: return {}; } return void 0; }, setSchema(instance, schema) { set(instance, DENERIC_SCHEMA_PATH, schema); }, getSchema(instance) { return get(instance, DENERIC_SCHEMA_PATH) || {}; } }); var Deneric = class { // private __proto__!: { schema: DenericSchema } constructor(schema) { if (!schema) { throw new TypeError("Invalid schema: " + this.constructor.name); } Utils.setSchema(this, schema); } clone() { return cloneDeep(this); } fromJson(data, strict = true) { const schema = Utils.getSchema(this); Object.keys(schema).forEach((key) => { var _a, _b; const [dataPath, dataType] = schema[key]; let defaultValue = (_a = get(this, key)) != null ? _a : Utils.getDefaultValue(dataType); if (schema[key][3] === void 0) { schema[key][3] = defaultValue; } else { defaultValue = (_b = schema[key][3]) != null ? _b : Utils.getDefaultValue(dataType); } const value = Utils.getValueFromJson(cloneDeep(Utils.getValue(data, dataPath)), dataType, defaultValue, strict); set(this, key, value); }); return this; } toJson() { const schema = Utils.getSchema(this); const json = {}; Object.keys(schema).forEach((key) => { const [dataPath, dataType, jsonIgnore, defaultValueFromSchema] = schema[key]; if (!jsonIgnore) { set(json, dataPath, Utils.getValueFromDeneric(get(this, key), dataType, defaultValueFromSchema || Utils.getDefaultValue(dataType))); } }); return json; } }; Deneric.Array = (dataType) => new ArrayDataType(dataType); Deneric.Map = (valueDataType) => new MapDataType(valueDataType); Deneric.Utils = Utils; var Deneric_default = Deneric; export { Deneric_default as default }; //# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map