UNPKG

@mdcc/at-json

Version:

A declarative mapper to and from JSON.

887 lines (825 loc) 35.2 kB
/******/ var __webpack_modules__ = ([ /* 0 */, /* 1 */ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ JsonArray: () => (/* reexport safe */ _decorators__WEBPACK_IMPORTED_MODULE_0__.JsonArray), /* harmony export */ JsonArrayOfComplexProperty: () => (/* reexport safe */ _decorators__WEBPACK_IMPORTED_MODULE_0__.JsonArrayOfComplexProperty), /* harmony export */ JsonClass: () => (/* reexport safe */ _decorators__WEBPACK_IMPORTED_MODULE_0__.JsonClass), /* harmony export */ JsonComplexProperty: () => (/* reexport safe */ _decorators__WEBPACK_IMPORTED_MODULE_0__.JsonComplexProperty), /* harmony export */ JsonMap: () => (/* reexport safe */ _decorators__WEBPACK_IMPORTED_MODULE_0__.JsonMap), /* harmony export */ JsonMapper: () => (/* reexport safe */ _mapper__WEBPACK_IMPORTED_MODULE_1__.JsonMapper), /* harmony export */ JsonProperty: () => (/* reexport safe */ _decorators__WEBPACK_IMPORTED_MODULE_0__.JsonProperty), /* harmony export */ makeCustomDecorator: () => (/* reexport safe */ _decorators__WEBPACK_IMPORTED_MODULE_0__.makeCustomDecorator) /* harmony export */ }); /* harmony import */ var _decorators__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2); /* harmony import */ var _mapper__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(12); /***/ }), /* 2 */ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ JsonArray: () => (/* reexport safe */ _array__WEBPACK_IMPORTED_MODULE_0__.JsonArray), /* harmony export */ JsonArrayOfComplexProperty: () => (/* reexport safe */ _array_of_complex_property__WEBPACK_IMPORTED_MODULE_1__.JsonArrayOfComplexProperty), /* harmony export */ JsonClass: () => (/* reexport safe */ _class__WEBPACK_IMPORTED_MODULE_2__.JsonClass), /* harmony export */ JsonComplexProperty: () => (/* reexport safe */ _complex_property__WEBPACK_IMPORTED_MODULE_4__.JsonComplexProperty), /* harmony export */ JsonMap: () => (/* reexport safe */ _map__WEBPACK_IMPORTED_MODULE_5__.JsonMap), /* harmony export */ JsonProperty: () => (/* reexport safe */ _property__WEBPACK_IMPORTED_MODULE_6__.JsonProperty), /* harmony export */ makeCustomDecorator: () => (/* reexport safe */ _common__WEBPACK_IMPORTED_MODULE_3__.makeCustomDecorator) /* harmony export */ }); /* harmony import */ var _array__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3); /* harmony import */ var _array_of_complex_property__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7); /* harmony import */ var _class__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(8); /* harmony import */ var _common__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4); /* harmony import */ var _complex_property__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9); /* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(10); /* harmony import */ var _property__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(11); /***/ }), /* 3 */ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ JsonArray: () => (/* binding */ JsonArray) /* harmony export */ }); /* harmony import */ var _common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4); /** * The basic decorator for array of simple properties. * * `params` has the same meaning that the one in {@link JsonProperty}. * * Usage examples: * ```typescript * import { JsonClass, JsonMapper, JsonArray } from '@mdcc/at-json'; * * @JsonClass() * class MyClass * { * @JsonArray() * basicProperty: string[]; * * @JsonArray('extName') * renamedProperty: number[]; * * @JsonArray({ * name: 'custom', * serialize: (mapper, n) => n.toString(), * deserialize: (mapper, n) => parseInt(n, 10) * }, true) * customProperty: number[]; * } * * const backendObject = { * basicProperty: ['value', 'value2'], * extName: [123, 456], * customProperty: ['456', '789'] * }; * const mapper = new JsonMapper(); * const deserialized = mapper.deserialize<MyClass>(MyClass, backendObject); * * // basicProperty keeps the same name * assert.equal(deserialized.basicProperty, ['value', 'value2']); * // extName became renamedProperty * assert.equal(deserialized.renamedProperty, [123, 456]); * // customProperty became custom, and the string was converted to number * assert.equal(deserialized.custom, [456, 789]); * * const backendObjectSerialized = mapper.serialize(deserialized); * // reverse conversion was performed * assert.deepEqual(backendObjectSerialized, backendObject); * * const errorObject = { basicProperty: {} }; * const deserializedErrorObject = mapper.deserialize<MyClass>(MyClass, errorObject); * // basicProperty is null * assert.isNull(deserializedErrorObject.basicProperty); * * const errorObject2 = { basicProperty: [], renamedProperty: [], customProperty: {} }; * // this throws because customProperty was decorated with `@JsonArray(..., true)` * const deserializedErrorObject2 = mapper.deserialize<MyClass>(MyClass, errorObject2); * ``` * * @export * @param {DecoratorInputWithCustomFunctions<T>} [params] the params * @param {NoCustomFunctionsDecoratorInput} params params * @param {boolean} throwIfNotArray if true, throws an error if the property is not an array. * @returns the decorator for the property. */ function JsonArray(params, throwIfNotArray) { return (0,_common__WEBPACK_IMPORTED_MODULE_0__.transformDecorator)(opt => ({ serialize: (mapper, array) => (0,_common__WEBPACK_IMPORTED_MODULE_0__.mapArray)(mapper, array, opt.serialize, throwIfNotArray), deserialize: (mapper, array) => (0,_common__WEBPACK_IMPORTED_MODULE_0__.mapArray)(mapper, array, opt.deserialize, throwIfNotArray), }))(params); } /***/ }), /* 4 */ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ makeCustomDecorator: () => (/* binding */ makeCustomDecorator), /* harmony export */ mapArray: () => (/* binding */ mapArray), /* harmony export */ transformDecorator: () => (/* binding */ transformDecorator) /* harmony export */ }); /* harmony import */ var _interfaces__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5); /* harmony import */ var _reflection__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6); function normalizeParams(params) { let resolvedParams; if (typeof params === 'string') { resolvedParams = { name: params }; } else { resolvedParams = params || {}; } return resolvedParams; } /** * A custom decorator factory function, in order to allow defining custom reusable decorators. * * @param serializeFn the function used for serializing the value. * @param deserializeFn the function used for deserializing the value. */ function makeCustomDecorator(fn) { return params => { const actualParams = { ...normalizeParams(params), ...fn(), }; return _createPropertyDecorator(actualParams); }; } /** * A decorator transforming function, used internally. */ function transformDecorator(fn) { return params => { const normalizedParams = normalizeParams(params); const { serialize, deserialize } = fn(normalizedParams); const actualParams = { ...normalizedParams, serialize, deserialize, }; return _createPropertyDecorator(actualParams); }; } function _createPropertyDecorator(actualParams) { return function (target, propertyKey) { const constructor = target.constructor; const objMetadata = (0,_reflection__WEBPACK_IMPORTED_MODULE_1__.getMetadata)(_interfaces__WEBPACK_IMPORTED_MODULE_0__.Symbols.fieldsMetadata, constructor) || []; (0,_reflection__WEBPACK_IMPORTED_MODULE_1__.defineMetadata)(_interfaces__WEBPACK_IMPORTED_MODULE_0__.Symbols.fieldsMetadata, [...objMetadata, propertyKey], constructor); (0,_reflection__WEBPACK_IMPORTED_MODULE_1__.defineMetadata)(_interfaces__WEBPACK_IMPORTED_MODULE_0__.Symbols.mappingMetadata, actualParams, constructor, propertyKey); }; } function mapArray(mapper, propertyValue, deserializeItem, throwIfNotArray) { if (Array.isArray(propertyValue)) { if (deserializeItem) { // map deserialize on the array return propertyValue.map(item => deserializeItem(mapper, item)); } else { return propertyValue; } } else { if (throwIfNotArray) { throw new Error(`Expected array, got ${typeof propertyValue}`); } // if marked as array, but not an array, set the value to null return null; } } /***/ }), /* 5 */ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Symbols: () => (/* binding */ Symbols), /* harmony export */ hasAfterDeserialize: () => (/* binding */ hasAfterDeserialize), /* harmony export */ hasCustomSerializeExport: () => (/* binding */ hasCustomSerializeExport) /* harmony export */ }); const Symbols = { mappingMetadata: Symbol('[[mapping]]'), mappingOptions: Symbol('[[mappingOptions]]'), fieldsMetadata: Symbol('[[fields]]'), metadataRoot: Symbol('[[AtJsonMetadata]]'), }; Object.freeze(Symbols); /** * Type guard for {@link CustomSerialize} interface. * * @param mapValue value to check * @returns if the parameter is a CustomSerialize interface */ function hasCustomSerializeExport(mapValue) { const fn = mapValue[nameOf('customSerialize')]; return typeof fn === 'function'; } /** * Type guard for {@link AfterDeserialize} interface. * * @param mapValue value to check * @returns if the parameter is a AfterDeserialize interface */ function hasAfterDeserialize(mapValue) { const fn = mapValue[nameOf('afterDeserialize')]; return typeof fn === 'function'; } /** helper */ function nameOf(k) { return k; } /***/ }), /* 6 */ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ defineMetadata: () => (/* binding */ defineMetadata), /* harmony export */ getMetadata: () => (/* binding */ getMetadata) /* harmony export */ }); /* harmony import */ var _interfaces__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5); /** * Defines a metadata on the target object. * * Replaces `Reflect.defineMetadata`. * * @param {string | symbol} key the key of the metadata * @param {any} value the value to be set in the metadata * @param {object} target the target on which the metadata should be set * @param {string | symbol} propertyName optional property name to add to the path on where value is set */ function defineMetadata(key, value, target, propertyName) { // define metadata map on object to avoid overwriting the parent if (!has(target, _interfaces__WEBPACK_IMPORTED_MODULE_0__.Symbols.metadataRoot)) { target[_interfaces__WEBPACK_IMPORTED_MODULE_0__.Symbols.metadataRoot] = {}; } const v = target[_interfaces__WEBPACK_IMPORTED_MODULE_0__.Symbols.metadataRoot]; if (typeof v[propertyName] === 'undefined') { v[propertyName] = {}; } v[propertyName][key] = value; } /** * Retrieves the metadata associated to `target` and `propertyName`. * * If not found, follows the prototype chain. * * Replaces `Reflect.getMedadata`. * * @param {string | symbol} key the key of the metadata * @param {object} target the target from which the metadata should be retrieved * @param {string | symbol} propertyName optional property name to add to the path on where value is retrieved * @returns {any} the value found, or `undefined` if not found */ function getMetadata(key, target, propertyName) { const propName = propertyName; while (target) { const map = target?.[_interfaces__WEBPACK_IMPORTED_MODULE_0__.Symbols.metadataRoot]; if (map && has(map, propName) && has(map[propName], key)) { return map[propName][key]; } target = Object.getPrototypeOf(target); } return undefined; } function has(object, key) { return Object.prototype.hasOwnProperty.call(object, key); } /***/ }), /* 7 */ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ JsonArrayOfComplexProperty: () => (/* binding */ JsonArrayOfComplexProperty) /* harmony export */ }); /* harmony import */ var _common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4); /** * Decorator for complex-type array properties to be (de)serialized correctly. * Use this if the property is an array of a type that needs recursive (de)serialization. * * Usage examples: * ```typescript * import { * JsonClass, * JsonMapper, * JsonProperty, * JsonArrayOfComplexProperty * } from '@mdcc/at-json'; * * @JsonClass() * class SubClass * { * @JsonProperty() * foo: string; * } * * @JsonClass() * class MyClass * { * @JsonArrayOfComplexProperty(SubClass) * sub1: SubClass[]; * * @JsonArrayOfComplexProperty(SubClass, 'extSub2', true) * sub2: SubClass[]; * } * * const backendObject = { * sub1: [{ foo: 'bar' }], * extSub2: [{ foo: 'baz' }] * }; * const mapper = new JsonMapper(); * const deserialized = mapper.deserialize<MyClass>(MyClass, backendObject); * * // sub1 keeps the same name * assert.isInstanceOf(deserialized.sub1, Array); * assert.isInstanceOf(deserialized.sub1[0], SubClass); * assert.equal(deserialized.sub1[0].foo, 'bar'); * * // extSub2 became sub2 * assert.isInstanceOf(deserialized.sub2, Array); * assert.isInstanceOf(deserialized.sub2[0], SubClass); * assert.equal(deserialized.sub2[0].foo, 'baz'); * * const backendObjectSerialized = mapper.serialize(deserialized); * // reverse conversion was performed * assert.deepEqual(backendObjectSerialized, backendObject); * * const errorObject = { sub1: {} }; * const deserializedErrorObject = mapper.deserialize<MyClass>(MyClass, errorObject); * // sub1 is null * assert.isNull(deserializedErrorObject.sub1); * * const errorObject2 = { sub1: [], sub2: {} }; * // this throws because sub2 was decorated with `@JsonArrayOfComplexProperty(..., true)` * const deserializedErrorObject2 = mapper.deserialize<MyClass>(MyClass, errorObject2); * ``` * * @export * @param {Constructable<any>} constructor the constructor type of the array items. * @param {DecoratorInputWithoutCustomFunctions} params params * @param {boolean} throwIfNotArray if true, throws an error if the property is not an array. * @returns the decorator for the property. */ function JsonArrayOfComplexProperty(constructor, params, throwIfNotArray) { function serialize(m, item) { return m.serialize(item); } function deserialize(m, item) { return item === null || item === undefined ? item : m.deserialize(constructor, item); } return (0,_common__WEBPACK_IMPORTED_MODULE_0__.makeCustomDecorator)(() => ({ serialize: (mapper, array) => (0,_common__WEBPACK_IMPORTED_MODULE_0__.mapArray)(mapper, array, serialize, throwIfNotArray), deserialize: (mapper, array) => (0,_common__WEBPACK_IMPORTED_MODULE_0__.mapArray)(mapper, array, deserialize, throwIfNotArray), }))(params); } /***/ }), /* 8 */ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ JsonClass: () => (/* binding */ JsonClass) /* harmony export */ }); /* harmony import */ var _interfaces__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5); /* harmony import */ var _reflection__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6); /** * Decorator for mapped classes. * * @export * @template T * @returns * @param ignoreMissingFields */ function JsonClass(options) { const actualOptions = Object.assign({ ignoreUndecoratedProperties: true }, options); return ctor => { (0,_reflection__WEBPACK_IMPORTED_MODULE_1__.defineMetadata)(_interfaces__WEBPACK_IMPORTED_MODULE_0__.Symbols.mappingOptions, actualOptions, ctor); return ctor; }; } /***/ }), /* 9 */ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ JsonComplexProperty: () => (/* binding */ JsonComplexProperty) /* harmony export */ }); /* harmony import */ var _common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4); /** * Decorator for complex-type properties to be (de)serialized correctly. * Use this if the property is of a non-array type that needs recursive (de)serialization. * * Uses only the `name` property of the params. * * Usage examples: * ```typescript * import { JsonClass, JsonMapper, JsonProperty, JsonComplexProperty } from '@mdcc/at-json'; * * @JsonClass() * class SubClass * { * @JsonProperty() * foo: string; * } * * @JsonClass() * class MyClass * { * @JsonComplexProperty(SubClass) * sub1: SubClass; * * @JsonComplexProperty(SubClass, 'extSub2') * sub2: SubClass; * } * * const backendObject = { * sub1: { foo: 'bar' }, * extSub2: { foo: 'baz' } * }; * const mapper = new JsonMapper(); * const deserialized = mapper.deserialize<MyClass>(MyClass, backendObject); * * // sub1 keeps the same name * assert.isInstanceOf(deserialized.sub1, SubClass); * assert.equal(deserialized.sub1.foo, 'bar'); * * // extSub2 became sub2 * assert.isInstanceOf(deserialized.sub2, SubClass); * assert.equal(deserialized.sub2.foo, 'baz'); * * const backendObjectSerialized = mapper.serialize(deserialized); * // reverse conversion was performed * assert.deepEqual(backendObjectSerialized, backendObject); * ``` * * @export * @param {Constructable<any>} constructor the constructor type of the property. * @param name the name of the property * @returns the decorator for the property. */ function JsonComplexProperty(constructor, params) { return (0,_common__WEBPACK_IMPORTED_MODULE_0__.makeCustomDecorator)(() => ({ serialize: (mapper, value) => mapper.serialize(value), deserialize: (mapper, value) => mapper.deserialize(constructor, value), }))(params); } /***/ }), /* 10 */ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ JsonMap: () => (/* binding */ JsonMap) /* harmony export */ }); /* harmony import */ var _common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4); /** * A custom decorator for handling objects as maps. * * @param params the mapping options to apply to the values of the map. */ function JsonMap(params) { return (0,_common__WEBPACK_IMPORTED_MODULE_0__.makeCustomDecorator)(() => ({ serialize: (mapper, map) => { const ret = {}; if (params?.complexType) { for (const [k, v] of map.entries()) { ret[k] = mapper.serialize(v); } } else { for (const [k, v] of map.entries()) { ret[k] = v; } } return ret; }, deserialize: (mapper, obj) => { const map = new Map(); if (params?.complexType) { for (const key in obj) { map.set(key, mapper.deserialize(params.complexType, obj[key])); } } else { for (const key in obj) { map.set(key, obj[key]); } } return map; }, }))(params); } /***/ }), /* 11 */ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ JsonProperty: () => (/* binding */ JsonProperty) /* harmony export */ }); /* harmony import */ var _common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4); /** * The basic decorator for simple properties. * * It basically takes the incoming property value, applies eventual custom serialization or deserialization, * and then sets the property value to the result. * * `params` can be: * - a string, if only the name of source property is provided (`name` property of {@link IMappingOptions}). * - an object compliant to {@link IMappingOptions} interface. * * Usage examples: * ```typescript * import { JsonClass, JsonMapper, JsonProperty } from '@mdcc/at-json'; * * @JsonClass() * class MyClass * { * @JsonProperty() * basicProperty: string; * * @JsonProperty('extName') * renamedProperty: number; * * @JsonProperty({ * name: 'custom', * serialize: (mapper, n) => n.toString(), * deserialize: (mapper, n) => parseInt(n, 10) * }) * customProperty: number; * } * * const mapper = new JsonMapper(); * const backendObject = { basicProperty: 'value', extName: 123, customProperty: '456' }; * const deserialized = mapper.deserialize<MyClass>(MyClass, backendObject); * * // basicProperty keeps the same name * assert.equal(deserialized.basicProperty, 'value'); * // extName became renamedProperty * assert.equal(deserialized.renamedProperty, 123); * // customProperty became custom, and the string was converted to number * assert.equal(deserialized.custom, 456); * * const backendObjectSerialized = mapper.serialize(deserialized); * // reverse conversion was performed * assert.deepEqual(backendObjectSerialized, backendObject); * ``` * * @export * @param {DecoratorInputWithCustomFunctions} [params] the params * @returns the decorator for the property. */ function JsonProperty(params) { return (0,_common__WEBPACK_IMPORTED_MODULE_0__.transformDecorator)(opt => ({ serialize: opt.serialize, deserialize: opt.deserialize, }))(params); } /***/ }), /* 12 */ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ JsonMapper: () => (/* binding */ JsonMapper) /* harmony export */ }); /* harmony import */ var _interfaces__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5); /* harmony import */ var _reflection__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6); /** * Class for JSON Mapping. * * @export * @class JsonMapper */ class JsonMapper { /** * Serialization method. * Transforms `source` into a new JSON value by applying the "serialization" step for each property decorator. * * Annotated properties are serialized into a property using the `name` value as the destination name (defaults to the property name). * * @param {*} source the value to be serialized. * @returns {string} the transformed JSON value. * @throws An error if a class encountered while serializing has no {@link JsonClass} decorator. * @memberof JsonMapper */ serialize(source) { // if val is nil no need to do anything if (source === null || source === undefined) { return source; } // retrieve the object constructor in order to load the class decorator metadata const ctor = Object.getPrototypeOf(source).constructor; const ctorOptions = (0,_reflection__WEBPACK_IMPORTED_MODULE_1__.getMetadata)(_interfaces__WEBPACK_IMPORTED_MODULE_0__.Symbols.mappingOptions, ctor); if (!ctorOptions) { throw new Error(`Class ${ctor.name} is not decorated with @JsonClass`); } // let's try to call an eventual custom export before the standard one const customExport = exportCustom(this, source); if (customExport.serialized) { return customExport.value; } // should missing properties be ignored const { ignoreUndecoratedProperties } = ctorOptions; // destination object for the mapping const target = {}; Object.keys(source).forEach(propName => { // retrieve the serialization options in the decorator of the property const options = (0,_reflection__WEBPACK_IMPORTED_MODULE_1__.getMetadata)(_interfaces__WEBPACK_IMPORTED_MODULE_0__.Symbols.mappingMetadata, ctor, propName); const propValue = source[propName]; // if no decorator is provided, map the property by copy if "ignoreUndecoratedProperties" is false // maybe here a clone should be used instead of a shallow copy if (options === undefined) { if (!ignoreUndecoratedProperties) { target[propName] = propValue; } return; } // destination property name, by default the property name in the source object, but it can be // overridden in the decorator const name = options.name || propName; if (options.serialize) { target[name] = options.serialize(this, propValue); } else { target[name] = propValue; } }); return target; } /** * Deserializes an array by applying {@link deserialize} to each element. * @template T the type of output object * @param {I.Constructable<T>} ctor the destination constructor * @param jsonArray the array to be deserialized * @returns {T} the deserialized object * @memberof JsonMapper */ deserializeArray(ctor, jsonArray) { return jsonArray.map(v => this.deserialize(ctor, v)); } /** * Deserialization method. * Deserializes `source` into an object built using `ctor`. * * Annotated properties are deserialized into a property using the `name` value as the source name (defaults to the property name). * * @template T the type of output object * @param {I.Constructable<T>} ctor the destination constructor * @param {*} source the value to be deserialized * @param {(s: string) => any} stringParser the string parser to deserialize strings into JSON objects. Defaults to `JSON.parse`. * @returns {T} the deserialized object * @throws An error if a class encountered while deserializing has no {@link JsonClass} decorator. * @memberof JsonMapper */ deserialize(ctor, source, stringParser = JSON.parse) { const ctorOptions = (0,_reflection__WEBPACK_IMPORTED_MODULE_1__.getMetadata)(_interfaces__WEBPACK_IMPORTED_MODULE_0__.Symbols.mappingOptions, ctor); if (!ctorOptions) { throw new Error(`Class ${ctor.name} is not decorated with @JsonClass`); } // automatic parse of strings if (typeof source === 'string') { source = stringParser(source); } const target = new ctor(); const has = Object.prototype.hasOwnProperty; const { ignoreUndecoratedProperties } = ctorOptions; // keep track of mapped properties, so we can copy not mapped ones if "ignoreUndecoratedProperties" is false const mapped = new Set(); // extract the property names array from the metadata stored in the constructor // be careful: undecorated properties are NOT stored in this array const propNames = (0,_reflection__WEBPACK_IMPORTED_MODULE_1__.getMetadata)(_interfaces__WEBPACK_IMPORTED_MODULE_0__.Symbols.fieldsMetadata, ctor) ?? []; propNames.forEach(propName => { const options = (0,_reflection__WEBPACK_IMPORTED_MODULE_1__.getMetadata)(_interfaces__WEBPACK_IMPORTED_MODULE_0__.Symbols.mappingMetadata, ctor, propName); /* istanbul ignore next */ if (options === undefined) { return; } const name = options.name || propName; if (!has.call(source, name)) { return; } if (options.deserialize) { target[propName] = options.deserialize(this, source[name]); } else { target[propName] = source[name]; } mapped.add(name); }); if (!ignoreUndecoratedProperties) { // iterate ALL object keys (even undecorated ones, since we are using Object.keys) Object.keys(source).forEach(propName => { // copy over not mapped properties // maybe here a clone should be performed? if (!mapped.has(propName)) { target[propName] = source[propName]; } }); } // call eventual after deserialize callback to post-process values if (_interfaces__WEBPACK_IMPORTED_MODULE_0__.hasAfterDeserialize(target)) { target.afterDeserialize(); } return target; } } /** * This method checks if the input value is a {@link CustomSerialize} implementation. * If it is so, it calls the custom export function and returns its output in the `value` field * of the response. * * @param {JsonMapper} mapper the mapper * @param mapValue the value to export * @returns the exported value decorated with a boolean */ function exportCustom(mapper, mapValue) { if (_interfaces__WEBPACK_IMPORTED_MODULE_0__.hasCustomSerializeExport(mapValue)) { return { serialized: true, value: mapValue.customSerialize(mapper), }; } else { return { serialized: false, }; } } /***/ }) /******/ ]); /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ var cachedModule = __webpack_module_cache__[moduleId]; /******/ if (cachedModule !== undefined) { /******/ return cachedModule.exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = __webpack_module_cache__[moduleId] = { /******/ // no module.id needed /******/ // no module.loaded needed /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /************************************************************************/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports /******/ __webpack_require__.d = (exports, definition) => { /******/ for(var key in definition) { /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); /******/ } /******/ } /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ (() => { /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) /******/ })(); /******/ /******/ /* webpack/runtime/make namespace object */ /******/ (() => { /******/ // define __esModule on exports /******/ __webpack_require__.r = (exports) => { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ })(); /******/ /************************************************************************/ var __webpack_exports__ = {}; // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. (() => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ JsonArray: () => (/* reexport safe */ _public_api__WEBPACK_IMPORTED_MODULE_0__.JsonArray), /* harmony export */ JsonArrayOfComplexProperty: () => (/* reexport safe */ _public_api__WEBPACK_IMPORTED_MODULE_0__.JsonArrayOfComplexProperty), /* harmony export */ JsonClass: () => (/* reexport safe */ _public_api__WEBPACK_IMPORTED_MODULE_0__.JsonClass), /* harmony export */ JsonComplexProperty: () => (/* reexport safe */ _public_api__WEBPACK_IMPORTED_MODULE_0__.JsonComplexProperty), /* harmony export */ JsonMap: () => (/* reexport safe */ _public_api__WEBPACK_IMPORTED_MODULE_0__.JsonMap), /* harmony export */ JsonMapper: () => (/* reexport safe */ _public_api__WEBPACK_IMPORTED_MODULE_0__.JsonMapper), /* harmony export */ JsonProperty: () => (/* reexport safe */ _public_api__WEBPACK_IMPORTED_MODULE_0__.JsonProperty), /* harmony export */ makeCustomDecorator: () => (/* reexport safe */ _public_api__WEBPACK_IMPORTED_MODULE_0__.makeCustomDecorator) /* harmony export */ }); /* harmony import */ var _public_api__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); })(); var __webpack_exports__JsonArray = __webpack_exports__.JsonArray; var __webpack_exports__JsonArrayOfComplexProperty = __webpack_exports__.JsonArrayOfComplexProperty; var __webpack_exports__JsonClass = __webpack_exports__.JsonClass; var __webpack_exports__JsonComplexProperty = __webpack_exports__.JsonComplexProperty; var __webpack_exports__JsonMap = __webpack_exports__.JsonMap; var __webpack_exports__JsonMapper = __webpack_exports__.JsonMapper; var __webpack_exports__JsonProperty = __webpack_exports__.JsonProperty; var __webpack_exports__makeCustomDecorator = __webpack_exports__.makeCustomDecorator; export { __webpack_exports__JsonArray as JsonArray, __webpack_exports__JsonArrayOfComplexProperty as JsonArrayOfComplexProperty, __webpack_exports__JsonClass as JsonClass, __webpack_exports__JsonComplexProperty as JsonComplexProperty, __webpack_exports__JsonMap as JsonMap, __webpack_exports__JsonMapper as JsonMapper, __webpack_exports__JsonProperty as JsonProperty, __webpack_exports__makeCustomDecorator as makeCustomDecorator }; //# sourceMappingURL=index.mjs.map