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 | 1x 5x 1x 5x 5x 5x 4x 5x 5x 1x 5x 5x | import PrjBaseData from 'src/models/Data/PrjBaseData'; /** * A unique symbol used to mark properties that should be included in the {@link PrjBaseData.mergeData} method. */ export const FieldConfigSymbol: unique symbol = Symbol('FieldConfig'); /** * Represents the field configuration properties. */ interface IFieldConfig_ { [FieldConfigSymbol]?: IFieldConfigEntry[]; } /** * Type guard to check if an object is an instance of {@link IFieldConfig_}. * @param obj The object to check. * @returns Ever `True` because the {@link FieldConfigSymbol} property is optional. */ function isIFieldConfig_(obj: unknown): obj is IFieldConfig_ { return true; } /** * Represents a entry in the field configuration. */ interface IFieldConfigEntry { key: string | number | symbol; defaultValue?: unknown; } /** * A decorator function to mark class properties for inclusion in the {@link PrjBaseData.mergeData} method. * @param defaultValue The optional default value for the field. The setter will be used with this value. * @returns A decorator function. * @remarks - The field must have a getter and setter. * - The field must be marked as `@fieldConfig` in the class. * - `@fieldConfig` in higher classes will overwrite the default value of the same field in lower classes. * - Create a {@link FieldConfigSymbol} property in the class to get the field configurations. */ export function fieldConfig(defaultValue?: unknown) { return function (target: unknown, propertyKey: string | symbol): void { // Check if the target is an object guard the optional `FieldConfigSymbol` property. Iif ( !target || typeof target !== 'object' || !(target instanceof Object) || !isIFieldConfig_(target.constructor) ) { throw new Error( 'The fieldConfig decorator can only be used on class properties.', ); } // If the class does not have a `FieldConfigSymbol` property, create it. if (!target.constructor[FieldConfigSymbol]) { target.constructor[FieldConfigSymbol] = []; } // Get the field configurations for the class. const fieldConfigs = target.constructor[FieldConfigSymbol]; // Check if the field is already in the list and.. const existingIndex = fieldConfigs.findIndex( (config: IFieldConfigEntry) => config.key === propertyKey, ); // ..if the field is not in the list, add it. if (existingIndex == -1) { // The first entry is the highest class, // allowing derived classes to overwrite standard values. fieldConfigs.push({ key: propertyKey, defaultValue, }); } }; } |