UNPKG

@rxap/xml-parser

Version:

Provides a set of decorators and services for parsing and serializing XML documents into TypeScript classes. It simplifies the process of mapping XML elements and attributes to class properties, handling data validation, and serializing objects back into

146 lines 7.19 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ElementChildSerializer = exports.ElementChildParser = void 0; exports.ElementChild = ElementChild; const tslib_1 = require("tslib"); const mixin_1 = require("@rxap/mixin"); const reflect_metadata_1 = require("@rxap/reflect-metadata"); const utilities_1 = require("@rxap/utilities"); const error_1 = require("../error"); const get_extended_types_1 = require("../utilities/get-extended-types"); const metadata_keys_1 = require("./metadata-keys"); const child_element_mixin_1 = require("./mixins/child-element.mixin"); const required_property_1 = require("./required-property"); const add_parser_to_metadata_1 = require("./utilities/add-parser-to-metadata"); const add_serializer_to_metadata_1 = require("./utilities/add-serializer-to-metadata"); const is_virtual_element_1 = require("./utilities/is-virtual-element"); let ElementChildParser = class ElementChildParser { constructor(propertyKey, elementTypeOrFunction, options) { this.propertyKey = propertyKey; this.elementTypeOrFunction = elementTypeOrFunction; this.options = options; this.parse = this.parse.bind(this); Reflect.set(this.parse, 'propertyKey', propertyKey); } parse(xmlParser, element, parsedElement) { var _a; element = this.applyPath(element); const elementType = this.findChildElementType(element); const tag = (_a = elementType.TAG) !== null && _a !== void 0 ? _a : (this.hasTag ? this.tag : null); if (!tag) { if (this.isVirtual) { return parsedElement; } throw new Error('The element type tag is not defined!'); } if (element.hasChild(tag)) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore parsedElement[this.propertyKey] = xmlParser.parse(element.getChild(tag), elementType, parsedElement); } else if (this.required) { throw new error_1.RxapXmlParserValidateRequiredError(`Element child <${tag}> is required in <${parsedElement.__tag}>!`, parsedElement.__tag); } return parsedElement; } findChildElementType(element) { const elementType = this.elementType; if (!elementType) { throw new Error(`The element type is not defined for <${element.name}>`); } const extendedTypes = (0, get_extended_types_1.getExtendedTypes)(elementType); for (const extendedType of extendedTypes) { if (extendedType.TAG) { if (element.hasChild(extendedType.TAG)) { return extendedType; } } } return elementType; } }; exports.ElementChildParser = ElementChildParser; exports.ElementChildParser = ElementChildParser = tslib_1.__decorate([ (0, mixin_1.Mixin)(child_element_mixin_1.ChildElementMixin), tslib_1.__metadata("design:paramtypes", [String, Object, Object]) ], ElementChildParser); let ElementChildSerializer = class ElementChildSerializer { constructor(propertyKey, elementTypeOrFunction, options) { this.propertyKey = propertyKey; this.elementTypeOrFunction = elementTypeOrFunction; this.options = options; this.serialize = this.serialize.bind(this); Reflect.set(this.serialize, 'propertyKey', propertyKey); } serialize(xmlParser, element, parsedElement) { if (!parsedElement.__tag) { throw new Error('The element instance does not have a defined __tag property. If created manually, ensure to set it.'); } // @ts-expect-error the propertyKey is set by the property decorator const child = parsedElement[this.propertyKey]; if (child && !(0, is_virtual_element_1.isVirtualElement)(child)) { element = this.coercePath(element); xmlParser.serialize(child, element); } else if (this.required) { throw new error_1.RxapXmlSerializerValidateRequiredError(`Element child <${parsedElement.__tag}> is required.`, parsedElement.__tag); } } }; exports.ElementChildSerializer = ElementChildSerializer; exports.ElementChildSerializer = ElementChildSerializer = tslib_1.__decorate([ (0, mixin_1.Mixin)(child_element_mixin_1.ChildElementMixin), tslib_1.__metadata("design:paramtypes", [String, Object, Object]) ], ElementChildSerializer); /** * Decorator factory that creates a decorator to parse and validate a child element of a specified type. * * This decorator can be applied to properties within a class to automatically handle the parsing * and validation of child elements based on the specified `elementType`. It uses the `ElementChildParser` * to configure the parsing process according to the provided options and any existing metadata associated * with the property. * * @param elementType - The constructor of the child element type that this parser should target. This * helps in ensuring that the parsed data conforms to the specified type. * @param options - An optional `ElementChildOptions` object that provides additional configuration * settings for the parser. These options are merged with any existing metadata options * defined on the property. * Default is an empty object. * * @returns A decorator function that takes a target object and a property key. The decorator function * enhances the target object's property with parsing capabilities, ensuring that the property * adheres to the defined child element type and options. * * Usage: * - `elementType`: Pass the class (constructor function) that the property is expected to be an instance of. * - `options`: Configuration options such as `required` which, if set to true, will enforce that the property * must not be undefined or null after parsing. * * Example: * ```typescript * class MyComponent { * @ElementChild(SomeChildElement, { required: true }) * child: SomeChildElement; * } * ``` * * Note: * - The decorator will automatically merge any runtime metadata options associated with the property, * allowing for flexible and powerful configuration that can be adjusted without modifying the source code. * - If the `required` option is set to true, the property will also be decorated with a `RequiredProperty` * decorator to enforce its presence. */ function ElementChild(elementType, options = {}) { return function (target, propertyKey) { options = (0, utilities_1.deepMerge)(options, (0, reflect_metadata_1.getMetadata)(metadata_keys_1.ElementParserMetaData.OPTIONS, target, propertyKey) || {}); const parser = new ElementChildParser(propertyKey, elementType, options); (0, add_parser_to_metadata_1.AddParserToMetadata)(parser, target); const serializer = new ElementChildSerializer(propertyKey, elementType, options); (0, add_serializer_to_metadata_1.AddSerializerToMetadata)(serializer, target); if (options.required) { (0, required_property_1.RequiredProperty)()(target, propertyKey); } }; } //# sourceMappingURL=element-child.js.map