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

116 lines 6.04 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ElementRecordParser = void 0; exports.AssertElementRecordOptions = AssertElementRecordOptions; exports.ElementRecord = ElementRecord; 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 metadata_keys_1 = require("./metadata-keys"); const tag_element_mixin_1 = require("./mixins/tag-element.mixin"); const text_content_element_mixin_1 = require("./mixins/text-content-element.mixin"); const required_property_1 = require("./required-property"); const utilities_2 = require("./utilities"); /** * Asserts that the provided `options` object conforms to the `ElementRecordOptions<any>` type. * * This function checks if the given `options` object meets the criteria of being an instance of `ElementRecordOptions<any>`, * specifically by verifying the presence of a "tag" property, which is essential for identifying the object as a valid `ElementRecordOptions`. * If the `options` object does not meet the criteria, the function throws an error indicating the absence of the required "tag" property. * * @param options - The object to be validated against the `ElementRecordOptions<any>` type. * @throws {Error} Throws an error if the `options` object does not have the required "tag" property. */ function AssertElementRecordOptions(options) { if (!(0, tag_element_mixin_1.IsTagElementOptions)(options)) { throw new Error('The object is not a ElementRecordOptions. The required property "tag" is missing!'); } } let ElementRecordParser = class ElementRecordParser { constructor(propertyKey, options) { this.propertyKey = propertyKey; this.options = options; this.parse = this.parse.bind(this); Reflect.set(this.parse, 'propertyKey', propertyKey); } parse(xmlParser, element, parsedElement) { if (element.hasChild(this.tag)) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore parsedElement[this.propertyKey] = {}; for (const child of element.getChild(this.tag).getAllChildNodes()) { if (!(0, utilities_1.hasIndexSignature)(parsedElement)) { throw new Error('Parsed Element has no index signature!'); } parsedElement[this.propertyKey][child.has('propertyKey') ? child.get('propertyKey') : this.convertTagToPropertyKey(child.name)] = child.getTextContent(); } } else if (this.required) { throw new error_1.RxapXmlParserValidateRequiredError(`Element <${element.name}> child <${this.tag}> text content is required!`, parsedElement.__tag); } return parsedElement; } convertTagToPropertyKey(name) { if (name.includes('-')) { return (0, utilities_1.camelize)(name); } return name; } }; exports.ElementRecordParser = ElementRecordParser; exports.ElementRecordParser = ElementRecordParser = tslib_1.__decorate([ (0, mixin_1.Mixin)(text_content_element_mixin_1.TextContentElementMixin, tag_element_mixin_1.TagElementMixin), tslib_1.__metadata("design:paramtypes", [String, Object]) ], ElementRecordParser); /** * Decorator factory that creates a decorator to be applied to class properties for element record parsing. * It configures the parsing behavior based on the provided options or defaults derived from the property name. * * @param {Partial<ElementRecordOptions<Value>> | string} optionsOrString - Configuration options for the element record parser, * or a string specifying the tag name directly. If a string is provided, it is used as the tag name. * If omitted, the tag name is derived by dasherizing the property name. * * @returns {Function} A decorator function that takes a target class and its property key to apply metadata and parsing logic. * * The decorator function internally: * - Resolves the configuration options for the element record. If `optionsOrString` is undefined, it defaults to using * a dasherized version of the property key as the tag. If it's a string, that string is used as the tag. * Otherwise, it treats it as partial options. * - Merges these options with any existing metadata options on the property. * - Ensures a tag is defined, defaulting to a dasherized property key if not explicitly provided. * - Validates the resolved options using `AssertElementRecordOptions`. * - Creates an instance of `ElementRecordParser` with the resolved options and associates it with the property. * - Registers the parser in the metadata of the target object. * - If the `required` option is set, it applies a `RequiredProperty` decorator to ensure the property must be set. * * Usage example: * ```typescript * class MyComponent { * @ElementRecord({ tag: 'my-element', required: true }) * myElement: HTMLElement; * } * ``` */ function ElementRecord(optionsOrString) { return function (target, propertyKey) { let options = optionsOrString === undefined ? { tag: (0, utilities_1.dasherize)(propertyKey) } : typeof optionsOrString === 'string' ? { tag: optionsOrString } : optionsOrString; options = (0, utilities_1.deepMerge)(options, (0, reflect_metadata_1.getMetadata)(metadata_keys_1.ElementParserMetaData.OPTIONS, target, propertyKey) || {}); if (!options.tag) { options.tag = (0, utilities_1.dasherize)(propertyKey); } AssertElementRecordOptions(options); const parser = new ElementRecordParser(propertyKey, options); (0, utilities_2.AddParserToMetadata)(parser, target); if (options.required) { (0, required_property_1.RequiredProperty)()(target, propertyKey); } }; } //# sourceMappingURL=element-record.js.map