All files / mixins PropertyMetadataInitializerMixin.ts

100% Statements 26/26
71.43% Branches 10/14
100% Functions 6/6
100% Lines 24/24

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109              9x                                   13x   13x   7x     11x       6x   6x   6x   6x   2x   2x                         11x     11x   11x     11x           19x             4x   4x   4x                 11x     11x     11x     11x         3x  
import { CustomElementMetadata, CustomElementPropertyMetadata } from "../interfaces";
 
/**
 * Initializes the properties of a custom element from the metadata configured
 * @param Base The base class to extend
 * @returns The mixin class
 */
const PropertyMetadataInitializerMixin = Base =>
 
    class PropertyMetadataInitializer extends Base {
 
        /**
         * The properties to track in the class
         */
        static properties: () => Record<string, CustomElementPropertyMetadata>;
 
        /**
         * To index the property descriptor by attribute name
         */
        private static _propertiesByAttribute: Record<string, CustomElementPropertyMetadata> = {};
 
        protected static initalizeProperties(metadata: CustomElementMetadata): void {
 
            const {
                properties
            } = this;
 
            if (properties === undefined) {
 
                return;
            }
 
            Object.entries(properties).forEach(([key, value]) => this._initializeProperty(key, value, metadata));
 
            // Add the properties of the base class if any so we can validate and initialize
            // the values of the properties of the base class in the instance
            const baseClass = Object.getPrototypeOf(this.prototype)?.constructor;
 
            Eif (baseClass !== undefined) {
 
                const baseClassMetadata = baseClass.metadata;
 
                if (baseClassMetadata !== undefined) {
 
                    metadata.properties = new Map([...metadata.properties, ...baseClassMetadata.properties]);
 
                    metadata.observedAttributes = [...metadata.observedAttributes, ...baseClassMetadata.observedAttributes];
                }
            }
        }
 
        /**
         * Creates the setters and getters for the property
         * @param name 
         * @param propertyMetadata 
         * @returns The name of the observed attribute for that property
         */
        private static _initializeProperty(name: string, propertyMetadata: CustomElementPropertyMetadata, metadata: CustomElementMetadata): void {
 
            propertyMetadata.name = name; // Set the name of the property
 
            // Set the name of the attribute as same as the name of the property if no attribute name was provided
            Eif (propertyMetadata.attribute === undefined) {
 
                propertyMetadata.attribute = name;
            }
 
            Object.defineProperty(
                this.prototype,
                name,
                {
                    get(): any {
 
                        return this._properties[name];
                    },
                    set(this: any, value: unknown) {
 
                        const {
                            attribute,
                            reflect
                        } = propertyMetadata;
 
                        const reflectOnAttribute = reflect === true ? attribute : undefined;
 
                        this.setProperty(name, value, reflectOnAttribute);
                    },
                    configurable: true,
                    enumerable: true,
                }
            );
 
            const {
                attribute
            } = propertyMetadata;
 
            // Index the property descriptor by the attribute name
            this._propertiesByAttribute[attribute] = propertyMetadata; // Index by attribute name
 
            // Add it to the metadata properties so the properties of the instances can be validated and initialized
            metadata.properties.set(name, propertyMetadata);
 
            // Add the observed attribute
            metadata.observedAttributes.push(propertyMetadata.attribute.toLowerCase());
        }
 
    }
 
export default PropertyMetadataInitializerMixin;