@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
126 lines • 6.37 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ElementAttributeSerializer = exports.ElementAttributeParser = void 0;
exports.ElementAttribute = ElementAttribute;
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 attribute_element_mixin_1 = require("./mixins/attribute-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");
let ElementAttributeParser = class ElementAttributeParser {
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) {
var _a;
let value = (_a = this.defaultValue) !== null && _a !== void 0 ? _a :
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
parsedElement[this.propertyKey];
if (element.has(this.attribute)) {
const rawValue = element.get(this.attribute, undefined, true);
value = this.parseValue(rawValue);
}
if (value === undefined) {
if (this.required) {
throw new error_1.RxapXmlParserValidateRequiredError(`The attribute '${this.attribute}' is required for <${parsedElement.__tag}>`, parsedElement.__tag, this.attribute);
}
}
else {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
parsedElement[this.propertyKey] = value;
}
return parsedElement;
}
};
exports.ElementAttributeParser = ElementAttributeParser;
exports.ElementAttributeParser = ElementAttributeParser = tslib_1.__decorate([
(0, mixin_1.Mixin)(attribute_element_mixin_1.AttributeElementMixin),
tslib_1.__metadata("design:paramtypes", [String, Object])
], ElementAttributeParser);
let ElementAttributeSerializer = class ElementAttributeSerializer {
constructor(propertyKey, options) {
this.propertyKey = propertyKey;
this.options = options;
this.serialize = this.serialize.bind(this);
Reflect.set(this.serialize, 'propertyKey', propertyKey);
}
serialize(xmlParser, element, parsedElement) {
// @ts-expect-error the propertyKey is set by the property decorator
const value = parsedElement[this.propertyKey];
if (value !== undefined) {
element.set(this.options.attribute, this.serializeValue(value));
}
else if (this.required) {
throw new error_1.RxapXmlSerializerValidateRequiredError(`The attribute '${this.attribute}' is required for <${parsedElement.__tag}>`, parsedElement.__tag, this.attribute);
}
}
};
exports.ElementAttributeSerializer = ElementAttributeSerializer;
exports.ElementAttributeSerializer = ElementAttributeSerializer = tslib_1.__decorate([
(0, mixin_1.Mixin)(attribute_element_mixin_1.AttributeElementMixin),
tslib_1.__metadata("design:paramtypes", [String, Object])
], ElementAttributeSerializer);
/**
* Decorator factory that binds a DOM element attribute to a property of a class.
* This decorator provides a way to specify custom behavior through options, allowing
* the attribute value to be parsed and handled according to the provided settings.
*
* @param optionsOrString - This parameter can either be a string specifying the name of the attribute,
* or an object containing options for configuring the attribute behavior.
* If a string is provided, it is used as the name of the attribute.
* If an object is provided, it can include any properties from `ElementAttributeOptions<Value>`.
* If omitted, the name of the property to which the decorator is applied will be used as the attribute name.
*
* @returns A decorator function that takes two parameters:
* - `target`: The prototype of the class.
* - `propertyKey`: The name of the property.
*
* The decorator initializes an `ElementAttributeParser` with the specified options, which handles
* the parsing and assignment of the attribute value to the class property. It also ensures that
* the property is registered with metadata that can be used by other parts of the system, such as
* serialization or additional validation mechanisms.
*
* If the `required` option is set to true in the options object, the property will also be decorated
* with a `RequiredProperty` decorator, enforcing that the attribute must be provided.
*
* ### Example Usage
*
* ```typescript
* class Component {
* @ElementAttribute({ attribute: 'data-id', required: true })
* id: string;
* }
* ```
*
* In this example, the `id` property of `Component` instances will be linked to the 'data-id' attribute
* of the corresponding DOM element. The attribute is marked as required, meaning it must be present.
*
*/
function ElementAttribute(optionsOrString) {
return function (target, propertyKey) {
var _a;
let options = optionsOrString === undefined ?
{ attribute: propertyKey } :
typeof optionsOrString === 'string' ? { attribute: optionsOrString } : optionsOrString;
options = (0, utilities_1.deepMerge)(options, (_a = (0, reflect_metadata_1.getMetadata)(metadata_keys_1.ElementParserMetaData.OPTIONS, target, propertyKey)) !== null && _a !== void 0 ? _a : {});
const optionsWithDefaults = Object.assign({ attribute: propertyKey }, options);
const parser = new ElementAttributeParser(propertyKey, optionsWithDefaults);
(0, add_parser_to_metadata_1.AddParserToMetadata)(parser, target);
const serializer = new ElementAttributeSerializer(propertyKey, optionsWithDefaults);
(0, add_serializer_to_metadata_1.AddSerializerToMetadata)(serializer, target);
if (optionsWithDefaults.required) {
(0, required_property_1.RequiredProperty)()(target, propertyKey);
}
};
}
//# sourceMappingURL=element-attribute.js.map