From a1691708aef0aa3bb5948aceb8ba77ee717acb9b Mon Sep 17 00:00:00 2001 From: Madeorsk Date: Mon, 23 Jun 2025 20:31:34 +0200 Subject: [PATCH] Apply prettier. --- .prettierrc | 5 + README.md | 32 +- package.json | 4 +- src/errors/index.ts | 1 - src/errors/invalid-type-value-error.ts | 15 +- src/errors/sharkitek-error.ts | 4 +- src/errors/type-error.ts | 13 +- src/library.ts | 2 +- src/model/model.ts | 374 +++++++++++------- src/model/property-definition.ts | 11 +- src/model/types/array.ts | 144 ++++--- src/model/types/boolean.ts | 15 +- src/model/types/date.ts | 28 +- src/model/types/decimal.ts | 15 +- src/model/types/map.ts | 339 ++++++++++------ src/model/types/model.ts | 149 +++++-- src/model/types/numeric.ts | 18 +- src/model/types/object.ts | 157 +++++--- src/model/types/string.ts | 12 +- src/model/types/type.ts | 41 +- src/utils.ts | 5 +- tests/errors.test.ts | 17 +- tests/model.test.ts | 290 ++++++++++---- tests/model/types/array.test.ts | 374 +++++++++++++----- tests/model/types/boolean.test.ts | 82 +++- tests/model/types/date.test.ts | 158 ++++++-- tests/model/types/decimal.test.ts | 78 +++- tests/model/types/map.test.ts | 194 +++++++--- tests/model/types/model.test.ts | 511 +++++++++++++++++++------ tests/model/types/numeric.test.ts | 78 +++- tests/model/types/object.test.ts | 245 ++++++++---- tests/model/types/string.test.ts | 88 +++-- tsconfig.json | 51 ++- vite.config.ts | 8 +- yarn.lock | 10 + 35 files changed, 2487 insertions(+), 1081 deletions(-) create mode 100644 .prettierrc diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..60ad1c3 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "useTabs": true, + "trailingComma": "all", + "bracketSpacing": false +} diff --git a/README.md b/README.md index 5ac0e97..93d76ee 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,7 @@ With Sharkitek, you define the architecture of your models by specifying their p Then, you can use the defined methods like `serialize`, `parse`, `patch` or `serializeDiff`. ```typescript -class Example -{ +class Example { static model = defineModel({ Class: Example, properties: { @@ -54,7 +53,7 @@ class Example }, identifier: "id", }); - + id: number; name: string; } @@ -70,8 +69,7 @@ class Example /** * A person. */ -class Person -{ +class Person { static model = defineModel({ Class: Person, properties: { @@ -83,7 +81,7 @@ class Person }, identifier: "id", }); - + id: number; name: string; email: string; @@ -96,8 +94,7 @@ class Person /** * An article. */ -class Article -{ +class Article { static model = defineModel({ Class: Article, properties: { @@ -109,12 +106,12 @@ class Article tags: s.property.array( s.property.object({ name: s.property.string(), - }) + }), ), }, identifier: "id", }); - + id: number; title: string; authors: Person[] = []; @@ -130,8 +127,7 @@ class Article /** * A model with composite keys. */ -class CompositeKeys -{ +class CompositeKeys { static model = defineModel({ Class: CompositeKeys, properties: { @@ -140,7 +136,7 @@ class CompositeKeys }, identifier: ["id1", "id2"], }); - + id1: number; id2: string; } @@ -225,15 +221,14 @@ Sharkitek defines some basic types by default, in these classes: When you are defining a property of a Sharkitek model, you must provide its type by instantiating one of these classes. ```typescript -class Example -{ +class Example { static model = defineModel({ Class: Example, properties: { foo: s.property.define(new StringType()), }, }); - + foo: string; } ``` @@ -253,15 +248,14 @@ To ease the use of these classes and reduce read complexity, properties of each Type implementers should provide a corresponding function for each defined type. They can even provide multiple functions or constants with predefined parameters. For example, we could define `s.property.stringArray()` which would be similar to `s.property.array(s.property.string())`. ```typescript -class Example -{ +class Example { static model = defineModel({ Class: Example, properties: { foo: s.property.string(), }, }); - + foo: string; } ``` diff --git a/package.json b/package.json index 0b1f8d4..95f9144 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "scripts": { "build": "tsc && vite build", "test": "vitest", - "coverage": "vitest run --coverage" + "coverage": "vitest run --coverage", + "format": "prettier . --write" }, "type": "module", "source": "src/library.ts", @@ -37,6 +38,7 @@ "devDependencies": { "@types/node": "^22.13.14", "@vitest/coverage-v8": "^3.0.9", + "prettier": "^3.6.0", "ts-node": "^10.9.2", "typescript": "^5.8.2", "vite": "^6.2.3", diff --git a/src/errors/index.ts b/src/errors/index.ts index e80b46a..5d1d67b 100644 --- a/src/errors/index.ts +++ b/src/errors/index.ts @@ -1,4 +1,3 @@ - export * from "./sharkitek-error"; export * from "./type-error"; export * from "./invalid-type-value-error"; diff --git a/src/errors/invalid-type-value-error.ts b/src/errors/invalid-type-value-error.ts index d71fde8..af0a904 100644 --- a/src/errors/invalid-type-value-error.ts +++ b/src/errors/invalid-type-value-error.ts @@ -4,10 +4,15 @@ import {Type} from "../model/types/type"; /** * A Sharkitek type error when the passed value is invalid. */ -export class InvalidTypeValueError extends TypeError -{ - constructor(public type: Type, public value: any, message?: string) - { - super(type, message ?? `${JSON.stringify(value)} is an invalid value`) +export class InvalidTypeValueError extends TypeError< + SerializedType, + ModelType +> { + constructor( + public type: Type, + public value: any, + message?: string, + ) { + super(type, message ?? `${JSON.stringify(value)} is an invalid value`); } } diff --git a/src/errors/sharkitek-error.ts b/src/errors/sharkitek-error.ts index a30ab6f..2c54704 100644 --- a/src/errors/sharkitek-error.ts +++ b/src/errors/sharkitek-error.ts @@ -1,6 +1,4 @@ /** * A Sharkitek error. */ -export class SharkitekError extends Error -{ -} +export class SharkitekError extends Error {} diff --git a/src/errors/type-error.ts b/src/errors/type-error.ts index af87c60..c00659d 100644 --- a/src/errors/type-error.ts +++ b/src/errors/type-error.ts @@ -4,10 +4,13 @@ import {Type} from "../model/types/type"; /** * A Sharkitek type error. */ -export class TypeError extends SharkitekError -{ - constructor(public type: Type, message?: string) - { - super(`Error in type ${type.constructor.name}${message ? `: ${message}` : ""}`); +export class TypeError extends SharkitekError { + constructor( + public type: Type, + message?: string, + ) { + super( + `Error in type ${type.constructor.name}${message ? `: ${message}` : ""}`, + ); } } diff --git a/src/library.ts b/src/library.ts index cd63347..fffb671 100644 --- a/src/library.ts +++ b/src/library.ts @@ -1,5 +1,5 @@ import * as s from "./model"; export * from "./model"; export * from "./errors"; -export { s }; +export {s}; export default s; diff --git a/src/model/model.ts b/src/model/model.ts index 590bb62..b67d2e7 100644 --- a/src/model/model.ts +++ b/src/model/model.ts @@ -11,7 +11,10 @@ export type ModelShape = Partial<{ /** * Properties values of a model based on its shape. */ -export type ModelPropertiesValues> = { +export type ModelPropertiesValues< + T extends object, + Shape extends ModelShape, +> = { [k in keyof Shape]: Shape[k]["_sharkitek"]; }; @@ -26,20 +29,38 @@ export type SerializedModel> = { * This is an experimental serialized model type declaration. * @deprecated */ -type ExperimentalSerializedModel> - = Omit, ExperimentalSerializedModelOptionalKeys> - & Pick>, ExperimentalSerializedModelOptionalKeys>; -type ExperimentalSerializedModelBase> = { +type ExperimentalSerializedModel< + T extends object, + Shape extends ModelShape, +> = Omit< + ExperimentalSerializedModelBase, + ExperimentalSerializedModelOptionalKeys +> & + Pick< + Partial>, + ExperimentalSerializedModelOptionalKeys + >; +type ExperimentalSerializedModelBase< + T extends object, + Shape extends ModelShape, +> = { [k in keyof Shape]: Shape[k]["_serialized"]; }; -type ExperimentalSerializedModelOptionalKeys> = { - [k in keyof Shape]: Shape[k]["_serialized"] extends undefined ? k : never +type ExperimentalSerializedModelOptionalKeys< + T extends object, + Shape extends ModelShape, +> = { + [k in keyof Shape]: Shape[k]["_serialized"] extends undefined ? k : never; }[keyof Shape]; /** * A sharkitek model instance, with internal model state. */ -export type ModelInstance, Identifier extends IdentifierDefinition> = T & { +export type ModelInstance< + T extends object, + Shape extends ModelShape, + Identifier extends IdentifierDefinition, +> = T & { /** * The Sharkitek model state. */ @@ -49,19 +70,34 @@ export type ModelInstance, Identif /** * Identifier definition type. */ -export type IdentifierDefinition> = (keyof Shape)|((keyof Shape)[]); +export type IdentifierDefinition< + T extends object, + Shape extends ModelShape, +> = keyof Shape | (keyof Shape)[]; /** * Identifier type. */ -export type IdentifierType, Identifier extends IdentifierDefinition> - = Identifier extends keyof Shape ? Shape[Identifier]["_sharkitek"] : { [K in keyof Identifier]: Identifier[K] extends keyof Shape ? Shape[Identifier[K]]["_sharkitek"] : unknown }; +export type IdentifierType< + T extends object, + Shape extends ModelShape, + Identifier extends IdentifierDefinition, +> = Identifier extends keyof Shape + ? Shape[Identifier]["_sharkitek"] + : { + [K in keyof Identifier]: Identifier[K] extends keyof Shape + ? Shape[Identifier[K]]["_sharkitek"] + : unknown; + }; /** * A model definition object. */ -export interface ModelDefinition, Identifier extends IdentifierDefinition> -{ +export interface ModelDefinition< + T extends object, + Shape extends ModelShape, + Identifier extends IdentifierDefinition, +> { /** * Model class. */ @@ -83,8 +119,7 @@ export interface ModelDefinition, /** * A model property. */ -export interface ModelProperty> -{ +export interface ModelProperty> { /** * Property name. */ @@ -104,13 +139,19 @@ export interface ModelProperty> /** * Model properties iterator object. */ -export type ModelProperties> = ModelProperty[]; +export type ModelProperties< + T extends object, + Shape extends ModelShape, +> = ModelProperty[]; /** * A Sharkitek model state. */ -export class Model, Identifier extends IdentifierDefinition> -{ +export class Model< + T extends object, + Shape extends ModelShape, + Identifier extends IdentifierDefinition, +> { /** * The model manager instance. */ @@ -144,15 +185,14 @@ export class Model, Identifier ext /** * The original serialized object, if there is one. */ - serialized: SerializedModel|null; + serialized: SerializedModel | null; }; /** * Initialize a new model state with the defined properties. * @param manager The model manager. */ - constructor(manager: ModelManager) - { + constructor(manager: ModelManager) { this.manager = manager; this.definition = manager.definition; this.properties = manager.properties; @@ -161,11 +201,10 @@ export class Model, Identifier ext /** * Initialize the Sharkitek model state for a new instance. */ - initInstance(): this - { + initInstance(): this { return this.fromInstance( // Initialize a new model instance. - new (this.definition.Class)() + new this.definition.Class(), ); } @@ -173,8 +212,7 @@ export class Model, Identifier ext * Initialize the Sharkitek model state for the provided instance. * @param instance The model instance. */ - fromInstance(instance: T): this - { + fromInstance(instance: T): this { // Initialize the sharkitek model instance. const sharkitekInstance = instance as ModelInstance; @@ -188,8 +226,8 @@ export class Model, Identifier ext if (originalInstance) // Share the same original values object. this.original = originalInstance.original; - else - { // Initialize a new original values object, based on the current values of the instance. + else { + // Initialize a new original values object, based on the current values of the instance. this.original = { properties: undefined, serialized: null, @@ -204,14 +242,14 @@ export class Model, Identifier ext * Deserialize provided data to a new model instance. * @param serialized Serialized model. */ - deserialize(serialized: SerializedModel): this - { + deserialize(serialized: SerializedModel): this { // Initialize a new model instance. this.initInstance(); - for (const property of this.properties) - { // For each defined model property, assigning its deserialized value. - (this.instance[property.name as keyof T] as any) = property.definition.type.deserialize(serialized[property.name]); + for (const property of this.properties) { + // For each defined model property, assigning its deserialized value. + (this.instance[property.name as keyof T] as any) = + property.definition.type.deserialize(serialized[property.name]); } // Reset original property values. @@ -225,29 +263,31 @@ export class Model, Identifier ext /** * Get current model instance identifier. */ - getIdentifier(): IdentifierType - { - if (Array.isArray(this.definition.identifier)) - { // The identifier is composite, make an array of properties values. - return this.definition.identifier.map(identifier => this.instance?.[identifier as keyof T]) as IdentifierType; - } - else - { // The identifier is a simple property, get its value. - return this.instance?.[this.definition.identifier as keyof Shape as keyof T] as IdentifierType; + getIdentifier(): IdentifierType { + if (Array.isArray(this.definition.identifier)) { + // The identifier is composite, make an array of properties values. + return this.definition.identifier.map( + (identifier) => this.instance?.[identifier as keyof T], + ) as IdentifierType; + } else { + // The identifier is a simple property, get its value. + return this.instance?.[ + this.definition.identifier as keyof Shape as keyof T + ] as IdentifierType; } } /** * Get current model instance properties. */ - getInstanceProperties(): ModelPropertiesValues - { + getInstanceProperties(): ModelPropertiesValues { // Initialize an empty model properties object. const instanceProperties: Partial> = {}; - for (const property of this.properties) - { // For each defined model property, adding it to the properties object. - instanceProperties[property.name] = this.instance?.[property.name as keyof T]; // keyof Shape is a subset of keyof T. + for (const property of this.properties) { + // For each defined model property, adding it to the properties object. + instanceProperties[property.name] = + this.instance?.[property.name as keyof T]; // keyof Shape is a subset of keyof T. } return instanceProperties as ModelPropertiesValues; // Returning the properties object. @@ -256,13 +296,12 @@ export class Model, Identifier ext /** * Serialize the model instance. */ - serialize(): SerializedModel - { + serialize(): SerializedModel { // Creating an empty serialized object. const serializedObject: Partial> = {}; - for (const property of this.properties) - { // For each defined model property, adding it to the serialized object. + for (const property of this.properties) { + // For each defined model property, adding it to the serialized object. serializedObject[property.name] = property.definition.type.serialize( // keyof Shape is a subset of keyof T. this.instance?.[property.name as keyof T], @@ -275,19 +314,22 @@ export class Model, Identifier ext /** * Examine if the model is new (never deserialized) or not. */ - isNew(): boolean - { + isNew(): boolean { return !this.original.serialized; } /** * Examine if the model is dirty or not. */ - isDirty(): boolean - { - for (const property of this.properties) - { // For each property, check if it is different. - if (property.definition.type.hasChanged(this.original.properties?.[property.name], this.instance?.[property.name as keyof T])) + isDirty(): boolean { + for (const property of this.properties) { + // For each property, check if it is different. + if ( + property.definition.type.hasChanged( + this.original.properties?.[property.name], + this.instance?.[property.name as keyof T], + ) + ) // There is a difference: the model is dirty. return true; } @@ -299,19 +341,23 @@ export class Model, Identifier ext /** * Serialize the difference between current model state and the original one. */ - serializeDiff(): Partial> - { + serializeDiff(): Partial> { // Creating an empty serialized object. const serializedObject: Partial> = {}; - for (const property of this.properties) - { // For each defined model property, adding it to the serialized object if it has changed or if it is in the identifier. + for (const property of this.properties) { + // For each defined model property, adding it to the serialized object if it has changed or if it is in the identifier. const instancePropValue = this.instance?.[property.name as keyof T]; // keyof Shape is a subset of keyof T. if ( property.identifier || - property.definition.type.hasChanged(this.original.properties?.[property.name], instancePropValue) - ) // The property is part of the identifier or its value has changed. - serializedObject[property.name] = property.definition.type.serializeDiff(instancePropValue); + property.definition.type.hasChanged( + this.original.properties?.[property.name], + instancePropValue, + ) + ) + // The property is part of the identifier or its value has changed. + serializedObject[property.name] = + property.definition.type.serializeDiff(instancePropValue); } return serializedObject; // Returning the serialized object. @@ -320,13 +366,13 @@ export class Model, Identifier ext /** * Set current model properties as original values. */ - resetDiff(): void - { + resetDiff(): void { this.original.properties = {}; - for (const property of this.properties) - { // For each property, set its original value to the current property value. + for (const property of this.properties) { + // For each property, set its original value to the current property value. const instancePropValue = this.instance?.[property.name as keyof T]; - this.original.properties[property.name] = property.definition.type.clone(instancePropValue); + this.original.properties[property.name] = + property.definition.type.clone(instancePropValue); property.definition.type.resetDiff(instancePropValue); } } @@ -335,8 +381,7 @@ export class Model, Identifier ext * Get difference between original values and current ones, then reset it. * Similar to call `serializeDiff()` then `resetDiff()`. */ - patch(): Partial> - { + patch(): Partial> { // Get the difference. const diff = this.serializeDiff(); @@ -349,32 +394,36 @@ export class Model, Identifier ext /** * Clone the model instance. */ - clone(): ModelInstance - { + clone(): ModelInstance { // Initialize a new instance for the clone. const cloned = this.manager.model(); // Clone every value of the model instance. - for (const [key, value] of Object.entries(this.instance) as [keyof T, unknown][]) - { // For each [key, value], clone the value and put it in the cloned instance. + for (const [key, value] of Object.entries(this.instance) as [ + keyof T, + unknown, + ][]) { + // For each [key, value], clone the value and put it in the cloned instance. // Do not clone ourselves. if (key == "_sharkitek") continue; - if (this.definition.properties[key]) - { // The current key is a defined property, clone using the defined type. - (cloned.instance[key] as any) = (this.definition.properties[key] as UnknownDefinition).type.clone(value); - } - else - { // Not a property, cloning the raw value. + if (this.definition.properties[key]) { + // The current key is a defined property, clone using the defined type. + (cloned.instance[key] as any) = ( + this.definition.properties[key] as UnknownDefinition + ).type.clone(value); + } else { + // Not a property, cloning the raw value. (cloned.instance[key] as any) = structuredClone(value); } } // Clone original properties. - for (const property of this.properties) - { // For each property, clone its original value. - cloned.original.properties[property.name] = property.definition.type.clone(this.original.properties[property.name]); + for (const property of this.properties) { + // For each property, clone its original value. + cloned.original.properties[property.name] = + property.definition.type.clone(this.original.properties[property.name]); } // Clone original serialized. @@ -388,10 +437,11 @@ export class Model, Identifier ext * Fields that cannot be matched to existing properties are silently ignored. * @param fields The fields to assign to the model. */ - assign(fields: Partial> & {[field: string]: any}): ModelInstance - { - for (const field in fields) - { // For each field, if it's a property, assign its value. + assign( + fields: Partial> & {[field: string]: any}, + ): ModelInstance { + for (const field in fields) { + // For each field, if it's a property, assign its value. if ((this.definition.properties as any)?.[field]) // Set the instance value. this.instance[field as keyof T] = fields[field]; @@ -404,26 +454,38 @@ export class Model, Identifier ext * @param patch The patch object to apply. * @param updateOriginals Indicates if the original properties values must be updated or not. By default, they are reset. */ - applyPatch(patch: SerializedModel, updateOriginals: boolean = true): ModelInstance - { - if (updateOriginals) - { // If serialized original is null and we need to update it, initialize it. + applyPatch( + patch: SerializedModel, + updateOriginals: boolean = true, + ): ModelInstance { + if (updateOriginals) { + // If serialized original is null and we need to update it, initialize it. this.original.serialized = this.serialize(); } - for (const serializedField in patch) - { // For each field, if it's a property, assign its value. + for (const serializedField in patch) { + // For each field, if it's a property, assign its value. // Get the property definition. - const property = this.definition.properties[serializedField as keyof Shape]; - if (property) - { // Found a matching model property, assigning its deserialized value. - (this.instance[serializedField as keyof Shape as keyof T] as any) = - (property as UnknownDefinition).type.applyPatch(this.instance[serializedField as keyof Shape as keyof T], patch[serializedField], updateOriginals); + const property = + this.definition.properties[serializedField as keyof Shape]; + if (property) { + // Found a matching model property, assigning its deserialized value. + (this.instance[serializedField as keyof Shape as keyof T] as any) = ( + property as UnknownDefinition + ).type.applyPatch( + this.instance[serializedField as keyof Shape as keyof T], + patch[serializedField], + updateOriginals, + ); - if (updateOriginals) - { // Update original values. + if (updateOriginals) { + // Update original values. // Set original property value. - (this.original.properties[serializedField] as any) = (property as UnknownDefinition).type.clone(this.instance[serializedField as keyof Shape as keyof T]); + (this.original.properties[serializedField] as any) = ( + property as UnknownDefinition + ).type.clone( + this.instance[serializedField as keyof Shape as keyof T], + ); // Set original serialized value. this.original.serialized[serializedField] = patch[serializedField]; } @@ -433,13 +495,14 @@ export class Model, Identifier ext } } - - /** * A model manager, created from a model definition. */ -export class ModelManager, Identifier extends IdentifierDefinition> -{ +export class ModelManager< + T extends object, + Shape extends ModelShape, + Identifier extends IdentifierDefinition, +> { /** * Defined properties. */ @@ -449,8 +512,9 @@ export class ModelManager, Identif * Initialize a model manager from a model definition. * @param definition The model definition. */ - constructor(public readonly definition: ModelDefinition) - { + constructor( + public readonly definition: ModelDefinition, + ) { this.initProperties(); } @@ -458,23 +522,22 @@ export class ModelManager, Identif * Initialize properties iterator from current definition. * @protected */ - protected initProperties(): void - { + protected initProperties(): void { // Build an array of model properties from the definition. this.properties = []; - for (const propertyName in this.definition.properties) - { // For each property, build a model property object. + for (const propertyName in this.definition.properties) { + // For each property, build a model property object. this.properties.push({ name: propertyName, definition: this.definition.properties[propertyName], // Find out if the current property is part of the identifier. - identifier: ( - Array.isArray(this.definition.identifier) - // The identifier is an array, the property must be in the array. - ? this.definition.identifier.includes(propertyName as keyof Shape as keyof T) - // The identifier is a single string, the property must be the defined identifier. - : (this.definition.identifier == propertyName as keyof Shape) - ), + identifier: Array.isArray(this.definition.identifier) + ? // The identifier is an array, the property must be in the array. + this.definition.identifier.includes( + propertyName as keyof Shape as keyof T, + ) + : // The identifier is a single string, the property must be the defined identifier. + this.definition.identifier == (propertyName as keyof Shape), } as ModelProperty); } } @@ -483,14 +546,19 @@ export class ModelManager, Identif * Get the model state of the provided model instance. * @param instance The model instance for which to get its state. NULL or undefined to create a new one. */ - model(instance: T|ModelInstance|null = null): Model - { // Get the instance model state if there is one, or initialize a new one. + model( + instance: T | ModelInstance | null = null, + ): Model { + // Get the instance model state if there is one, or initialize a new one. if (instance) // There is an instance, create a model from it. - return ((instance as ModelInstance)?._sharkitek ?? (new Model(this))).fromInstance(instance); + return ( + (instance as ModelInstance)?._sharkitek ?? + new Model(this) + ).fromInstance(instance); else // No instance, initialize a new one. - return (new Model(this)).initInstance(); + return new Model(this).initInstance(); } /** @@ -498,8 +566,9 @@ export class ModelManager, Identif * Fields that cannot be matched to existing properties are silently ignored. * @param fields */ - from(fields: Partial> & {[field: string]: any}): ModelInstance - { + from( + fields: Partial> & {[field: string]: any}, + ): ModelInstance { return this.model().assign(fields); } @@ -507,8 +576,9 @@ export class ModelManager, Identif * Parse the serialized model object to a new model instance. * @param serialized The serialized model object. */ - parse(serialized: SerializedModel): ModelInstance - { + parse( + serialized: SerializedModel, + ): ModelInstance { return this.model().deserialize(serialized).instance; } } @@ -517,10 +587,11 @@ export class ModelManager, Identif * Define a new model. * @param definition The model definition object. */ -export function defineModel, Identifier extends IdentifierDefinition>( - definition: ModelDefinition -) -{ +export function defineModel< + T extends object, + Shape extends ModelShape, + Identifier extends IdentifierDefinition, +>(definition: ModelDefinition) { return new ModelManager(definition); } @@ -530,16 +601,21 @@ export function defineModel, Ident * @param definition The extension of the model definition object. */ export function extend< - ExtT extends object, ExtShape extends ModelShape, ExtIdentifier extends IdentifierDefinition, - T extends ExtT, Shape extends ModelShape, Identifier extends IdentifierDefinition, - ResIdentifier extends IdentifierDefinition, ResShape extends ModelShape = Modify + ExtT extends object, + ExtShape extends ModelShape, + ExtIdentifier extends IdentifierDefinition, + T extends ExtT, + Shape extends ModelShape, + Identifier extends IdentifierDefinition, + ResIdentifier extends IdentifierDefinition, + ResShape extends ModelShape = Modify, >( extendedModel: ModelManager, definition: ModelDefinition, -) -{ - const { properties: extendedProperties, ...overridableDefinition } = extendedModel.definition; - const { properties: propertiesExtension, ...definitionExtension } = definition; +) { + const {properties: extendedProperties, ...overridableDefinition} = + extendedModel.definition; + const {properties: propertiesExtension, ...definitionExtension} = definition; return new ModelManager({ ...overridableDefinition, ...definitionExtension, @@ -553,15 +629,25 @@ export function extend< /** * A generic model manager for a provided model type, to use in circular dependencies. */ -export type GenericModelManager = ModelManager, IdentifierDefinition>>; +export type GenericModelManager = ModelManager< + T, + ModelShape, + IdentifierDefinition> +>; /** * Function to get a model manager lazily. */ -export type LazyModelManager, Identifier extends IdentifierDefinition> - = (() => ModelManager); +export type LazyModelManager< + T extends object, + Shape extends ModelShape, + Identifier extends IdentifierDefinition, +> = () => ModelManager; /** * A model manager definition that can be lazy. */ -export type DeclaredModelManager, Identifier extends IdentifierDefinition> - = ModelManager|LazyModelManager; +export type DeclaredModelManager< + T extends object, + Shape extends ModelShape, + Identifier extends IdentifierDefinition, +> = ModelManager | LazyModelManager; diff --git a/src/model/property-definition.ts b/src/model/property-definition.ts index c5f8d86..1b7fb77 100644 --- a/src/model/property-definition.ts +++ b/src/model/property-definition.ts @@ -3,8 +3,7 @@ import {Type} from "./types/type"; /** * Property definition class. */ -export class Definition -{ +export class Definition { readonly _sharkitek: ModelType; readonly _serialized: SerializedType; @@ -12,8 +11,7 @@ export class Definition * Create a property definer instance. * @param type Property type. */ - constructor(public readonly type: Type) - {} + constructor(public readonly type: Type) {} } /** @@ -30,7 +28,8 @@ export type AnyDefinition = Definition; * New definition of a property of the given type. * @param type Type of the property to define. */ -export function define(type: Type): Definition -{ +export function define( + type: Type, +): Definition { return new Definition(type); } diff --git a/src/model/types/array.ts b/src/model/types/array.ts index fee8198..01bff94 100644 --- a/src/model/types/array.ts +++ b/src/model/types/array.ts @@ -5,56 +5,70 @@ import {InvalidTypeValueError} from "../../errors"; /** * Type of an array of values. */ -export class ArrayType extends Type -{ +export class ArrayType extends Type< + SerializedValueType[], + SharkitekValueType[] +> { /** * Initialize a new array type of a Sharkitek model property. * @param valueDefinition Definition the array values. */ - constructor(protected valueDefinition: Definition) - { + constructor( + protected valueDefinition: Definition< + SerializedValueType, + SharkitekValueType + >, + ) { super(); } - serialize(value: SharkitekValueType[]|null|undefined): SerializedValueType[]|null|undefined - { + serialize( + value: SharkitekValueType[] | null | undefined, + ): SerializedValueType[] | null | undefined { if (value === undefined) return undefined; if (value === null) return null; - if (!Array.isArray(value)) throw new InvalidTypeValueError(this, value, "value must be an array"); + if (!Array.isArray(value)) + throw new InvalidTypeValueError(this, value, "value must be an array"); - return value.map((value) => ( + return value.map((value) => // Serializing each value of the array. - this.valueDefinition.type.serialize(value) - )); + this.valueDefinition.type.serialize(value), + ); } - deserialize(value: SerializedValueType[]|null|undefined): SharkitekValueType[]|null|undefined - { + deserialize( + value: SerializedValueType[] | null | undefined, + ): SharkitekValueType[] | null | undefined { if (value === undefined) return undefined; if (value === null) return null; - if (!Array.isArray(value)) throw new InvalidTypeValueError(this, value, "value must be an array"); + if (!Array.isArray(value)) + throw new InvalidTypeValueError(this, value, "value must be an array"); - return value.map((serializedValue) => ( + return value.map((serializedValue) => // Deserializing each value of the array. - this.valueDefinition.type.deserialize(serializedValue) - )); + this.valueDefinition.type.deserialize(serializedValue), + ); } - serializeDiff(value: SharkitekValueType[]|null|undefined): SerializedValueType[]|null|undefined - { + serializeDiff( + value: SharkitekValueType[] | null | undefined, + ): SerializedValueType[] | null | undefined { if (value === undefined) return undefined; if (value === null) return null; - if (!Array.isArray(value)) throw new InvalidTypeValueError(this, value, "value must be an array"); + if (!Array.isArray(value)) + throw new InvalidTypeValueError(this, value, "value must be an array"); // Serializing diff of all elements. - return value.map((value) => this.valueDefinition.type.serializeDiff(value) as SerializedValueType); + return value.map( + (value) => + this.valueDefinition.type.serializeDiff(value) as SerializedValueType, + ); } - resetDiff(value: SharkitekValueType[]|null|undefined): void - { + resetDiff(value: SharkitekValueType[] | null | undefined): void { // Do nothing if it is not an array. if (!Array.isArray(value)) return; @@ -62,16 +76,24 @@ export class ArrayType extends Type this.valueDefinition.type.resetDiff(value)); } - hasChanged(originalValue: SharkitekValueType[]|null|undefined, currentValue: SharkitekValueType[]|null|undefined): boolean - { + hasChanged( + originalValue: SharkitekValueType[] | null | undefined, + currentValue: SharkitekValueType[] | null | undefined, + ): boolean { // If any array length is different, arrays are different. if (originalValue?.length != currentValue?.length) return true; // If length is undefined, values are probably not arrays. - if (originalValue?.length == undefined) return super.hasChanged(originalValue, currentValue); + if (originalValue?.length == undefined) + return super.hasChanged(originalValue, currentValue); - for (const key of originalValue.keys()) - { // Check for any change for each value in the array. - if (this.valueDefinition.type.hasChanged(originalValue[key], currentValue[key])) + for (const key of originalValue.keys()) { + // Check for any change for each value in the array. + if ( + this.valueDefinition.type.hasChanged( + originalValue[key], + currentValue[key], + ) + ) // The value has changed, the array is different. return true; } @@ -79,16 +101,24 @@ export class ArrayType extends Type extends Type(array: T|null|undefined): T - { + clone(array: T | null | undefined): T { // Handle NULL / undefined array. if (!array) return super.clone(array); - if (!Array.isArray(array)) throw new InvalidTypeValueError(this, array, "value must be an array"); + if (!Array.isArray(array)) + throw new InvalidTypeValueError(this, array, "value must be an array"); // Initialize an empty array. const cloned = [] as T; - for (const value of array) - { // Clone each value of the array. + for (const value of array) { + // Clone each value of the array. cloned.push(this.valueDefinition.type.clone(value)); } return cloned; // Returning cloned array. } - applyPatch(currentValue: T|null|undefined, patchValue: SerializedValueType[]|null|undefined, updateOriginals: boolean): T|null|undefined - { + applyPatch( + currentValue: T | null | undefined, + patchValue: SerializedValueType[] | null | undefined, + updateOriginals: boolean, + ): T | null | undefined { if (patchValue === undefined) return undefined; if (patchValue === null) return null; if (!Array.isArray(patchValue)) - throw new InvalidTypeValueError(this, patchValue, "value must be an array"); + throw new InvalidTypeValueError( + this, + patchValue, + "value must be an array", + ); - currentValue = Array.isArray(currentValue) ? currentValue : [] as T; + currentValue = Array.isArray(currentValue) ? currentValue : ([] as T); - for (let i = 0; i < patchValue.length; i++) - { // Apply the patch to all values of the array. - const patchedElement = this.valueDefinition.type.applyPatch(currentValue?.[i], patchValue[i], updateOriginals); - if (i < currentValue.length) - currentValue[i] = patchedElement; - else - currentValue.push(patchedElement); + for (let i = 0; i < patchValue.length; i++) { + // Apply the patch to all values of the array. + const patchedElement = this.valueDefinition.type.applyPatch( + currentValue?.[i], + patchValue[i], + updateOriginals, + ); + if (i < currentValue.length) currentValue[i] = patchedElement; + else currentValue.push(patchedElement); } return currentValue; @@ -141,7 +180,8 @@ export class ArrayType extends Type(valueDefinition: Definition): Definition -{ +export function array( + valueDefinition: Definition, +): Definition { return define(new ArrayType(valueDefinition)); } diff --git a/src/model/types/boolean.ts b/src/model/types/boolean.ts index 77e26c8..7fd742a 100644 --- a/src/model/types/boolean.ts +++ b/src/model/types/boolean.ts @@ -4,10 +4,8 @@ import {define, Definition} from "../property-definition"; /** * Type of any boolean value. */ -export class BooleanType extends Type -{ - deserialize(value: boolean|null|undefined): boolean|null|undefined - { +export class BooleanType extends Type { + deserialize(value: boolean | null | undefined): boolean | null | undefined { // Keep NULL and undefined values. if (value === undefined) return undefined; if (value === null) return null; @@ -15,8 +13,7 @@ export class BooleanType extends Type return !!value; // ensure bool type. } - serialize(value: boolean|null|undefined): boolean|null|undefined - { + serialize(value: boolean | null | undefined): boolean | null | undefined { // Keep NULL and undefined values. if (value === undefined) return undefined; if (value === null) return null; @@ -28,15 +25,13 @@ export class BooleanType extends Type /** * New boolean property definition. */ -export function boolean(): Definition -{ +export function boolean(): Definition { return define(new BooleanType()); } /** * New boolean property definition. * Alias of boolean. */ -export function bool(): ReturnType -{ +export function bool(): ReturnType { return boolean(); } diff --git a/src/model/types/date.ts b/src/model/types/date.ts index 21af282..eaab3db 100644 --- a/src/model/types/date.ts +++ b/src/model/types/date.ts @@ -5,30 +5,30 @@ import {InvalidTypeValueError} from "../../errors"; /** * Type of dates. */ -export class DateType extends Type -{ - deserialize(value: string|null|undefined): Date|null|undefined - { +export class DateType extends Type { + deserialize(value: string | null | undefined): Date | null | undefined { if (value === undefined) return undefined; if (value === null) return null; return new Date(value); } - serialize(value: Date|null|undefined): string|null|undefined - { + serialize(value: Date | null | undefined): string | null | undefined { if (value === undefined) return undefined; if (value === null) return null; - if (!(value instanceof Date)) throw new InvalidTypeValueError(this, value, "value must be a date"); + if (!(value instanceof Date)) + throw new InvalidTypeValueError(this, value, "value must be a date"); if (isNaN(value?.valueOf())) return value?.toString(); return value?.toISOString(); } - hasChanged(originalValue: Date|null|undefined, currentValue: Date|null|undefined): boolean - { - if (originalValue instanceof Date && currentValue instanceof Date) - { // Compare dates. + hasChanged( + originalValue: Date | null | undefined, + currentValue: Date | null | undefined, + ): boolean { + if (originalValue instanceof Date && currentValue instanceof Date) { + // Compare dates. const originalTime = originalValue.getTime(); const currentTime = currentValue.getTime(); @@ -37,8 +37,7 @@ export class DateType extends Type // Timestamps need to be exactly the same. return originalValue.getTime() !== currentValue.getTime(); - } - else + } else // Compare undefined or null values. return originalValue !== currentValue; } @@ -47,7 +46,6 @@ export class DateType extends Type /** * New date property definition. */ -export function date(): Definition -{ +export function date(): Definition { return define(new DateType()); } diff --git a/src/model/types/decimal.ts b/src/model/types/decimal.ts index fe2d35a..1f98a3a 100644 --- a/src/model/types/decimal.ts +++ b/src/model/types/decimal.ts @@ -5,21 +5,19 @@ import {InvalidTypeValueError} from "../../errors"; /** * Type of decimal numbers. */ -export class DecimalType extends Type -{ - deserialize(value: string|null|undefined): number|null|undefined - { +export class DecimalType extends Type { + deserialize(value: string | null | undefined): number | null | undefined { if (value === undefined) return undefined; if (value === null) return null; return parseFloat(value); } - serialize(value: number|null|undefined): string|null|undefined - { + serialize(value: number | null | undefined): string | null | undefined { if (value === undefined) return undefined; if (value === null) return null; - if (typeof value !== "number" && typeof value !== "string") throw new InvalidTypeValueError(this, value, "value must be a number"); + if (typeof value !== "number" && typeof value !== "string") + throw new InvalidTypeValueError(this, value, "value must be a number"); return value?.toString(); } @@ -28,7 +26,6 @@ export class DecimalType extends Type /** * New decimal property definition. */ -export function decimal(): Definition -{ +export function decimal(): Definition { return define(new DecimalType()); } diff --git a/src/model/types/map.ts b/src/model/types/map.ts index 147f739..f8873b9 100644 --- a/src/model/types/map.ts +++ b/src/model/types/map.ts @@ -1,155 +1,219 @@ import {Type} from "./type"; import {define, Definition} from "../property-definition"; import {InvalidTypeValueError} from "../../errors"; -import {type} from "node:os"; import {string} from "./string"; /** * Type of a key-value map. */ -export class MapType = Record> extends Type> -{ - /** - * Initialize a new map type of a Sharkitek model property. - * @param keyDefinition Definition of the map keys. - * @param valueDefinition Definition of the map values. - */ - constructor( - protected keyDefinition: Definition, - protected valueDefinition: Definition, - ) - { - super(); - } +export class MapType< + KeyType, + ValueType, + SerializedValueType, + SerializedMapType extends Record = Record< + string, + SerializedValueType + >, +> extends Type> { + /** + * Initialize a new map type of a Sharkitek model property. + * @param keyDefinition Definition of the map keys. + * @param valueDefinition Definition of the map values. + */ + constructor( + protected keyDefinition: Definition, + protected valueDefinition: Definition, + ) { + super(); + } - serialize(value: Map|null|undefined): SerializedMapType|null|undefined - { - if (value === undefined) return undefined; - if (value === null) return null; + serialize( + value: Map | null | undefined, + ): SerializedMapType | null | undefined { + if (value === undefined) return undefined; + if (value === null) return null; - if (!(value instanceof Map)) throw new InvalidTypeValueError(this, value, "value must be an instance of map"); + if (!(value instanceof Map)) + throw new InvalidTypeValueError( + this, + value, + "value must be an instance of map", + ); - return Object.fromEntries( - // Serializing each key-value pair of the map. - value.entries().map(([key, value]) => - ([this.keyDefinition.type.serialize(key), this.valueDefinition.type.serialize(value)])) - ) as SerializedMapType; - } + return Object.fromEntries( + // Serializing each key-value pair of the map. + value + .entries() + .map(([key, value]) => [ + this.keyDefinition.type.serialize(key), + this.valueDefinition.type.serialize(value), + ]), + ) as SerializedMapType; + } - deserialize(value: SerializedMapType|null|undefined): Map|null|undefined - { - if (value === undefined) return undefined; - if (value === null) return null; + deserialize( + value: SerializedMapType | null | undefined, + ): Map | null | undefined { + if (value === undefined) return undefined; + if (value === null) return null; - if (typeof value !== "object" || Array.isArray(value)) throw new InvalidTypeValueError(this, value, "value must be an object"); + if (typeof value !== "object" || Array.isArray(value)) + throw new InvalidTypeValueError(this, value, "value must be an object"); - const map = new Map; - for (const [serializedKey, serializedValue] of Object.entries(value)) - { // Deserializing each key-value pair of the map. - map.set(this.keyDefinition.type.deserialize(serializedKey), this.valueDefinition.type.deserialize(serializedValue)); - } + const map = new Map(); + for (const [serializedKey, serializedValue] of Object.entries(value)) { + // Deserializing each key-value pair of the map. + map.set( + this.keyDefinition.type.deserialize(serializedKey), + this.valueDefinition.type.deserialize(serializedValue), + ); + } - return map; - } + return map; + } - serializeDiff(value: Map|null|undefined): SerializedMapType|null|undefined - { - if (value === undefined) return undefined; - if (value === null) return null; + serializeDiff( + value: Map | null | undefined, + ): SerializedMapType | null | undefined { + if (value === undefined) return undefined; + if (value === null) return null; - if (!(value instanceof Map)) throw new InvalidTypeValueError(this, value, "value must be an instance of map"); + if (!(value instanceof Map)) + throw new InvalidTypeValueError( + this, + value, + "value must be an instance of map", + ); - return Object.fromEntries( - // Serializing the diff of each key-value pair of the map. - value.entries().map(([key, value]) => - ([this.keyDefinition.type.serializeDiff(key), this.valueDefinition.type.serializeDiff(value)])) - ) as SerializedMapType; - } + return Object.fromEntries( + // Serializing the diff of each key-value pair of the map. + value + .entries() + .map(([key, value]) => [ + this.keyDefinition.type.serializeDiff(key), + this.valueDefinition.type.serializeDiff(value), + ]), + ) as SerializedMapType; + } - resetDiff(value: Map|null|undefined): void - { - // Do nothing if it is not a map. - if (!(value instanceof Map)) return; + resetDiff(value: Map | null | undefined): void { + // Do nothing if it is not a map. + if (!(value instanceof Map)) return; - // Reset diff of all key-value pairs. - value.forEach((value, key) => { - this.keyDefinition.type.resetDiff(key); - this.valueDefinition.type.resetDiff(value); - }); - } + // Reset diff of all key-value pairs. + value.forEach((value, key) => { + this.keyDefinition.type.resetDiff(key); + this.valueDefinition.type.resetDiff(value); + }); + } - hasChanged(originalValue: Map|null|undefined, currentValue: Map|null|undefined): boolean - { - // If any map size is different, maps are different. - if (originalValue?.size != currentValue?.size) return true; - // If size is undefined, values are probably not maps. - if (originalValue?.size == undefined) return super.hasChanged(originalValue, currentValue); + hasChanged( + originalValue: Map | null | undefined, + currentValue: Map | null | undefined, + ): boolean { + // If any map size is different, maps are different. + if (originalValue?.size != currentValue?.size) return true; + // If size is undefined, values are probably not maps. + if (originalValue?.size == undefined) + return super.hasChanged(originalValue, currentValue); - for (const [key, value] of originalValue.entries()) - { // Check for any change for each key-value in the map. - if (this.valueDefinition.type.hasChanged(value, currentValue.get(key))) - // The value has changed, the map is different. - return true; - } + for (const [key, value] of originalValue.entries()) { + // Check for any change for each key-value in the map. + if (this.valueDefinition.type.hasChanged(value, currentValue.get(key))) + // The value has changed, the map is different. + return true; + } - return false; // No change detected. - } + return false; // No change detected. + } - serializedHasChanged(originalValue: SerializedMapType | null | undefined, currentValue: SerializedMapType | null | undefined): boolean - { - // If any value is not a defined object, use the default comparison function. - if (!originalValue || !currentValue || typeof originalValue !== "object" || typeof currentValue !== "object") return super.serializedHasChanged(originalValue, currentValue); + serializedHasChanged( + originalValue: SerializedMapType | null | undefined, + currentValue: SerializedMapType | null | undefined, + ): boolean { + // If any value is not a defined object, use the default comparison function. + if ( + !originalValue || + !currentValue || + typeof originalValue !== "object" || + typeof currentValue !== "object" + ) + return super.serializedHasChanged(originalValue, currentValue); - // If any object size is different, objects are different. - if (Object.keys(originalValue)?.length != Object.keys(currentValue)?.length) return true; + // If any object size is different, objects are different. + if (Object.keys(originalValue)?.length != Object.keys(currentValue)?.length) + return true; - for (const [key, value] of Object.entries(originalValue)) - { // Check for any change for each key-value pair in the object. - if (this.valueDefinition.type.serializedHasChanged(value, currentValue[key])) - // The value has changed, the object is different. - return true; - } + for (const [key, value] of Object.entries(originalValue)) { + // Check for any change for each key-value pair in the object. + if ( + this.valueDefinition.type.serializedHasChanged(value, currentValue[key]) + ) + // The value has changed, the object is different. + return true; + } - return false; // No change detected. - } + return false; // No change detected. + } - clone>(map: T|null|undefined): T - { - // Handle NULL / undefined map. - if (!map) return super.clone(map); + clone>(map: T | null | undefined): T { + // Handle NULL / undefined map. + if (!map) return super.clone(map); - if (!(map instanceof Map)) throw new InvalidTypeValueError(this, map, "value must be an instance of map"); + if (!(map instanceof Map)) + throw new InvalidTypeValueError( + this, + map, + "value must be an instance of map", + ); - // Initialize an empty map. - const cloned = new Map() as T; + // Initialize an empty map. + const cloned = new Map() as T; - for (const [key, value] of map.entries()) - { // Clone each value of the map. - cloned.set(this.keyDefinition.type.clone(key), this.valueDefinition.type.clone(value)); - } + for (const [key, value] of map.entries()) { + // Clone each value of the map. + cloned.set( + this.keyDefinition.type.clone(key), + this.valueDefinition.type.clone(value), + ); + } - return cloned; // Returning cloned map. - } + return cloned; // Returning cloned map. + } - applyPatch>(currentValue: T|null|undefined, patchValue: SerializedMapType|null|undefined, updateOriginals: boolean): T|null|undefined - { - if (patchValue === undefined) return undefined; - if (patchValue === null) return null; + applyPatch>( + currentValue: T | null | undefined, + patchValue: SerializedMapType | null | undefined, + updateOriginals: boolean, + ): T | null | undefined { + if (patchValue === undefined) return undefined; + if (patchValue === null) return null; - if (typeof patchValue !== "object") - throw new InvalidTypeValueError(this, patchValue, "value must be an object"); + if (typeof patchValue !== "object") + throw new InvalidTypeValueError( + this, + patchValue, + "value must be an object", + ); - currentValue = currentValue instanceof Map ? currentValue : new Map() as T; + currentValue = + currentValue instanceof Map + ? currentValue + : (new Map() as T); - for (const [key, value] of Object.entries(patchValue)) - { // Apply the patch to all values of the map. - const patchedKey = this.keyDefinition.type.deserialize(key); - const patchedElement = this.valueDefinition.type.applyPatch(currentValue.get(patchedKey), value, updateOriginals); - currentValue.set(patchedKey, patchedElement); - } + for (const [key, value] of Object.entries(patchValue)) { + // Apply the patch to all values of the map. + const patchedKey = this.keyDefinition.type.deserialize(key); + const patchedElement = this.valueDefinition.type.applyPatch( + currentValue.get(patchedKey), + value, + updateOriginals, + ); + currentValue.set(patchedKey, patchedElement); + } - return currentValue; - } + return currentValue; + } } /** @@ -157,21 +221,44 @@ export class MapType = Record>( - keyDefinition: Definition, - valueDefinition: Definition, -): Definition> -{ - return define(new MapType(keyDefinition, valueDefinition)); +export function map< + KeyType, + ValueType, + SerializedValueType, + SerializedMapType extends Record = Record< + string, + SerializedValueType + >, +>( + keyDefinition: Definition, + valueDefinition: Definition, +): Definition> { + return define( + new MapType( + keyDefinition, + valueDefinition, + ), + ); } /** * New map property definition, with string as index. * @param valueDefinition Definition of the map values. */ -export function stringMap = Record>( - valueDefinition: Definition, -): Definition> -{ - return define(new MapType(string(), valueDefinition)); +export function stringMap< + ValueType, + SerializedValueType, + SerializedMapType extends Record = Record< + string, + SerializedValueType + >, +>( + valueDefinition: Definition, +): Definition> { + return define( + new MapType( + string(), + valueDefinition, + ), + ); } diff --git a/src/model/types/model.ts b/src/model/types/model.ts index d6fe05d..6f4bfd7 100644 --- a/src/model/types/model.ts +++ b/src/model/types/model.ts @@ -2,50 +2,62 @@ import {Type} from "./type"; import {define, Definition} from "../property-definition"; import { GenericModelManager, - IdentifierDefinition, DeclaredModelManager, + IdentifierDefinition, + DeclaredModelManager, ModelInstance, ModelManager, ModelShape, - SerializedModel + SerializedModel, } from "../model"; import {InvalidTypeValueError} from "../../errors"; /** * Type of a Sharkitek model value. */ -export class ModelType, Identifier extends IdentifierDefinition> extends Type, ModelInstance> -{ +export class ModelType< + T extends object, + Shape extends ModelShape, + Identifier extends IdentifierDefinition, +> extends Type, ModelInstance> { /** * Initialize a new model type of a Sharkitek model property. * @param declaredModelManager Model manager. */ - constructor(protected declaredModelManager: DeclaredModelManager) - { + constructor( + protected declaredModelManager: DeclaredModelManager, + ) { super(); } /** * Resolve the defined model using the declared model, that can be defined lazily. */ - get definedModel(): ModelManager - { - return typeof this.declaredModelManager == "object" ? this.declaredModelManager : this.declaredModelManager(); + get definedModel(): ModelManager { + return typeof this.declaredModelManager == "object" + ? this.declaredModelManager + : this.declaredModelManager(); } - serialize(value: ModelInstance|null|undefined): SerializedModel|null|undefined - { + serialize( + value: ModelInstance | null | undefined, + ): SerializedModel | null | undefined { if (value === undefined) return undefined; if (value === null) return null; if (!(value instanceof this.definedModel.definition.Class)) - throw new InvalidTypeValueError(this, value, `value must be a compatible model (given ${value.constructor.name}, expected ${this.definedModel.definition.Class.name})`); + throw new InvalidTypeValueError( + this, + value, + `value must be a compatible model (given ${value.constructor.name}, expected ${this.definedModel.definition.Class.name})`, + ); // Serializing the given model. return this.definedModel.model(value).serialize(); } - deserialize(value: SerializedModel|null|undefined): ModelInstance|null|undefined - { + deserialize( + value: SerializedModel | null | undefined, + ): ModelInstance | null | undefined { if (value === undefined) return undefined; if (value === null) return null; @@ -56,86 +68,135 @@ export class ModelType, Identifier return this.definedModel.parse(value); } - serializeDiff(value: ModelInstance|null|undefined): Partial>|null|undefined - { + serializeDiff( + value: ModelInstance | null | undefined, + ): Partial> | null | undefined { if (value === undefined) return undefined; if (value === null) return null; if (!(value instanceof this.definedModel.definition.Class)) - throw new InvalidTypeValueError(this, value, `value must be a compatible model (given ${value.constructor.name}, expected ${this.definedModel.definition.Class.name})`); + throw new InvalidTypeValueError( + this, + value, + `value must be a compatible model (given ${value.constructor.name}, expected ${this.definedModel.definition.Class.name})`, + ); // Serializing the given model. return this.definedModel.model(value).serializeDiff(); } - resetDiff(value: ModelInstance|null|undefined): void - { + resetDiff( + value: ModelInstance | null | undefined, + ): void { if (value === undefined) return; if (value === null) return; if (!(value instanceof this.definedModel.definition.Class)) - throw new InvalidTypeValueError(this, value, `value must be a compatible model (given ${value.constructor.name}, expected ${this.definedModel.definition.Class.name})`); + throw new InvalidTypeValueError( + this, + value, + `value must be a compatible model (given ${value.constructor.name}, expected ${this.definedModel.definition.Class.name})`, + ); // Reset diff of the given model. this.definedModel.model(value).resetDiff(); } - hasChanged(originalValue: ModelInstance|null|undefined, currentValue: ModelInstance|null|undefined): boolean - { + hasChanged( + originalValue: ModelInstance | null | undefined, + currentValue: ModelInstance | null | undefined, + ): boolean { if (originalValue === undefined) return currentValue !== undefined; if (originalValue === null) return currentValue !== null; if (currentValue === undefined) return true; // Original value is not undefined. if (currentValue === null) return true; // Original value is not null. if (!(originalValue instanceof this.definedModel.definition.Class)) - throw new InvalidTypeValueError(this, originalValue, `value must be a compatible model (given ${originalValue.constructor.name}, expected ${this.definedModel.definition.Class.name})`); + throw new InvalidTypeValueError( + this, + originalValue, + `value must be a compatible model (given ${originalValue.constructor.name}, expected ${this.definedModel.definition.Class.name})`, + ); if (!(currentValue instanceof this.definedModel.definition.Class)) - throw new InvalidTypeValueError(this, currentValue, `value must be a compatible model (given ${currentValue.constructor.name}, expected ${this.definedModel.definition.Class.name})`); + throw new InvalidTypeValueError( + this, + currentValue, + `value must be a compatible model (given ${currentValue.constructor.name}, expected ${this.definedModel.definition.Class.name})`, + ); // If the current value is dirty, it has changed. return this.definedModel.model(currentValue).isDirty(); } - serializedHasChanged(originalValue: SerializedModel | null | undefined, currentValue: SerializedModel | null | undefined): boolean - { + serializedHasChanged( + originalValue: SerializedModel | null | undefined, + currentValue: SerializedModel | null | undefined, + ): boolean { if (originalValue === undefined) return currentValue !== undefined; if (originalValue === null) return currentValue !== null; if (currentValue === undefined) return true; // Original value is not undefined. if (currentValue === null) return true; // Original value is not null. if (typeof originalValue !== "object" || Array.isArray(originalValue)) - throw new InvalidTypeValueError(this, originalValue, "value must be an object"); + throw new InvalidTypeValueError( + this, + originalValue, + "value must be an object", + ); if (typeof currentValue !== "object" || Array.isArray(currentValue)) - throw new InvalidTypeValueError(this, currentValue, "value must be an object"); + throw new InvalidTypeValueError( + this, + currentValue, + "value must be an object", + ); // If any property has changed, the value has changed. for (const property of this.definedModel.properties) - if (property.definition.type.serializedHasChanged(originalValue?.[property.name], currentValue?.[property.name])) + if ( + property.definition.type.serializedHasChanged( + originalValue?.[property.name], + currentValue?.[property.name], + ) + ) return true; return false; // No change detected. } - clone>(value: Type|null|undefined): Type - { + clone>( + value: Type | null | undefined, + ): Type { // Handle NULL / undefined values. if (!value) return super.clone(value); if (!(value instanceof this.definedModel.definition.Class)) - throw new InvalidTypeValueError(this, value, `value must be a compatible model (given ${value.constructor.name}, expected ${this.definedModel.definition.Class.name})`); + throw new InvalidTypeValueError( + this, + value, + `value must be a compatible model (given ${value.constructor.name}, expected ${this.definedModel.definition.Class.name})`, + ); return this.definedModel.model(value).clone() as Type; } - applyPatch>(currentValue: Type|null|undefined, patchValue: SerializedModel|null|undefined, updateOriginals: boolean): Type|null|undefined - { + applyPatch>( + currentValue: Type | null | undefined, + patchValue: SerializedModel | null | undefined, + updateOriginals: boolean, + ): Type | null | undefined { if (patchValue === undefined) return undefined; if (patchValue === null) return null; if (typeof patchValue !== "object" || Array.isArray(patchValue)) - throw new InvalidTypeValueError(this, patchValue, "value must be an object"); + throw new InvalidTypeValueError( + this, + patchValue, + "value must be an object", + ); - return this.definedModel.model(currentValue).applyPatch(patchValue, updateOriginals) as Type; + return this.definedModel + .model(currentValue) + .applyPatch(patchValue, updateOriginals) as Type; } } @@ -143,14 +204,18 @@ export class ModelType, Identifier * New model property definition. * @param definedModel Model manager. */ -export function model, Identifier extends IdentifierDefinition>( - definedModel: DeclaredModelManager -): Definition, ModelInstance> -{ +export function model< + T extends object, + Shape extends ModelShape, + Identifier extends IdentifierDefinition, +>( + definedModel: DeclaredModelManager, +): Definition, ModelInstance> { return define(new ModelType(definedModel)); } -export function circular(definedModel: () => any): () => GenericModelManager -{ +export function circular( + definedModel: () => any, +): () => GenericModelManager { return definedModel; } diff --git a/src/model/types/numeric.ts b/src/model/types/numeric.ts index b548657..b58ee5d 100644 --- a/src/model/types/numeric.ts +++ b/src/model/types/numeric.ts @@ -5,24 +5,23 @@ import {InvalidTypeValueError} from "../../errors"; /** * Type of any numeric value. */ -export class NumericType extends Type -{ - deserialize(value: number|null|undefined): number|null|undefined - { +export class NumericType extends Type { + deserialize(value: number | null | undefined): number | null | undefined { if (value === undefined) return undefined; if (value === null) return null; - if (typeof value !== "number") throw new InvalidTypeValueError(this, value, "value must be a number"); + if (typeof value !== "number") + throw new InvalidTypeValueError(this, value, "value must be a number"); return value; } - serialize(value: number|null|undefined): number|null|undefined - { + serialize(value: number | null | undefined): number | null | undefined { if (value === undefined) return undefined; if (value === null) return null; - if (typeof value !== "number") throw new InvalidTypeValueError(this, value, "value must be a number"); + if (typeof value !== "number") + throw new InvalidTypeValueError(this, value, "value must be a number"); return value; } @@ -31,7 +30,6 @@ export class NumericType extends Type /** * New numeric property definition. */ -export function numeric(): Definition -{ +export function numeric(): Definition { return define(new NumericType()); } diff --git a/src/model/types/object.ts b/src/model/types/object.ts index e171796..0c43f7c 100644 --- a/src/model/types/object.ts +++ b/src/model/types/object.ts @@ -1,13 +1,21 @@ import {Type} from "./type"; import {define, Definition, UnknownDefinition} from "../property-definition"; -import {ModelProperties, ModelPropertiesValues, ModelProperty, ModelShape, SerializedModel} from "../model"; +import { + ModelProperties, + ModelPropertiesValues, + ModelProperty, + ModelShape, + SerializedModel, +} from "../model"; import {InvalidTypeValueError} from "../../errors"; /** * Type of a custom object. */ -export class ObjectType, T extends object> extends Type, ModelPropertiesValues> -{ +export class ObjectType< + Shape extends ModelShape, + T extends object, +> extends Type, ModelPropertiesValues> { /** * Defined properties. */ @@ -17,8 +25,7 @@ export class ObjectType, T extends object> extends T * Initialize a new object type of a Sharkitek model property. * @param shape */ - constructor(readonly shape: Shape) - { + constructor(readonly shape: Shape) { super(); this.initProperties(); } @@ -27,12 +34,11 @@ export class ObjectType, T extends object> extends T * Initialize properties iterator from the object shape. * @protected */ - protected initProperties(): void - { + protected initProperties(): void { // Build an array of model properties from the object shape. this.properties = []; - for (const propertyName in this.shape) - { // For each property, build a model property object. + for (const propertyName in this.shape) { + // For each property, build a model property object. this.properties.push({ name: propertyName, definition: this.shape[propertyName], @@ -41,8 +47,9 @@ export class ObjectType, T extends object> extends T } } - deserialize(value: SerializedModel|null|undefined): ModelPropertiesValues|null|undefined - { + deserialize( + value: SerializedModel | null | undefined, + ): ModelPropertiesValues | null | undefined { if (value === undefined) return undefined; if (value === null) return null; @@ -52,16 +59,18 @@ export class ObjectType, T extends object> extends T // Initialize an empty object. const obj: Partial> = {}; - for (const property of this.properties) - { // For each defined property, deserialize its value according to its type. - (obj[property.name as keyof T] as any) = property.definition.type.deserialize(value?.[property.name]); + for (const property of this.properties) { + // For each defined property, deserialize its value according to its type. + (obj[property.name as keyof T] as any) = + property.definition.type.deserialize(value?.[property.name]); } return obj as ModelPropertiesValues; // Returning serialized object. } - serialize(value: ModelPropertiesValues|null|undefined): SerializedModel|null|undefined - { + serialize( + value: ModelPropertiesValues | null | undefined, + ): SerializedModel | null | undefined { if (value === undefined) return undefined; if (value === null) return null; @@ -71,8 +80,8 @@ export class ObjectType, T extends object> extends T // Creating an empty serialized object. const serializedObject: Partial> = {}; - for (const property of this.properties) - { // For each property, adding it to the serialized object. + for (const property of this.properties) { + // For each property, adding it to the serialized object. serializedObject[property.name] = property.definition.type.serialize( // keyof Shape is a subset of keyof T. value?.[property.name as keyof T], @@ -82,8 +91,9 @@ export class ObjectType, T extends object> extends T return serializedObject as SerializedModel; // Returning the serialized object. } - serializeDiff(value: ModelPropertiesValues|null|undefined): Partial>|null|undefined - { + serializeDiff( + value: ModelPropertiesValues | null | undefined, + ): Partial> | null | undefined { if (value === undefined) return undefined; if (value === null) return null; @@ -93,8 +103,8 @@ export class ObjectType, T extends object> extends T // Creating an empty serialized object. const serializedObject: Partial> = {}; - for (const property of this.properties) - { // For each property, adding it to the serialized object. + for (const property of this.properties) { + // For each property, adding it to the serialized object. serializedObject[property.name] = property.definition.type.serializeDiff( // keyof Shape is a subset of keyof T. value?.[property.name as keyof T], @@ -104,8 +114,7 @@ export class ObjectType, T extends object> extends T return serializedObject as SerializedModel; // Returning the serialized object. } - resetDiff(value: ModelPropertiesValues|null|undefined) - { + resetDiff(value: ModelPropertiesValues | null | undefined) { if (value === undefined) return; if (value === null) return; @@ -113,53 +122,84 @@ export class ObjectType, T extends object> extends T throw new InvalidTypeValueError(this, value, "value must be an object"); // For each property, reset its diff. + // keyof Shape is a subset of keyof T. for (const property of this.properties) - // keyof Shape is a subset of keyof T. property.definition.type.resetDiff(value?.[property.name as keyof T]); } - hasChanged(originalValue: ModelPropertiesValues|null|undefined, currentValue: ModelPropertiesValues|null|undefined): boolean - { + hasChanged( + originalValue: ModelPropertiesValues | null | undefined, + currentValue: ModelPropertiesValues | null | undefined, + ): boolean { if (originalValue === undefined) return currentValue !== undefined; if (originalValue === null) return currentValue !== null; if (currentValue === undefined) return true; // Original value is not undefined. if (currentValue === null) return true; // Original value is not null. if (typeof originalValue !== "object" || Array.isArray(originalValue)) - throw new InvalidTypeValueError(this, originalValue, "value must be an object"); + throw new InvalidTypeValueError( + this, + originalValue, + "value must be an object", + ); if (typeof currentValue !== "object" || Array.isArray(currentValue)) - throw new InvalidTypeValueError(this, currentValue, "value must be an object"); + throw new InvalidTypeValueError( + this, + currentValue, + "value must be an object", + ); // If any property has changed, the value has changed. for (const property of this.properties) - if (property.definition.type.hasChanged(originalValue?.[property.name as keyof T], currentValue?.[property.name as keyof T])) + if ( + property.definition.type.hasChanged( + originalValue?.[property.name as keyof T], + currentValue?.[property.name as keyof T], + ) + ) return true; return false; // No change detected. } - serializedHasChanged(originalValue: SerializedModel|null|undefined, currentValue: SerializedModel|null|undefined): boolean - { + serializedHasChanged( + originalValue: SerializedModel | null | undefined, + currentValue: SerializedModel | null | undefined, + ): boolean { if (originalValue === undefined) return currentValue !== undefined; if (originalValue === null) return currentValue !== null; if (currentValue === undefined) return true; // Original value is not undefined. if (currentValue === null) return true; // Original value is not null. if (typeof originalValue !== "object" || Array.isArray(originalValue)) - throw new InvalidTypeValueError(this, originalValue, "value must be an object"); + throw new InvalidTypeValueError( + this, + originalValue, + "value must be an object", + ); if (typeof currentValue !== "object" || Array.isArray(currentValue)) - throw new InvalidTypeValueError(this, currentValue, "value must be an object"); + throw new InvalidTypeValueError( + this, + currentValue, + "value must be an object", + ); // If any property has changed, the value has changed. for (const property of this.properties) - if (property.definition.type.serializedHasChanged(originalValue?.[property.name], currentValue?.[property.name])) + if ( + property.definition.type.serializedHasChanged( + originalValue?.[property.name], + currentValue?.[property.name], + ) + ) return true; return false; // No change detected. } - clone>(value: Type|null|undefined): Type - { + clone>( + value: Type | null | undefined, + ): Type { // Handle NULL / undefined object. if (!value) return super.clone(value); @@ -169,29 +209,47 @@ export class ObjectType, T extends object> extends T // Initialize an empty object. const cloned: Partial> = {}; - for (const property of this.properties) - { // For each defined property, clone it. - cloned[property.name as keyof T] = property.definition.type.clone(value?.[property.name]); + for (const property of this.properties) { + // For each defined property, clone it. + cloned[property.name as keyof T] = property.definition.type.clone( + value?.[property.name], + ); } return cloned as Type; // Returning cloned object. } - applyPatch>(currentValue: Type|null|undefined, patchValue: SerializedModel|null|undefined, updateOriginals: boolean): Type|null|undefined - { + applyPatch>( + currentValue: Type | null | undefined, + patchValue: SerializedModel | null | undefined, + updateOriginals: boolean, + ): Type | null | undefined { if (patchValue === undefined) return undefined; if (patchValue === null) return null; if (typeof patchValue !== "object" || Array.isArray(patchValue)) - throw new InvalidTypeValueError(this, patchValue, "value must be an object"); + throw new InvalidTypeValueError( + this, + patchValue, + "value must be an object", + ); - const patchedValue: Partial = typeof currentValue === "object" && currentValue !== null ? currentValue : {}; + const patchedValue: Partial = + typeof currentValue === "object" && currentValue !== null + ? currentValue + : {}; - for (const key in patchValue) - { // Apply the patch to each property of the patch value. + for (const key in patchValue) { + // Apply the patch to each property of the patch value. const propertyDef = this.shape[key]; if (propertyDef) - patchedValue[key as keyof Type] = (propertyDef as UnknownDefinition).type.applyPatch(currentValue?.[key as keyof Type], patchValue[key], updateOriginals); + patchedValue[key as keyof Type] = ( + propertyDef as UnknownDefinition + ).type.applyPatch( + currentValue?.[key as keyof Type], + patchValue[key], + updateOriginals, + ); } return patchedValue as Type; @@ -202,7 +260,8 @@ export class ObjectType, T extends object> extends T * New object property definition. * @param shape Shape of the object. */ -export function object, T extends object>(shape: Shape): Definition, ModelPropertiesValues> -{ +export function object, T extends object>( + shape: Shape, +): Definition, ModelPropertiesValues> { return define(new ObjectType(shape)); } diff --git a/src/model/types/string.ts b/src/model/types/string.ts index 5fa3435..7a850ff 100644 --- a/src/model/types/string.ts +++ b/src/model/types/string.ts @@ -4,18 +4,15 @@ import {define, Definition} from "../property-definition"; /** * Type of any string value. */ -export class StringType extends Type -{ - deserialize(value: string|null|undefined): string|null|undefined - { +export class StringType extends Type { + deserialize(value: string | null | undefined): string | null | undefined { if (value === undefined) return undefined; if (value === null) return null; return String(value); } - serialize(value: string|null|undefined): string|null|undefined - { + serialize(value: string | null | undefined): string | null | undefined { if (value === undefined) return undefined; if (value === null) return null; @@ -26,7 +23,6 @@ export class StringType extends Type /** * New string property definition. */ -export function string(): Definition -{ +export function string(): Definition { return define(new StringType()); } diff --git a/src/model/types/type.ts b/src/model/types/type.ts index a477daa..05ec6db 100644 --- a/src/model/types/type.ts +++ b/src/model/types/type.ts @@ -1,26 +1,30 @@ /** * Abstract class of a Sharkitek model property type. */ -export abstract class Type -{ +export abstract class Type { /** * Serialize the given value of a Sharkitek model property. * @param value Value to serialize. */ - abstract serialize(value: ModelType|null|undefined): SerializedType|null|undefined; + abstract serialize( + value: ModelType | null | undefined, + ): SerializedType | null | undefined; /** * Deserialize the given value of a serialized Sharkitek model. * @param value Value to deserialize. */ - abstract deserialize(value: SerializedType|null|undefined): ModelType|null|undefined; + abstract deserialize( + value: SerializedType | null | undefined, + ): ModelType | null | undefined; /** * Serialize the given value only if it has changed. * @param value Value to deserialize. */ - serializeDiff(value: ModelType|null|undefined): Partial|null|undefined - { + serializeDiff( + value: ModelType | null | undefined, + ): Partial | null | undefined { return this.serialize(value); // By default, nothing changes. } @@ -28,8 +32,7 @@ export abstract class Type * Reset the difference between the original value and the current one. * @param value Value for which reset diff data. */ - resetDiff(value: ModelType|null|undefined): void - { + resetDiff(value: ModelType | null | undefined): void { // By default, nothing to do. } @@ -38,8 +41,10 @@ export abstract class Type * @param originalValue Original value. * @param currentValue Current value. */ - hasChanged(originalValue: ModelType|null|undefined, currentValue: ModelType|null|undefined): boolean - { + hasChanged( + originalValue: ModelType | null | undefined, + currentValue: ModelType | null | undefined, + ): boolean { return originalValue !== currentValue; } @@ -48,8 +53,10 @@ export abstract class Type * @param originalValue Original serialized value. * @param currentValue Current serialized value. */ - serializedHasChanged(originalValue: SerializedType|null|undefined, currentValue: SerializedType|null|undefined): boolean - { + serializedHasChanged( + originalValue: SerializedType | null | undefined, + currentValue: SerializedType | null | undefined, + ): boolean { return originalValue !== currentValue; } @@ -57,8 +64,7 @@ export abstract class Type * Clone the provided value. * @param value The to clone. */ - clone(value: T|null|undefined): T - { + clone(value: T | null | undefined): T { return structuredClone(value); } @@ -68,8 +74,11 @@ export abstract class Type * @param patchValue The serialized patch value. * @param updateOriginals Indicates if the original properties values must be updated or not. */ - applyPatch(currentValue: T|null|undefined, patchValue: SerializedType|null|undefined, updateOriginals: boolean): T|null|undefined - { + applyPatch( + currentValue: T | null | undefined, + patchValue: SerializedType | null | undefined, + updateOriginals: boolean, + ): T | null | undefined { return this.deserialize(patchValue) as T; } } diff --git a/src/utils.ts b/src/utils.ts index 6120e99..b595c0e 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,9 +1,10 @@ /** * Type definition of a class constructor. */ -export type ConstructorOf = { new(): T; }; +export type ConstructorOf = {new (): T}; /** * Type definition of an original object overridden by another. */ -export type Modify = Omit & Override; +export type Modify = Omit & + Override; diff --git a/tests/errors.test.ts b/tests/errors.test.ts index a7f0166..a396503 100644 --- a/tests/errors.test.ts +++ b/tests/errors.test.ts @@ -4,12 +4,21 @@ import {s} from "../src/library"; describe("errors", () => { it("tests type error", () => { - expect((new TypeError(s.property.string().type)).message).toBe("Error in type StringType"); - expect((new TypeError(s.property.string().type, "test")).message).toBe("Error in type StringType: test"); + expect(new TypeError(s.property.string().type).message).toBe( + "Error in type StringType", + ); + expect(new TypeError(s.property.string().type, "test").message).toBe( + "Error in type StringType: test", + ); }); it("tests invalid type value error", () => { - expect((new InvalidTypeValueError(s.property.decimal().type, ["value"])).message).toBe("Error in type DecimalType: [\"value\"] is an invalid value"); - expect((new InvalidTypeValueError(s.property.decimal().type, ["value"], "test")).message).toBe("Error in type DecimalType: test"); + expect( + new InvalidTypeValueError(s.property.decimal().type, ["value"]).message, + ).toBe('Error in type DecimalType: ["value"] is an invalid value'); + expect( + new InvalidTypeValueError(s.property.decimal().type, ["value"], "test") + .message, + ).toBe("Error in type DecimalType: test"); }); }); diff --git a/tests/model.test.ts b/tests/model.test.ts index 730fc38..73eadcb 100644 --- a/tests/model.test.ts +++ b/tests/model.test.ts @@ -4,8 +4,7 @@ import {circular, defineModel, s} from "../src/library"; /** * Test class of an account. */ -class Account -{ +class Account { static model = s.defineModel({ Class: Account, identifier: "id", @@ -28,8 +27,7 @@ class Account /** * Test class of an article. */ -class Article -{ +class Article { static model = s.defineModel({ Class: Article, identifier: "id", @@ -39,7 +37,7 @@ class Article authors: s.property.array(s.property.model(() => Account.model)), text: s.property.string(), evaluation: s.property.decimal(), - tags: s.property.array(s.property.object({ name: s.property.string() })), + tags: s.property.array(s.property.object({name: s.property.string()})), comments: s.property.array(s.property.model(() => ArticleComment.model)), }, }); @@ -49,15 +47,14 @@ class Article authors: Account[]; text: string; evaluation: number; - tags: { name: string }[]; + tags: {name: string}[]; comments: ArticleComment[]; } /** * Test class of a comment on an article. */ -class ArticleComment -{ +class ArticleComment { static model = s.defineModel({ Class: ArticleComment, identifier: "id", @@ -78,8 +75,7 @@ class ArticleComment /** * Get a test account instance. */ -function getTestAccount(): Account -{ +function getTestAccount(): Account { const account = new Account(); account.id = 52; account.createdAt = new Date(); @@ -89,17 +85,13 @@ function getTestAccount(): Account return account; } -function getTestArticle(): Article -{ +function getTestArticle(): Article { const article = new Article(); article.id = 1; article.title = "this is a test"; article.text = "this is a long test."; article.evaluation = 25.23; - article.tags = [ - { name: "test" }, - { name: "foo" }, - ]; + article.tags = [{name: "test"}, {name: "foo"}]; article.authors = [getTestAccount()]; article.comments = []; return article; @@ -107,8 +99,7 @@ function getTestArticle(): Article describe("model", () => { it("defines a new model, extending an existing one", () => { - class ExtendedAccount extends Account - { + class ExtendedAccount extends Account { static extendedModel = s.extend(Account.model, { Class: ExtendedAccount, properties: { @@ -147,8 +138,7 @@ describe("model", () => { expect(Article.model.model(article).getIdentifier()).toBe(1); }); it("gets a model composite identifier value", () => { - class CompositeModel - { + class CompositeModel { static model = s.defineModel({ Class: CompositeModel, properties: { @@ -157,7 +147,7 @@ describe("model", () => { label: s.property.string(), }, identifier: ["firstId", "secondId"], - }) + }); firstId: number; secondId: number; @@ -165,11 +155,15 @@ describe("model", () => { } expect( - CompositeModel.model.model(Object.assign(new CompositeModel(), { - firstId: 5, - secondId: 6, - label: "test", - })).getIdentifier() + CompositeModel.model + .model( + Object.assign(new CompositeModel(), { + firstId: 5, + secondId: 6, + label: "test", + }), + ) + .getIdentifier(), ).toStrictEqual([5, 6]); }); it("checks model dirtiness when altered, then reset diff", () => { @@ -177,7 +171,7 @@ describe("model", () => { expect(Article.model.model(article).isDirty()).toBeFalsy(); article.title = "new title"; expect(Article.model.model(article).isDirty()).toBeTruthy(); - Article.model.model(article).resetDiff() + Article.model.model(article).resetDiff(); expect(Article.model.model(article).isDirty()).toBeFalsy(); }); @@ -186,14 +180,36 @@ describe("model", () => { id: 1, title: "this is a test", authors: [ - Object.assign(new Account(), { id: 52, name: "John Doe", email: "test@test.test", createdAt: new Date("2022-08-07T08:47:01.000Z"), active: true, }), - Object.assign(new Account(), { id: 4, name: "Tester", email: "another@test.test", createdAt: new Date("2022-09-07T18:32:55.000Z"), active: false, }), + Object.assign(new Account(), { + id: 52, + name: "John Doe", + email: "test@test.test", + createdAt: new Date("2022-08-07T08:47:01.000Z"), + active: true, + }), + Object.assign(new Account(), { + id: 4, + name: "Tester", + email: "another@test.test", + createdAt: new Date("2022-09-07T18:32:55.000Z"), + active: false, + }), ], text: "this is a long test.", evaluation: 8.52, - tags: [ {name: "test"}, {name: "foo"} ], + tags: [{name: "test"}, {name: "foo"}], comments: [ - Object.assign(new ArticleComment(), { id: 542, author: Object.assign(new Account(), { id: 52, name: "John Doe", email: "test@test.test", createdAt: new Date("2022-08-07T08:47:01.000Z"), active: true, }), message: "comment content", }), + Object.assign(new ArticleComment(), { + id: 542, + author: Object.assign(new Account(), { + id: 52, + name: "John Doe", + email: "test@test.test", + createdAt: new Date("2022-08-07T08:47:01.000Z"), + active: true, + }), + message: "comment content", + }), ], }); @@ -201,23 +217,49 @@ describe("model", () => { id: 1, title: "this is a test", authors: [ - { id: 52, name: "John Doe", email: "test@test.test", createdAt: "2022-08-07T08:47:01.000Z", active: true, }, - { id: 4, name: "Tester", email: "another@test.test", createdAt: "2022-09-07T18:32:55.000Z", active: false, }, + { + id: 52, + name: "John Doe", + email: "test@test.test", + createdAt: "2022-08-07T08:47:01.000Z", + active: true, + }, + { + id: 4, + name: "Tester", + email: "another@test.test", + createdAt: "2022-09-07T18:32:55.000Z", + active: false, + }, ], text: "this is a long test.", evaluation: "8.52", - tags: [ {name: "test"}, {name: "foo"} ], + tags: [{name: "test"}, {name: "foo"}], comments: [ - { id: 542, author: { id: 52, name: "John Doe", email: "test@test.test", createdAt: "2022-08-07T08:47:01.000Z", active: true, }, message: "comment content", }, + { + id: 542, + author: { + id: 52, + name: "John Doe", + email: "test@test.test", + createdAt: "2022-08-07T08:47:01.000Z", + active: true, + }, + message: "comment content", + }, ], }); - const deserializedArticleProperties = Article.model.model(deserializedArticle).getInstanceProperties(); + const deserializedArticleProperties = Article.model + .model(deserializedArticle) + .getInstanceProperties(); delete deserializedArticleProperties.authors[0]._sharkitek; delete deserializedArticleProperties.authors[1]._sharkitek; delete deserializedArticleProperties.comments[0]._sharkitek; delete (deserializedArticleProperties.comments[0].author as any)._sharkitek; - const expectedArticleProperties = Article.model.model(expectedArticle).getInstanceProperties(); + const expectedArticleProperties = Article.model + .model(expectedArticle) + .getInstanceProperties(); delete expectedArticleProperties.authors[0]._sharkitek; delete expectedArticleProperties.authors[1]._sharkitek; delete expectedArticleProperties.comments[0]._sharkitek; @@ -232,9 +274,15 @@ describe("model", () => { title: "this is a test", text: "this is a long test.", evaluation: "25.23", - tags: [{ name: "test" }, { name: "foo" }], + tags: [{name: "test"}, {name: "foo"}], authors: [ - { id: 52, createdAt: article.authors[0].createdAt.toISOString(), name: "John Doe", email: "john@doe.test", active: true } + { + id: 52, + createdAt: article.authors[0].createdAt.toISOString(), + name: "John Doe", + email: "john@doe.test", + active: true, + }, ], comments: [], }); @@ -245,14 +293,36 @@ describe("model", () => { id: 1, title: "this is a test", authors: [ - { id: 52, name: "John Doe", email: "test@test.test", createdAt: "2022-08-07T08:47:01.000Z", active: true, }, - { id: 4, name: "Tester", email: "another@test.test", createdAt: "2022-09-07T18:32:55.000Z", active: false, }, + { + id: 52, + name: "John Doe", + email: "test@test.test", + createdAt: "2022-08-07T08:47:01.000Z", + active: true, + }, + { + id: 4, + name: "Tester", + email: "another@test.test", + createdAt: "2022-09-07T18:32:55.000Z", + active: false, + }, ], text: "this is a long test.", evaluation: "8.52", - tags: [ {name: "test"}, {name: "foo"} ], + tags: [{name: "test"}, {name: "foo"}], comments: [ - { id: 542, author: { id: 52, name: "John Doe", email: "test@test.test", createdAt: "2022-08-07T08:47:01.000Z", active: true, }, message: "comment content", }, + { + id: 542, + author: { + id: 52, + name: "John Doe", + email: "test@test.test", + createdAt: "2022-08-07T08:47:01.000Z", + active: true, + }, + message: "comment content", + }, ], }); @@ -276,14 +346,36 @@ describe("model", () => { id: 1, title: "this is a test", authors: [ - { id: 52, name: "John Doe", email: "test@test.test", createdAt: "2022-08-07T08:47:01.000Z", active: true, }, - { id: 4, name: "Tester", email: "another@test.test", createdAt: "2022-09-07T18:32:55.000Z", active: false, }, + { + id: 52, + name: "John Doe", + email: "test@test.test", + createdAt: "2022-08-07T08:47:01.000Z", + active: true, + }, + { + id: 4, + name: "Tester", + email: "another@test.test", + createdAt: "2022-09-07T18:32:55.000Z", + active: false, + }, ], text: "this is a long test.", evaluation: "8.52", - tags: [ {name: "test"}, {name: "foo"} ], + tags: [{name: "test"}, {name: "foo"}], comments: [ - { id: 542, author: { id: 52, name: "John Doe", email: "test@test.test", createdAt: "2022-08-07T08:47:01.000Z", active: true, }, message: "comment content", }, + { + id: 542, + author: { + id: 52, + name: "John Doe", + email: "test@test.test", + createdAt: "2022-08-07T08:47:01.000Z", + active: true, + }, + message: "comment content", + }, ], }); @@ -291,10 +383,7 @@ describe("model", () => { expect(Article.model.model(deserializedArticle).patch()).toStrictEqual({ id: 1, - authors: [ - { id: 52, }, - { id: 4, active: true }, - ], + authors: [{id: 52}, {id: 4, active: true}], }); deserializedArticle.comments[0].author.name = "Johnny"; @@ -314,8 +403,7 @@ describe("model", () => { }); it("deserializes and patches with fields that are not properties", () => { - class TestModel - { + class TestModel { static model = defineModel({ Class: TestModel, properties: { @@ -323,12 +411,12 @@ describe("model", () => { label: s.property.string(), }, identifier: "id", - }) + }); id: number; label: string; - notAProperty: { hello: string } = { hello: "world" }; + notAProperty: {hello: string} = {hello: "world"}; } const deserializedModel = TestModel.model.parse({ @@ -339,17 +427,29 @@ describe("model", () => { expect(deserializedModel.label).toBe("testing"); expect(deserializedModel.notAProperty?.hello).toBe("world"); - const clonedDeserializedModel = TestModel.model.model(deserializedModel).clone(); + const clonedDeserializedModel = TestModel.model + .model(deserializedModel) + .clone(); deserializedModel.label = "new!"; - expect(TestModel.model.model(deserializedModel).patch()).toStrictEqual({ id: 5, label: "new!" }); + expect(TestModel.model.model(deserializedModel).patch()).toStrictEqual({ + id: 5, + label: "new!", + }); deserializedModel.notAProperty.hello = "monster"; - expect(TestModel.model.model(deserializedModel).patch()).toStrictEqual({ id: 5 }); + expect(TestModel.model.model(deserializedModel).patch()).toStrictEqual({ + id: 5, + }); - expect(TestModel.model.model(deserializedModel).serialize()).toStrictEqual({ id: 5, label: "new!" }); + expect(TestModel.model.model(deserializedModel).serialize()).toStrictEqual({ + id: 5, + label: "new!", + }); - expect(TestModel.model.model(clonedDeserializedModel).serialize()).toStrictEqual({ id: 5, label: "testing" }); + expect( + TestModel.model.model(clonedDeserializedModel).serialize(), + ).toStrictEqual({id: 5, label: "testing"}); expect(clonedDeserializedModel.notAProperty.hello).toEqual("world"); }); @@ -358,14 +458,36 @@ describe("model", () => { id: 1, title: "this is a test", authors: [ - { id: 52, name: "John Doe", email: "test@test.test", createdAt: "2022-08-07T08:47:01.000Z", active: true, }, - { id: 4, name: "Tester", email: "another@test.test", createdAt: "2022-09-07T18:32:55.000Z", active: false, }, + { + id: 52, + name: "John Doe", + email: "test@test.test", + createdAt: "2022-08-07T08:47:01.000Z", + active: true, + }, + { + id: 4, + name: "Tester", + email: "another@test.test", + createdAt: "2022-09-07T18:32:55.000Z", + active: false, + }, ], text: "this is a long test.", evaluation: "8.52", - tags: [ {name: "test"}, {name: "foo"} ], + tags: [{name: "test"}, {name: "foo"}], comments: [ - { id: 542, author: { id: 52, name: "John Doe", email: "test@test.test", createdAt: "2022-08-07T08:47:01.000Z", active: true, }, message: "comment content", }, + { + id: 542, + author: { + id: 52, + name: "John Doe", + email: "test@test.test", + createdAt: "2022-08-07T08:47:01.000Z", + active: true, + }, + message: "comment content", + }, ], }); @@ -387,11 +509,16 @@ describe("model", () => { const testArticle = Article.model.from({ title: "this is a test", authors: [ - Account.model.from({ name: "John Doe", email: "test@test.test", createdAt: new Date(), active: true }), + Account.model.from({ + name: "John Doe", + email: "test@test.test", + createdAt: new Date(), + active: true, + }), ], text: "this is a long text", evaluation: 8.52, - tags: [{ name: "test" }, { name: "foo" }], + tags: [{name: "test"}, {name: "foo"}], unknownField: true, anotherOne: "test", @@ -411,11 +538,17 @@ describe("model", () => { id: 1, title: "this is a test", authors: [ - Account.model.from({ id: 55, name: "John Doe", email: "test@test.test", createdAt: new Date(), active: true }), + Account.model.from({ + id: 55, + name: "John Doe", + email: "test@test.test", + createdAt: new Date(), + active: true, + }), ], text: "this is a long text", evaluation: 8.52, - tags: [{ name: "test" }, { name: "foo" }], + tags: [{name: "test"}, {name: "foo"}], unknownField: true, anotherOne: "test", @@ -427,23 +560,30 @@ describe("model", () => { title: "new title", }); expect(testArticle.title).toBe("new title"); - expect(Article.model.model(testArticle).serializeDiff()).toStrictEqual({ id: 1 }); + expect(Article.model.model(testArticle).serializeDiff()).toStrictEqual({ + id: 1, + }); // Test originals update propagation. Article.model.model(testArticle).applyPatch({ - authors: [ { email: "john@test.test" } ] + authors: [{email: "john@test.test"}], }); expect(testArticle.authors[0].email).toBe("john@test.test"); - expect(Article.model.model(testArticle).serializeDiff()).toStrictEqual({ id: 1 }); + expect(Article.model.model(testArticle).serializeDiff()).toStrictEqual({ + id: 1, + }); // Test without originals update. - Article.model.model(testArticle).applyPatch({ - authors: [ { name: "Johnny" } ] - }, false); + Article.model.model(testArticle).applyPatch( + { + authors: [{name: "Johnny"}], + }, + false, + ); expect(testArticle.authors[0].name).toBe("Johnny"); expect(Article.model.model(testArticle).serializeDiff()).toStrictEqual({ id: 1, - authors: [ { id: 55, name: "Johnny" } ] + authors: [{id: 55, name: "Johnny"}], }); }); }); diff --git a/tests/model/types/array.test.ts b/tests/model/types/array.test.ts index 75cedd4..4acfc9d 100644 --- a/tests/model/types/array.test.ts +++ b/tests/model/types/array.test.ts @@ -1,8 +1,7 @@ import {describe, expect, test} from "vitest"; import {ArrayType, InvalidTypeValueError, s} from "../../../src/library"; -class TestModel -{ +class TestModel { id: number; name: string; price: number; @@ -27,19 +26,35 @@ describe("array type", () => { const testProperty = s.property.array(s.property.decimal()); test("array type functions", () => { - expect(testProperty.type.serialize([12.547, 8, -52.11])).toEqual(["12.547", "8", "-52.11"]); - expect(testProperty.type.deserialize(["12.547", "8", "-52.11"])).toEqual([12.547, 8, -52.11]); + expect(testProperty.type.serialize([12.547, 8, -52.11])).toEqual([ + "12.547", + "8", + "-52.11", + ]); + expect(testProperty.type.deserialize(["12.547", "8", "-52.11"])).toEqual([ + 12.547, 8, -52.11, + ]); - { // Try to serialize the difference of an array with one changed model. + { + // Try to serialize the difference of an array with one changed model. const propertyValue = [ - testModel.model(Object.assign(new TestModel(), { id: 1, name: "test", price: 22 })).instance, - testModel.model(Object.assign(new TestModel(), { id: 2, name: "another", price: 12.55 })).instance, + testModel.model( + Object.assign(new TestModel(), {id: 1, name: "test", price: 22}), + ).instance, + testModel.model( + Object.assign(new TestModel(), { + id: 2, + name: "another", + price: 12.55, + }), + ).instance, ]; propertyValue[0].name = "new"; - expect(s.property.array(s.property.model(testModel)).type.serializeDiff(propertyValue)).toEqual([ - { id: 1, name: "new" }, - { id: 2 }, - ]); + expect( + s.property + .array(s.property.model(testModel)) + .type.serializeDiff(propertyValue), + ).toEqual([{id: 1, name: "new"}, {id: 2}]); } expect(testProperty.type.serialize(null)).toBe(null); @@ -50,157 +65,326 @@ describe("array type", () => { expect(testProperty.type.deserialize(undefined)).toBe(undefined); expect(testProperty.type.serializeDiff(undefined)).toBe(undefined); - expect(testProperty.type.hasChanged([12.547, 8, -52.11], [12.547, 8, -52.11])).toBeFalsy(); + expect( + testProperty.type.hasChanged([12.547, 8, -52.11], [12.547, 8, -52.11]), + ).toBeFalsy(); expect(testProperty.type.hasChanged(null, null)).toBeFalsy(); expect(testProperty.type.hasChanged(undefined, undefined)).toBeFalsy(); expect(testProperty.type.hasChanged(null, undefined)).toBeTruthy(); expect(testProperty.type.hasChanged(undefined, null)).toBeTruthy(); - expect(testProperty.type.hasChanged(null, [12.547, 8, -52.11])).toBeTruthy(); - expect(testProperty.type.hasChanged(undefined, [12.547, 8, -52.11])).toBeTruthy(); - expect(testProperty.type.hasChanged([12.547, 8, -52.11], null)).toBeTruthy(); - expect(testProperty.type.hasChanged([12.547, 8, -52.11], undefined)).toBeTruthy(); - expect(testProperty.type.hasChanged([12.547, 8, -52.11], [12.547, -52.11, 8])).toBeTruthy(); - expect(testProperty.type.hasChanged([12.547, -52.11, 8], [12.547, 8, -52.11])).toBeTruthy(); - expect(testProperty.type.hasChanged([12.547, 8, -52.11], [12.547, 8])).toBeTruthy(); - expect(testProperty.type.hasChanged([12.547, 8], [12.547, 8, -52.11])).toBeTruthy(); + expect( + testProperty.type.hasChanged(null, [12.547, 8, -52.11]), + ).toBeTruthy(); + expect( + testProperty.type.hasChanged(undefined, [12.547, 8, -52.11]), + ).toBeTruthy(); + expect( + testProperty.type.hasChanged([12.547, 8, -52.11], null), + ).toBeTruthy(); + expect( + testProperty.type.hasChanged([12.547, 8, -52.11], undefined), + ).toBeTruthy(); + expect( + testProperty.type.hasChanged([12.547, 8, -52.11], [12.547, -52.11, 8]), + ).toBeTruthy(); + expect( + testProperty.type.hasChanged([12.547, -52.11, 8], [12.547, 8, -52.11]), + ).toBeTruthy(); + expect( + testProperty.type.hasChanged([12.547, 8, -52.11], [12.547, 8]), + ).toBeTruthy(); + expect( + testProperty.type.hasChanged([12.547, 8], [12.547, 8, -52.11]), + ).toBeTruthy(); - expect(testProperty.type.serializedHasChanged(["12.547", "8", "-52.11"], ["12.547", "8", "-52.11"])).toBeFalsy(); + expect( + testProperty.type.serializedHasChanged( + ["12.547", "8", "-52.11"], + ["12.547", "8", "-52.11"], + ), + ).toBeFalsy(); expect(testProperty.type.serializedHasChanged(null, null)).toBeFalsy(); - expect(testProperty.type.serializedHasChanged(undefined, undefined)).toBeFalsy(); - expect(testProperty.type.serializedHasChanged(null, undefined)).toBeTruthy(); - expect(testProperty.type.serializedHasChanged(undefined, null)).toBeTruthy(); - expect(testProperty.type.serializedHasChanged(null, ["12.547", "8", "-52.11"])).toBeTruthy(); - expect(testProperty.type.serializedHasChanged(undefined, ["12.547", "8", "-52.11"])).toBeTruthy(); - expect(testProperty.type.serializedHasChanged(["12.547", "8", "-52.11"], null)).toBeTruthy(); - expect(testProperty.type.serializedHasChanged(["12.547", "8", "-52.11"], undefined)).toBeTruthy(); - expect(testProperty.type.serializedHasChanged(["12.547", "8", "-52.11"], ["12.547", "-52.11", "8"])).toBeTruthy(); - expect(testProperty.type.serializedHasChanged(["12.547", "-52.11", "8"], ["12.547", "8", "-52.11"])).toBeTruthy(); - expect(testProperty.type.serializedHasChanged(["12.547", "8", "-52.11"], ["12.547", "8"])).toBeTruthy(); - expect(testProperty.type.serializedHasChanged(["12.547", "8"], ["12.547", "8", "-52.11"])).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged(undefined, undefined), + ).toBeFalsy(); + expect( + testProperty.type.serializedHasChanged(null, undefined), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged(undefined, null), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged(null, ["12.547", "8", "-52.11"]), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged(undefined, [ + "12.547", + "8", + "-52.11", + ]), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged(["12.547", "8", "-52.11"], null), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged( + ["12.547", "8", "-52.11"], + undefined, + ), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged( + ["12.547", "8", "-52.11"], + ["12.547", "-52.11", "8"], + ), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged( + ["12.547", "-52.11", "8"], + ["12.547", "8", "-52.11"], + ), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged( + ["12.547", "8", "-52.11"], + ["12.547", "8"], + ), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged( + ["12.547", "8"], + ["12.547", "8", "-52.11"], + ), + ).toBeTruthy(); - { // Try to reset the difference of an array with one changed model. + { + // Try to reset the difference of an array with one changed model. const propertyValue = [ - testModel.model(Object.assign(new TestModel(), { id: 1, name: "test", price: 22 })).instance, - testModel.model(Object.assign(new TestModel(), { id: 2, name: "another", price: 12.55 })).instance, + testModel.model( + Object.assign(new TestModel(), {id: 1, name: "test", price: 22}), + ).instance, + testModel.model( + Object.assign(new TestModel(), { + id: 2, + name: "another", + price: 12.55, + }), + ).instance, ]; propertyValue[0].name = "new"; - expect(s.property.array(s.property.model(testModel)).type.serializeDiff(propertyValue)).toEqual([ - { id: 1, name: "new" }, - { id: 2 }, - ]); - s.property.array(s.property.model(testModel)).type.resetDiff(propertyValue) - expect(s.property.array(s.property.model(testModel)).type.serializeDiff(propertyValue)).toEqual([ - { id: 1 }, - { id: 2 }, - ]); + expect( + s.property + .array(s.property.model(testModel)) + .type.serializeDiff(propertyValue), + ).toEqual([{id: 1, name: "new"}, {id: 2}]); + s.property + .array(s.property.model(testModel)) + .type.resetDiff(propertyValue); + expect( + s.property + .array(s.property.model(testModel)) + .type.serializeDiff(propertyValue), + ).toEqual([{id: 1}, {id: 2}]); } testProperty.type.resetDiff(undefined); testProperty.type.resetDiff(null); - { // Test that values are cloned in a different array. + { + // Test that values are cloned in a different array. const propertyValue = [12.547, 8, -52.11]; const clonedPropertyValue = testProperty.type.clone(propertyValue); expect(clonedPropertyValue).not.toBe(propertyValue); expect(clonedPropertyValue).toEqual(propertyValue); } - { // Test that values are cloned recursively. + { + // Test that values are cloned recursively. const propertyValue = [ - testModel.model(Object.assign(new TestModel(), { id: 1, name: "test", price: 22 })).instance, - testModel.model(Object.assign(new TestModel(), { id: 2, name: "another", price: 12.55 })).instance, + testModel.model( + Object.assign(new TestModel(), {id: 1, name: "test", price: 22}), + ).instance, + testModel.model( + Object.assign(new TestModel(), { + id: 2, + name: "another", + price: 12.55, + }), + ).instance, ]; // The arrays are different. - const clonedPropertyValue = s.property.array(s.property.model(testModel)).type.clone(propertyValue); + const clonedPropertyValue = s.property + .array(s.property.model(testModel)) + .type.clone(propertyValue); expect(clonedPropertyValue).not.toBe(propertyValue); // Array values must be different objects but have the same values. expect(clonedPropertyValue[0]).not.toBe(propertyValue[0]); expect(clonedPropertyValue[1]).not.toBe(propertyValue[1]); - expect(testModel.model(clonedPropertyValue[0]).getInstanceProperties()).toEqual(testModel.model(propertyValue[0]).getInstanceProperties()); - expect(testModel.model(clonedPropertyValue[1]).getInstanceProperties()).toEqual(testModel.model(propertyValue[1]).getInstanceProperties()); + expect( + testModel.model(clonedPropertyValue[0]).getInstanceProperties(), + ).toEqual(testModel.model(propertyValue[0]).getInstanceProperties()); + expect( + testModel.model(clonedPropertyValue[1]).getInstanceProperties(), + ).toEqual(testModel.model(propertyValue[1]).getInstanceProperties()); } expect(testProperty.type.clone(undefined)).toBe(undefined); expect(testProperty.type.clone(null)).toBe(null); - { // Test simple patch. + { + // Test simple patch. expect( - testProperty.type.applyPatch([12.547, 8, -52.11], ["12.547", "444.34", "-52.11"], true) + testProperty.type.applyPatch( + [12.547, 8, -52.11], + ["12.547", "444.34", "-52.11"], + true, + ), ).toEqual([12.547, 444.34, -52.11]); expect( - testProperty.type.applyPatch(undefined, ["12.547", "444.34", "-52.11"], false) + testProperty.type.applyPatch( + undefined, + ["12.547", "444.34", "-52.11"], + false, + ), ).toEqual([12.547, 444.34, -52.11]); expect( - testProperty.type.applyPatch(null, ["12.547", "444.34", "-52.11"], false) + testProperty.type.applyPatch( + null, + ["12.547", "444.34", "-52.11"], + false, + ), ).toEqual([12.547, 444.34, -52.11]); expect( - testProperty.type.applyPatch([12.547, 8, -52.11], undefined, false) + testProperty.type.applyPatch([12.547, 8, -52.11], undefined, false), ).toBeUndefined(); expect( - testProperty.type.applyPatch([12.547, 8, -52.11], null, false) + testProperty.type.applyPatch([12.547, 8, -52.11], null, false), ).toBeNull(); } - { // Invalid patch. - expect( - () => testProperty.type.applyPatch([12.547, 8, -52.11], {} as any, false) + { + // Invalid patch. + expect(() => + testProperty.type.applyPatch([12.547, 8, -52.11], {} as any, false), ).toThrow(InvalidTypeValueError); } - { // Test recursive patch. + { + // Test recursive patch. const propertyValue = [ - testModel.model(Object.assign(new TestModel(), { id: 1, name: "test", price: 22 })).instance, - testModel.model(Object.assign(new TestModel(), { id: 2, name: "another", price: 12.55 })).instance, + testModel.model( + Object.assign(new TestModel(), {id: 1, name: "test", price: 22}), + ).instance, + testModel.model( + Object.assign(new TestModel(), { + id: 2, + name: "another", + price: 12.55, + }), + ).instance, ]; - const patched = s.property.array(s.property.model(testModel)).type.applyPatch(propertyValue, [{ - id: 1, - name: "new", - }, { - id: 2, - price: "13.65", - }], true); + const patched = s.property + .array(s.property.model(testModel)) + .type.applyPatch( + propertyValue, + [ + { + id: 1, + name: "new", + }, + { + id: 2, + price: "13.65", + }, + ], + true, + ); // Check applied patch. expect(patched).toEqual([ - testModel.parse({ id: 1, name: "new", price: "22" }), - testModel.parse({ id: 2, name: "another", price: "13.65" }), + testModel.parse({id: 1, name: "new", price: "22"}), + testModel.parse({id: 2, name: "another", price: "13.65"}), ]); // Check that originals have been updated. - expect(testModel.model(patched[0]).serializeDiff()).toEqual({ id: 1 }); + expect(testModel.model(patched[0]).serializeDiff()).toEqual({id: 1}); patched[0].name = "test"; - expect(testModel.model(patched[0]).serializeDiff()).toEqual({ id: 1, name: "test" }); - expect(testModel.model(patched[1]).serializeDiff()).toEqual({ id: 2 }); + expect(testModel.model(patched[0]).serializeDiff()).toEqual({ + id: 1, + name: "test", + }); + expect(testModel.model(patched[1]).serializeDiff()).toEqual({id: 2}); patched[1].price = 12.55; - expect(testModel.model(patched[1]).serializeDiff()).toEqual({ id: 2, price: "12.55" }); + expect(testModel.model(patched[1]).serializeDiff()).toEqual({ + id: 2, + price: "12.55", + }); } - { // Test recursive patch without originals update.- + { + // Test recursive patch without originals update.- const propertyValue = [ - testModel.model(Object.assign(new TestModel(), { id: 1, name: "test", price: 22 })).instance, - testModel.model(Object.assign(new TestModel(), { id: 2, name: "another", price: 12.55 })).instance, + testModel.model( + Object.assign(new TestModel(), {id: 1, name: "test", price: 22}), + ).instance, + testModel.model( + Object.assign(new TestModel(), { + id: 2, + name: "another", + price: 12.55, + }), + ).instance, ]; - const patched = s.property.array(s.property.model(testModel)).type.applyPatch(propertyValue, [{ - id: 1, - name: "new", - }, { - id: 2, - price: "13.65", - }], false); + const patched = s.property + .array(s.property.model(testModel)) + .type.applyPatch( + propertyValue, + [ + { + id: 1, + name: "new", + }, + { + id: 2, + price: "13.65", + }, + ], + false, + ); // Check that originals haven't been updated. - expect(testModel.model(patched[0]).serializeDiff()).toEqual({ id: 1, name: "new" }); - expect(testModel.model(patched[1]).serializeDiff()).toEqual({ id: 2, price: "13.65" }); + expect(testModel.model(patched[0]).serializeDiff()).toEqual({ + id: 1, + name: "new", + }); + expect(testModel.model(patched[1]).serializeDiff()).toEqual({ + id: 2, + price: "13.65", + }); } }); test("invalid parameters types", () => { - expect(() => testProperty.type.serialize({} as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.deserialize({} as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.serializeDiff({} as any)).toThrowError(InvalidTypeValueError); + expect(() => testProperty.type.serialize({} as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => testProperty.type.deserialize({} as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => testProperty.type.serializeDiff({} as any)).toThrowError( + InvalidTypeValueError, + ); expect(() => testProperty.type.resetDiff({} as any)).not.toThrow(); expect(testProperty.type.hasChanged({} as any, {} as any)).toBeTruthy(); - expect(testProperty.type.hasChanged(false as any, false as any)).toBeFalsy(); - expect(testProperty.type.serializedHasChanged({} as any, {} as any)).toBeTruthy(); - expect(testProperty.type.serializedHasChanged(false as any, false as any)).toBeFalsy(); - expect(() => testProperty.type.clone({} as any)).toThrowError(InvalidTypeValueError); + expect( + testProperty.type.hasChanged(false as any, false as any), + ).toBeFalsy(); + expect( + testProperty.type.serializedHasChanged({} as any, {} as any), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged(false as any, false as any), + ).toBeFalsy(); + expect(() => testProperty.type.clone({} as any)).toThrowError( + InvalidTypeValueError, + ); }); }); diff --git a/tests/model/types/boolean.test.ts b/tests/model/types/boolean.test.ts index e77e6ab..9e14d65 100644 --- a/tests/model/types/boolean.test.ts +++ b/tests/model/types/boolean.test.ts @@ -28,7 +28,9 @@ describe("boolean type", () => { expect(s.property.boolean().type.hasChanged(true, true)).toBeFalsy(); expect(s.property.boolean().type.hasChanged(null, null)).toBeFalsy(); - expect(s.property.boolean().type.hasChanged(undefined, undefined)).toBeFalsy(); + expect( + s.property.boolean().type.hasChanged(undefined, undefined), + ).toBeFalsy(); expect(s.property.boolean().type.hasChanged(null, undefined)).toBeTruthy(); expect(s.property.boolean().type.hasChanged(undefined, null)).toBeTruthy(); expect(s.property.boolean().type.hasChanged(null, false)).toBeTruthy(); @@ -36,28 +38,58 @@ describe("boolean type", () => { expect(s.property.boolean().type.hasChanged(false, null)).toBeTruthy(); expect(s.property.boolean().type.hasChanged(false, undefined)).toBeTruthy(); - expect(s.property.boolean().type.serializedHasChanged(false, false)).toBeFalsy(); - expect(s.property.boolean().type.serializedHasChanged(null, null)).toBeFalsy(); - expect(s.property.boolean().type.serializedHasChanged(undefined, undefined)).toBeFalsy(); - expect(s.property.boolean().type.serializedHasChanged(null, undefined)).toBeTruthy(); - expect(s.property.boolean().type.serializedHasChanged(undefined, null)).toBeTruthy(); - expect(s.property.boolean().type.serializedHasChanged(null, false)).toBeTruthy(); - expect(s.property.boolean().type.serializedHasChanged(undefined, false)).toBeTruthy(); - expect(s.property.boolean().type.serializedHasChanged(false, null)).toBeTruthy(); - expect(s.property.boolean().type.serializedHasChanged(false, undefined)).toBeTruthy(); + expect( + s.property.boolean().type.serializedHasChanged(false, false), + ).toBeFalsy(); + expect( + s.property.boolean().type.serializedHasChanged(null, null), + ).toBeFalsy(); + expect( + s.property.boolean().type.serializedHasChanged(undefined, undefined), + ).toBeFalsy(); + expect( + s.property.boolean().type.serializedHasChanged(null, undefined), + ).toBeTruthy(); + expect( + s.property.boolean().type.serializedHasChanged(undefined, null), + ).toBeTruthy(); + expect( + s.property.boolean().type.serializedHasChanged(null, false), + ).toBeTruthy(); + expect( + s.property.boolean().type.serializedHasChanged(undefined, false), + ).toBeTruthy(); + expect( + s.property.boolean().type.serializedHasChanged(false, null), + ).toBeTruthy(); + expect( + s.property.boolean().type.serializedHasChanged(false, undefined), + ).toBeTruthy(); s.property.boolean().type.resetDiff(false); s.property.boolean().type.resetDiff(undefined); s.property.boolean().type.resetDiff(null); - expect(s.property.boolean().type.applyPatch(false, true, true)).toBeTruthy(); - expect(s.property.boolean().type.applyPatch(false, true, false)).toBeTruthy(); - expect(s.property.boolean().type.applyPatch(true, false, false)).toBeFalsy(); - expect(s.property.boolean().type.applyPatch(false, undefined, false)).toBeUndefined(); + expect( + s.property.boolean().type.applyPatch(false, true, true), + ).toBeTruthy(); + expect( + s.property.boolean().type.applyPatch(false, true, false), + ).toBeTruthy(); + expect( + s.property.boolean().type.applyPatch(true, false, false), + ).toBeFalsy(); + expect( + s.property.boolean().type.applyPatch(false, undefined, false), + ).toBeUndefined(); expect(s.property.boolean().type.applyPatch(false, null, false)).toBeNull(); - expect(s.property.boolean().type.applyPatch(undefined, null, false)).toBeNull(); + expect( + s.property.boolean().type.applyPatch(undefined, null, false), + ).toBeNull(); expect(s.property.boolean().type.applyPatch(null, null, false)).toBeNull(); - expect(s.property.boolean().type.applyPatch(null, false, false)).toBeFalsy(); + expect( + s.property.boolean().type.applyPatch(null, false, false), + ).toBeFalsy(); }); test("invalid parameters types", () => { @@ -68,10 +100,20 @@ describe("boolean type", () => { expect(s.property.boolean().type.serializeDiff(1 as any)).toBeTruthy(); expect(s.property.boolean().type.serializeDiff(0 as any)).toBeFalsy(); expect(() => s.property.boolean().type.resetDiff({} as any)).not.toThrow(); - expect(s.property.boolean().type.hasChanged({} as any, {} as any)).toBeTruthy(); - expect(s.property.boolean().type.hasChanged(false as any, false as any)).toBeFalsy(); - expect(s.property.boolean().type.serializedHasChanged({} as any, {} as any)).toBeTruthy(); - expect(s.property.boolean().type.serializedHasChanged(false as any, false as any)).toBeFalsy(); + expect( + s.property.boolean().type.hasChanged({} as any, {} as any), + ).toBeTruthy(); + expect( + s.property.boolean().type.hasChanged(false as any, false as any), + ).toBeFalsy(); + expect( + s.property.boolean().type.serializedHasChanged({} as any, {} as any), + ).toBeTruthy(); + expect( + s.property + .boolean() + .type.serializedHasChanged(false as any, false as any), + ).toBeFalsy(); expect(s.property.boolean().type.clone({} as any)).toStrictEqual({}); }); }); diff --git a/tests/model/types/date.test.ts b/tests/model/types/date.test.ts index 9cac39a..6ff31be 100644 --- a/tests/model/types/date.test.ts +++ b/tests/model/types/date.test.ts @@ -10,11 +10,24 @@ describe("date type", () => { }); test("date type functions", () => { - expect(s.property.date().type.serialize(testDate)).toBe(testDate.toISOString()); - expect(s.property.date().type.deserialize(testDate.toISOString())?.getTime()).toBe(testDate.getTime()); - expect(s.property.date().type.serializeDiff(new Date(testDate))).toBe(testDate.toISOString()); - expect(s.property.date().type.deserialize("2565152-2156121-256123121 5121544175:21515612").valueOf()).toBeNaN(); - expect(s.property.date().type.serialize(new Date(NaN))).toBe((new Date(NaN)).toString()); + expect(s.property.date().type.serialize(testDate)).toBe( + testDate.toISOString(), + ); + expect( + s.property.date().type.deserialize(testDate.toISOString())?.getTime(), + ).toBe(testDate.getTime()); + expect(s.property.date().type.serializeDiff(new Date(testDate))).toBe( + testDate.toISOString(), + ); + expect( + s.property + .date() + .type.deserialize("2565152-2156121-256123121 5121544175:21515612") + .valueOf(), + ).toBeNaN(); + expect(s.property.date().type.serialize(new Date(NaN))).toBe( + new Date(NaN).toString(), + ); expect(s.property.date().type.serialize(null)).toBe(null); expect(s.property.date().type.deserialize(null)).toBe(null); @@ -24,7 +37,9 @@ describe("date type", () => { expect(s.property.date().type.deserialize(undefined)).toBe(undefined); expect(s.property.date().type.serializeDiff(undefined)).toBe(undefined); - expect(s.property.date().type.hasChanged(testDate, new Date(testDate))).toBeFalsy(); + expect( + s.property.date().type.hasChanged(testDate, new Date(testDate)), + ).toBeFalsy(); expect(s.property.date().type.hasChanged(null, null)).toBeFalsy(); expect(s.property.date().type.hasChanged(undefined, undefined)).toBeFalsy(); expect(s.property.date().type.hasChanged(null, undefined)).toBeTruthy(); @@ -33,48 +48,129 @@ describe("date type", () => { expect(s.property.date().type.hasChanged(undefined, testDate)).toBeTruthy(); expect(s.property.date().type.hasChanged(testDate, null)).toBeTruthy(); expect(s.property.date().type.hasChanged(new Date(NaN), null)).toBeTruthy(); - expect(s.property.date().type.hasChanged(new Date(NaN), undefined)).toBeTruthy(); - expect(s.property.date().type.hasChanged(new Date(NaN), new Date(NaN))).toBeFalsy(); + expect( + s.property.date().type.hasChanged(new Date(NaN), undefined), + ).toBeTruthy(); + expect( + s.property.date().type.hasChanged(new Date(NaN), new Date(NaN)), + ).toBeFalsy(); - expect(s.property.date().type.serializedHasChanged(testDate.toISOString(), (new Date(testDate)).toISOString())).toBeFalsy(); + expect( + s.property + .date() + .type.serializedHasChanged( + testDate.toISOString(), + new Date(testDate).toISOString(), + ), + ).toBeFalsy(); expect(s.property.date().type.serializedHasChanged(null, null)).toBeFalsy(); - expect(s.property.date().type.serializedHasChanged(undefined, undefined)).toBeFalsy(); - expect(s.property.date().type.serializedHasChanged(null, undefined)).toBeTruthy(); - expect(s.property.date().type.serializedHasChanged(undefined, null)).toBeTruthy(); - expect(s.property.date().type.serializedHasChanged(null, testDate.toISOString())).toBeTruthy(); - expect(s.property.date().type.serializedHasChanged(undefined, testDate.toISOString())).toBeTruthy(); - expect(s.property.date().type.serializedHasChanged(testDate.toISOString(), null)).toBeTruthy(); - expect(s.property.date().type.serializedHasChanged((new Date(NaN)).toString(), null)).toBeTruthy(); - expect(s.property.date().type.serializedHasChanged((new Date(NaN)).toString(), undefined)).toBeTruthy(); - expect(s.property.date().type.serializedHasChanged((new Date(NaN)).toString(), (new Date(NaN)).toString())).toBeFalsy(); + expect( + s.property.date().type.serializedHasChanged(undefined, undefined), + ).toBeFalsy(); + expect( + s.property.date().type.serializedHasChanged(null, undefined), + ).toBeTruthy(); + expect( + s.property.date().type.serializedHasChanged(undefined, null), + ).toBeTruthy(); + expect( + s.property.date().type.serializedHasChanged(null, testDate.toISOString()), + ).toBeTruthy(); + expect( + s.property + .date() + .type.serializedHasChanged(undefined, testDate.toISOString()), + ).toBeTruthy(); + expect( + s.property.date().type.serializedHasChanged(testDate.toISOString(), null), + ).toBeTruthy(); + expect( + s.property + .date() + .type.serializedHasChanged(new Date(NaN).toString(), null), + ).toBeTruthy(); + expect( + s.property + .date() + .type.serializedHasChanged(new Date(NaN).toString(), undefined), + ).toBeTruthy(); + expect( + s.property + .date() + .type.serializedHasChanged( + new Date(NaN).toString(), + new Date(NaN).toString(), + ), + ).toBeFalsy(); s.property.date().type.resetDiff(testDate); s.property.date().type.resetDiff(undefined); s.property.date().type.resetDiff(null); - { // Test that the date is cloned in a different object. + { + // Test that the date is cloned in a different object. const propertyValue = new Date(); const clonedPropertyValue = s.property.date().type.clone(propertyValue); expect(clonedPropertyValue).not.toBe(propertyValue); expect(clonedPropertyValue).toEqual(propertyValue); } - expect(s.property.date().type.applyPatch(new Date("2022-02-22"), testDate.toISOString(), false)?.getTime()).toBe(testDate.getTime()); - expect(s.property.date().type.applyPatch(null, testDate.toISOString(), true)?.getTime()).toBe(testDate.getTime()); - expect(s.property.date().type.applyPatch(undefined, "2565152-2156121-256123121 5121544175:21515612", false).valueOf()).toBeNaN(); - expect(s.property.date().type.applyPatch(new Date(), undefined, false)).toBeUndefined(); - expect(s.property.date().type.applyPatch(new Date(), null, false)).toBeNull(); + expect( + s.property + .date() + .type.applyPatch(new Date("2022-02-22"), testDate.toISOString(), false) + ?.getTime(), + ).toBe(testDate.getTime()); + expect( + s.property + .date() + .type.applyPatch(null, testDate.toISOString(), true) + ?.getTime(), + ).toBe(testDate.getTime()); + expect( + s.property + .date() + .type.applyPatch( + undefined, + "2565152-2156121-256123121 5121544175:21515612", + false, + ) + .valueOf(), + ).toBeNaN(); + expect( + s.property.date().type.applyPatch(new Date(), undefined, false), + ).toBeUndefined(); + expect( + s.property.date().type.applyPatch(new Date(), null, false), + ).toBeNull(); }); test("invalid parameters types", () => { - expect(() => s.property.date().type.serialize({} as any)).toThrowError(InvalidTypeValueError); - expect(s.property.date().type.deserialize({} as any).getTime()).toBe(NaN); - expect(() => s.property.date().type.serializeDiff({} as any)).toThrowError(InvalidTypeValueError); + expect(() => s.property.date().type.serialize({} as any)).toThrowError( + InvalidTypeValueError, + ); + expect( + s.property + .date() + .type.deserialize({} as any) + .getTime(), + ).toBe(NaN); + expect(() => s.property.date().type.serializeDiff({} as any)).toThrowError( + InvalidTypeValueError, + ); expect(() => s.property.date().type.resetDiff({} as any)).not.toThrow(); - expect(s.property.date().type.hasChanged({} as any, {} as any)).toBeTruthy(); - expect(s.property.date().type.hasChanged(false as any, false as any)).toBeFalsy(); - expect(s.property.date().type.serializedHasChanged({} as any, {} as any)).toBeTruthy(); - expect(s.property.date().type.serializedHasChanged(false as any, false as any)).toBeFalsy(); + expect( + s.property.date().type.hasChanged({} as any, {} as any), + ).toBeTruthy(); + expect( + s.property.date().type.hasChanged(false as any, false as any), + ).toBeFalsy(); + expect( + s.property.date().type.serializedHasChanged({} as any, {} as any), + ).toBeTruthy(); + expect( + s.property.date().type.serializedHasChanged(false as any, false as any), + ).toBeFalsy(); expect(s.property.date().type.clone({} as any)).toStrictEqual({}); }); }); diff --git a/tests/model/types/decimal.test.ts b/tests/model/types/decimal.test.ts index 6aeec3d..97fddd7 100644 --- a/tests/model/types/decimal.test.ts +++ b/tests/model/types/decimal.test.ts @@ -22,7 +22,9 @@ describe("decimal type", () => { expect(s.property.decimal().type.hasChanged(5.257, 5.257)).toBeFalsy(); expect(s.property.decimal().type.hasChanged(null, null)).toBeFalsy(); - expect(s.property.decimal().type.hasChanged(undefined, undefined)).toBeFalsy(); + expect( + s.property.decimal().type.hasChanged(undefined, undefined), + ).toBeFalsy(); expect(s.property.decimal().type.hasChanged(null, undefined)).toBeTruthy(); expect(s.property.decimal().type.hasChanged(undefined, null)).toBeTruthy(); expect(s.property.decimal().type.hasChanged(null, 5.257)).toBeTruthy(); @@ -30,37 +32,75 @@ describe("decimal type", () => { expect(s.property.decimal().type.hasChanged(5.257, null)).toBeTruthy(); expect(s.property.decimal().type.hasChanged(5.257, undefined)).toBeTruthy(); - expect(s.property.decimal().type.serializedHasChanged("5.257", "5.257")).toBeFalsy(); - expect(s.property.decimal().type.serializedHasChanged(null, null)).toBeFalsy(); - expect(s.property.decimal().type.serializedHasChanged(undefined, undefined)).toBeFalsy(); - expect(s.property.decimal().type.serializedHasChanged(null, undefined)).toBeTruthy(); - expect(s.property.decimal().type.serializedHasChanged(undefined, null)).toBeTruthy(); - expect(s.property.decimal().type.serializedHasChanged(null, "5.257")).toBeTruthy(); - expect(s.property.decimal().type.serializedHasChanged(undefined, "5.257")).toBeTruthy(); - expect(s.property.decimal().type.serializedHasChanged("5.257", null)).toBeTruthy(); - expect(s.property.decimal().type.serializedHasChanged("5.257", undefined)).toBeTruthy(); + expect( + s.property.decimal().type.serializedHasChanged("5.257", "5.257"), + ).toBeFalsy(); + expect( + s.property.decimal().type.serializedHasChanged(null, null), + ).toBeFalsy(); + expect( + s.property.decimal().type.serializedHasChanged(undefined, undefined), + ).toBeFalsy(); + expect( + s.property.decimal().type.serializedHasChanged(null, undefined), + ).toBeTruthy(); + expect( + s.property.decimal().type.serializedHasChanged(undefined, null), + ).toBeTruthy(); + expect( + s.property.decimal().type.serializedHasChanged(null, "5.257"), + ).toBeTruthy(); + expect( + s.property.decimal().type.serializedHasChanged(undefined, "5.257"), + ).toBeTruthy(); + expect( + s.property.decimal().type.serializedHasChanged("5.257", null), + ).toBeTruthy(); + expect( + s.property.decimal().type.serializedHasChanged("5.257", undefined), + ).toBeTruthy(); s.property.decimal().type.resetDiff(5.257); s.property.decimal().type.resetDiff(undefined); s.property.decimal().type.resetDiff(null); expect(s.property.decimal().type.applyPatch(1, "5.257", false)).toBe(5.257); - expect(s.property.decimal().type.applyPatch(undefined, "5.257", true)).toBe(5.257); - expect(s.property.decimal().type.applyPatch(null, "5.257", false)).toBe(5.257); - expect(s.property.decimal().type.applyPatch(5.257, undefined, false)).toBeUndefined(); + expect(s.property.decimal().type.applyPatch(undefined, "5.257", true)).toBe( + 5.257, + ); + expect(s.property.decimal().type.applyPatch(null, "5.257", false)).toBe( + 5.257, + ); + expect( + s.property.decimal().type.applyPatch(5.257, undefined, false), + ).toBeUndefined(); expect(s.property.decimal().type.applyPatch(5.257, null, false)).toBeNull(); }); test("invalid parameters types", () => { - expect(() => s.property.decimal().type.serialize({} as any)).toThrowError(InvalidTypeValueError); + expect(() => s.property.decimal().type.serialize({} as any)).toThrowError( + InvalidTypeValueError, + ); expect(s.property.decimal().type.deserialize({} as any)).toBe(NaN); expect(s.property.decimal().type.deserialize({} as any)).toBe(NaN); - expect(() => s.property.decimal().type.serializeDiff({} as any)).toThrowError(InvalidTypeValueError); + expect(() => + s.property.decimal().type.serializeDiff({} as any), + ).toThrowError(InvalidTypeValueError); expect(() => s.property.decimal().type.resetDiff({} as any)).not.toThrow(); - expect(s.property.decimal().type.hasChanged({} as any, {} as any)).toBeTruthy(); - expect(s.property.decimal().type.hasChanged(false as any, false as any)).toBeFalsy(); - expect(s.property.decimal().type.serializedHasChanged({} as any, {} as any)).toBeTruthy(); - expect(s.property.decimal().type.serializedHasChanged(false as any, false as any)).toBeFalsy(); + expect( + s.property.decimal().type.hasChanged({} as any, {} as any), + ).toBeTruthy(); + expect( + s.property.decimal().type.hasChanged(false as any, false as any), + ).toBeFalsy(); + expect( + s.property.decimal().type.serializedHasChanged({} as any, {} as any), + ).toBeTruthy(); + expect( + s.property + .decimal() + .type.serializedHasChanged(false as any, false as any), + ).toBeFalsy(); expect(s.property.decimal().type.clone({} as any)).toStrictEqual({}); }); }); diff --git a/tests/model/types/map.test.ts b/tests/model/types/map.test.ts index 0196963..1e021d9 100644 --- a/tests/model/types/map.test.ts +++ b/tests/model/types/map.test.ts @@ -1,5 +1,10 @@ import {describe, expect, test} from "vitest"; -import {InvalidTypeValueError, NumericType, s, StringType} from "../../../src/library"; +import { + InvalidTypeValueError, + NumericType, + s, + StringType, +} from "../../../src/library"; import {MapType} from "../../../src/model/types/map"; describe("map type", () => { @@ -8,7 +13,10 @@ describe("map type", () => { expect(mapType.type).toBeInstanceOf(MapType); }); - const testProperty = s.property.map(s.property.string(), s.property.decimal()); + const testProperty = s.property.map( + s.property.string(), + s.property.decimal(), + ); const testMapValue = new Map(); testMapValue.set("test", 1.52); testMapValue.set("another", 55); @@ -18,10 +26,12 @@ describe("map type", () => { test: "1.52", another: "55", }); - expect(testProperty.type.deserialize({ - test: "1.52", - another: "55", - })).toEqual(testMapValue); + expect( + testProperty.type.deserialize({ + test: "1.52", + another: "55", + }), + ).toEqual(testMapValue); expect(testProperty.type.serializeDiff(testMapValue)).toEqual({ test: "1.52", another: "55", @@ -38,11 +48,17 @@ describe("map type", () => { const anotherTestMapValue = new Map(); anotherTestMapValue.set("test", 1.52); anotherTestMapValue.set("another", 55); - expect(testProperty.type.hasChanged(testMapValue, anotherTestMapValue)).toBeFalsy(); + expect( + testProperty.type.hasChanged(testMapValue, anotherTestMapValue), + ).toBeFalsy(); anotherTestMapValue.set("test", 1.521); - expect(testProperty.type.hasChanged(testMapValue, anotherTestMapValue)).toBeTruthy(); + expect( + testProperty.type.hasChanged(testMapValue, anotherTestMapValue), + ).toBeTruthy(); anotherTestMapValue.delete("test"); - expect(testProperty.type.hasChanged(testMapValue, anotherTestMapValue)).toBeTruthy(); + expect( + testProperty.type.hasChanged(testMapValue, anotherTestMapValue), + ).toBeTruthy(); expect(testProperty.type.hasChanged(null, null)).toBeFalsy(); expect(testProperty.type.hasChanged(undefined, undefined)).toBeFalsy(); expect(testProperty.type.hasChanged(null, undefined)).toBeTruthy(); @@ -52,63 +68,109 @@ describe("map type", () => { expect(testProperty.type.hasChanged(testMapValue, null)).toBeTruthy(); expect(testProperty.type.hasChanged(testMapValue, undefined)).toBeTruthy(); - expect(testProperty.type.serializedHasChanged({ test: "1.52", another: "55" }, { test: "1.52", another: "55" })).toBeFalsy(); - expect(testProperty.type.serializedHasChanged({ test: "1.52", another: "55" }, { test: "1.521", another: "55" })).toBeTruthy(); - expect(testProperty.type.serializedHasChanged({ test: "1.52", another: "55" }, { another: "55" })).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged( + {test: "1.52", another: "55"}, + {test: "1.52", another: "55"}, + ), + ).toBeFalsy(); + expect( + testProperty.type.serializedHasChanged( + {test: "1.52", another: "55"}, + {test: "1.521", another: "55"}, + ), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged( + {test: "1.52", another: "55"}, + {another: "55"}, + ), + ).toBeTruthy(); expect(testProperty.type.serializedHasChanged(null, null)).toBeFalsy(); - expect(testProperty.type.serializedHasChanged(undefined, undefined)).toBeFalsy(); - expect(testProperty.type.serializedHasChanged(null, undefined)).toBeTruthy(); - expect(testProperty.type.serializedHasChanged(undefined, null)).toBeTruthy(); - expect(testProperty.type.serializedHasChanged(null, { test: "1.52", another: "55" })).toBeTruthy(); - expect(testProperty.type.serializedHasChanged(undefined, { test: "1.52", another: "55" })).toBeTruthy(); - expect(testProperty.type.serializedHasChanged({ test: "1.52", another: "55" }, null)).toBeTruthy(); - expect(testProperty.type.serializedHasChanged({ test: "1.52", another: "55" }, undefined)).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged(undefined, undefined), + ).toBeFalsy(); + expect( + testProperty.type.serializedHasChanged(null, undefined), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged(undefined, null), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged(null, { + test: "1.52", + another: "55", + }), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged(undefined, { + test: "1.52", + another: "55", + }), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged( + {test: "1.52", another: "55"}, + null, + ), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged( + {test: "1.52", another: "55"}, + undefined, + ), + ).toBeTruthy(); testProperty.type.resetDiff(testMapValue); testProperty.type.resetDiff(undefined); testProperty.type.resetDiff(null); - { // Test that keys and values are cloned in a different map. + { + // Test that keys and values are cloned in a different map. const clonedTestMapValue = testProperty.type.clone(testMapValue); expect(clonedTestMapValue).not.toBe(testMapValue); expect(clonedTestMapValue).toEqual(testMapValue); } - { // Test that values are cloned in a different object. + { + // Test that values are cloned in a different object. const propertyValue = new Map(); propertyValue.set("test", [12, 11]); - const clonedPropertyValue = s.property.stringMap(s.property.array(s.property.numeric())).type.clone(propertyValue); + const clonedPropertyValue = s.property + .stringMap(s.property.array(s.property.numeric())) + .type.clone(propertyValue); expect(clonedPropertyValue).not.toBe(propertyValue); expect(clonedPropertyValue).toEqual(propertyValue); - expect(clonedPropertyValue.get("test")).not.toBe(propertyValue.get("test")); - expect(clonedPropertyValue.get("test")).toEqual(propertyValue.get("test")); + expect(clonedPropertyValue.get("test")).not.toBe( + propertyValue.get("test"), + ); + expect(clonedPropertyValue.get("test")).toEqual( + propertyValue.get("test"), + ); } expect(testProperty.type.clone(undefined)).toBe(undefined); expect(testProperty.type.clone(null)).toBe(null); - { // Apply a patch with undefined / NULL values. - expect(testProperty.type.applyPatch( - testMapValue, - undefined, - false - )).toBeUndefined(); - expect(testProperty.type.applyPatch( - testMapValue, - null, - true - )).toBeNull(); + { + // Apply a patch with undefined / NULL values. + expect( + testProperty.type.applyPatch(testMapValue, undefined, false), + ).toBeUndefined(); + expect(testProperty.type.applyPatch(testMapValue, null, true)).toBeNull(); } - { // Invalid patch. - expect( - () => testProperty.type.applyPatch(testMapValue, 5416 as any, false) + { + // Invalid patch. + expect(() => + testProperty.type.applyPatch(testMapValue, 5416 as any, false), ).toThrow(InvalidTypeValueError); } - { // Apply a patch. + { + // Apply a patch. { const objectInstance = testProperty.type.applyPatch( testMapValue, - { test: "1.521" }, + {test: "1.521"}, true, ); @@ -121,8 +183,8 @@ describe("map type", () => { { const objectInstance = testProperty.type.applyPatch( undefined, - { test: "1.52" }, - false + {test: "1.52"}, + false, ); const expectedMapValue = new Map(); @@ -133,8 +195,8 @@ describe("map type", () => { { const objectInstance = testProperty.type.applyPatch( null, - { test: "1.52" }, - false + {test: "1.52"}, + false, ); const expectedMapValue = new Map(); @@ -145,18 +207,40 @@ describe("map type", () => { }); test("invalid parameters types", () => { - expect(() => testProperty.type.serialize(5 as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.deserialize(5 as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.serializeDiff(5 as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.clone(5 as any)).toThrowError(InvalidTypeValueError); + expect(() => testProperty.type.serialize(5 as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => testProperty.type.deserialize(5 as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => testProperty.type.serializeDiff(5 as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => testProperty.type.clone(5 as any)).toThrowError( + InvalidTypeValueError, + ); - expect(() => testProperty.type.serialize([] as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.deserialize([] as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.serializeDiff([] as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.clone([] as any)).toThrowError(InvalidTypeValueError); + expect(() => testProperty.type.serialize([] as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => testProperty.type.deserialize([] as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => testProperty.type.serializeDiff([] as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => testProperty.type.clone([] as any)).toThrowError( + InvalidTypeValueError, + ); - expect(() => testProperty.type.serialize({} as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.serializeDiff({} as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.clone({} as any)).toThrowError(InvalidTypeValueError); + expect(() => testProperty.type.serialize({} as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => testProperty.type.serializeDiff({} as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => testProperty.type.clone({} as any)).toThrowError( + InvalidTypeValueError, + ); }); }); diff --git a/tests/model/types/model.test.ts b/tests/model/types/model.test.ts index f4b6ef7..f199401 100644 --- a/tests/model/types/model.test.ts +++ b/tests/model/types/model.test.ts @@ -1,8 +1,7 @@ import {describe, expect, test} from "vitest"; import {InvalidTypeValueError, ModelType, s} from "../../../src/library"; -class TestModel -{ +class TestModel { id: number; name: string; price: number; @@ -25,164 +24,381 @@ describe("model type", () => { }); test("model type functions", () => { - { // Try to serialize / deserialize. - const testModelInstance = testModel.model(Object.assign(new TestModel(), { id: 1, name: "test", price: 12.548777 })).instance; - expect(s.property.model(testModel).type.serialize(testModelInstance)).toEqual({ id: 1, name: "test", price: "12.548777" }); - expect(testModel.model( - s.property.model(testModel).type.deserialize({ id: 1, name: "test", price: "12.548777" }) - ).getInstanceProperties()).toEqual(testModel.model(testModelInstance).getInstanceProperties()); + { + // Try to serialize / deserialize. + const testModelInstance = testModel.model( + Object.assign(new TestModel(), { + id: 1, + name: "test", + price: 12.548777, + }), + ).instance; + expect( + s.property.model(testModel).type.serialize(testModelInstance), + ).toEqual({id: 1, name: "test", price: "12.548777"}); + expect( + testModel + .model( + s.property + .model(testModel) + .type.deserialize({id: 1, name: "test", price: "12.548777"}), + ) + .getInstanceProperties(), + ).toEqual(testModel.model(testModelInstance).getInstanceProperties()); } - { // Try to serialize the difference. - const testModelInstance = testModel.model(Object.assign(new TestModel(), { id: 1, name: "test", price: 12.548777 })).instance; + { + // Try to serialize the difference. + const testModelInstance = testModel.model( + Object.assign(new TestModel(), { + id: 1, + name: "test", + price: 12.548777, + }), + ).instance; testModelInstance.name = "new"; - expect(s.property.model(testModel).type.serializeDiff(testModelInstance)).toEqual({ id: 1, name: "new" }); + expect( + s.property.model(testModel).type.serializeDiff(testModelInstance), + ).toEqual({id: 1, name: "new"}); } expect(s.property.model(testModel).type.serialize(null)).toEqual(null); expect(s.property.model(testModel).type.deserialize(null)).toEqual(null); expect(s.property.model(testModel).type.serializeDiff(null)).toEqual(null); - expect(s.property.model(testModel).type.serialize(undefined)).toEqual(undefined); - expect(s.property.model(testModel).type.deserialize(undefined)).toEqual(undefined); - expect(s.property.model(testModel).type.serializeDiff(undefined)).toEqual(undefined); + expect(s.property.model(testModel).type.serialize(undefined)).toEqual( + undefined, + ); + expect(s.property.model(testModel).type.deserialize(undefined)).toEqual( + undefined, + ); + expect(s.property.model(testModel).type.serializeDiff(undefined)).toEqual( + undefined, + ); { - const testModelInstance = testModel.model(Object.assign(new TestModel(), { id: 1, name: "test", price: 12.548777 })).instance; - expect(s.property.model(testModel).type.hasChanged(testModelInstance, testModelInstance)).toBeFalsy(); + const testModelInstance = testModel.model( + Object.assign(new TestModel(), { + id: 1, + name: "test", + price: 12.548777, + }), + ).instance; + expect( + s.property + .model(testModel) + .type.hasChanged(testModelInstance, testModelInstance), + ).toBeFalsy(); } { - const testModelInstance = testModel.model(Object.assign(new TestModel(), { id: 1, name: "test", price: 12.548777 })).instance; + const testModelInstance = testModel.model( + Object.assign(new TestModel(), { + id: 1, + name: "test", + price: 12.548777, + }), + ).instance; testModelInstance.price = 12.548778; - expect(s.property.model(testModel).type.hasChanged(testModelInstance, testModelInstance)).toBeTruthy(); + expect( + s.property + .model(testModel) + .type.hasChanged(testModelInstance, testModelInstance), + ).toBeTruthy(); } expect(s.property.model(testModel).type.hasChanged(null, null)).toBeFalsy(); - expect(s.property.model(testModel).type.hasChanged(undefined, undefined)).toBeFalsy(); - expect(s.property.model(testModel).type.hasChanged(null, undefined)).toBeTruthy(); - expect(s.property.model(testModel).type.hasChanged(undefined, null)).toBeTruthy(); - expect(s.property.model(testModel).type.hasChanged(null, testModel.model(Object.assign(new TestModel(), { id: 1, name: "test", price: 12.548777 })).instance)).toBeTruthy(); - expect(s.property.model(testModel).type.hasChanged(undefined, testModel.model(Object.assign(new TestModel(), { id: 1, name: "test", price: 12.548777 })).instance)).toBeTruthy(); - expect(s.property.model(testModel).type.hasChanged(testModel.model(Object.assign(new TestModel(), { id: 1, name: "test", price: 12.548777 })).instance, null)).toBeTruthy(); - expect(s.property.model(testModel).type.hasChanged(testModel.model(Object.assign(new TestModel(), { id: 1, name: "test", price: 12.548777 })).instance, undefined)).toBeTruthy(); + expect( + s.property.model(testModel).type.hasChanged(undefined, undefined), + ).toBeFalsy(); + expect( + s.property.model(testModel).type.hasChanged(null, undefined), + ).toBeTruthy(); + expect( + s.property.model(testModel).type.hasChanged(undefined, null), + ).toBeTruthy(); + expect( + s.property.model(testModel).type.hasChanged( + null, + testModel.model( + Object.assign(new TestModel(), { + id: 1, + name: "test", + price: 12.548777, + }), + ).instance, + ), + ).toBeTruthy(); + expect( + s.property.model(testModel).type.hasChanged( + undefined, + testModel.model( + Object.assign(new TestModel(), { + id: 1, + name: "test", + price: 12.548777, + }), + ).instance, + ), + ).toBeTruthy(); + expect( + s.property.model(testModel).type.hasChanged( + testModel.model( + Object.assign(new TestModel(), { + id: 1, + name: "test", + price: 12.548777, + }), + ).instance, + null, + ), + ).toBeTruthy(); + expect( + s.property.model(testModel).type.hasChanged( + testModel.model( + Object.assign(new TestModel(), { + id: 1, + name: "test", + price: 12.548777, + }), + ).instance, + undefined, + ), + ).toBeTruthy(); - expect(s.property.model(testModel).type.serializedHasChanged( - { id: 1, name: "test", price: "12.548777" }, - { id: 1, price: "12.548777", name: "test" }, - )).toBeFalsy(); - expect(s.property.model(testModel).type.serializedHasChanged( - { id: 1, name: "test", price: "12.548777" }, - { id: 1, name: "test", price: "12.548778" }, - )).toBeTruthy(); - expect(s.property.model(testModel).type.serializedHasChanged(null, null)).toBeFalsy(); - expect(s.property.model(testModel).type.serializedHasChanged(undefined, undefined)).toBeFalsy(); - expect(s.property.model(testModel).type.serializedHasChanged(null, undefined)).toBeTruthy(); - expect(s.property.model(testModel).type.serializedHasChanged(undefined, null)).toBeTruthy(); - expect(s.property.model(testModel).type.serializedHasChanged(null, { id: 1, name: "test", price: "12.548777" })).toBeTruthy(); - expect(s.property.model(testModel).type.serializedHasChanged(undefined, { id: 1, name: "test", price: "12.548777" })).toBeTruthy(); - expect(s.property.model(testModel).type.serializedHasChanged({ id: 1, name: "test", price: "12.548777" }, null)).toBeTruthy(); - expect(s.property.model(testModel).type.serializedHasChanged({ id: 1, name: "test", price: "12.548777" }, undefined)).toBeTruthy(); + expect( + s.property + .model(testModel) + .type.serializedHasChanged( + {id: 1, name: "test", price: "12.548777"}, + {id: 1, price: "12.548777", name: "test"}, + ), + ).toBeFalsy(); + expect( + s.property + .model(testModel) + .type.serializedHasChanged( + {id: 1, name: "test", price: "12.548777"}, + {id: 1, name: "test", price: "12.548778"}, + ), + ).toBeTruthy(); + expect( + s.property.model(testModel).type.serializedHasChanged(null, null), + ).toBeFalsy(); + expect( + s.property + .model(testModel) + .type.serializedHasChanged(undefined, undefined), + ).toBeFalsy(); + expect( + s.property.model(testModel).type.serializedHasChanged(null, undefined), + ).toBeTruthy(); + expect( + s.property.model(testModel).type.serializedHasChanged(undefined, null), + ).toBeTruthy(); + expect( + s.property.model(testModel).type.serializedHasChanged(null, { + id: 1, + name: "test", + price: "12.548777", + }), + ).toBeTruthy(); + expect( + s.property.model(testModel).type.serializedHasChanged(undefined, { + id: 1, + name: "test", + price: "12.548777", + }), + ).toBeTruthy(); + expect( + s.property + .model(testModel) + .type.serializedHasChanged( + {id: 1, name: "test", price: "12.548777"}, + null, + ), + ).toBeTruthy(); + expect( + s.property + .model(testModel) + .type.serializedHasChanged( + {id: 1, name: "test", price: "12.548777"}, + undefined, + ), + ).toBeTruthy(); - { // Serializing the difference to check that the difference has been reset. - const testModelInstance = testModel.model(Object.assign(new TestModel(), { id: 1, name: "test", price: 12.548777 })).instance; + { + // Serializing the difference to check that the difference has been reset. + const testModelInstance = testModel.model( + Object.assign(new TestModel(), { + id: 1, + name: "test", + price: 12.548777, + }), + ).instance; testModelInstance.price = 555.555; - expect(testModel.model(testModelInstance).serializeDiff()).toEqual({ id: 1, price: "555.555" }); + expect(testModel.model(testModelInstance).serializeDiff()).toEqual({ + id: 1, + price: "555.555", + }); s.property.model(testModel).type.resetDiff(testModelInstance); - expect(testModel.model(testModelInstance).serializeDiff()).toEqual({ id: 1 }); + expect(testModel.model(testModelInstance).serializeDiff()).toEqual({ + id: 1, + }); } s.property.model(testModel).type.resetDiff(undefined); s.property.model(testModel).type.resetDiff(null); - { // Test that values are cloned in a different model instance. - const testModelInstance = testModel.model(Object.assign(new TestModel(), { id: 1, name: "test", price: 12.548777 })).instance; + { + // Test that values are cloned in a different model instance. + const testModelInstance = testModel.model( + Object.assign(new TestModel(), { + id: 1, + name: "test", + price: 12.548777, + }), + ).instance; testModelInstance.price = 555.555; - const clonedModelInstance = s.property.model(testModel).type.clone(testModelInstance); + const clonedModelInstance = s.property + .model(testModel) + .type.clone(testModelInstance); expect(clonedModelInstance).not.toBe(testModelInstance); - expect(testModel.model(clonedModelInstance).getInstanceProperties()).toEqual(testModel.model(testModelInstance).getInstanceProperties()); - expect(testModel.model(clonedModelInstance).serializeDiff()).toEqual(testModel.model(testModelInstance).serializeDiff()); + expect( + testModel.model(clonedModelInstance).getInstanceProperties(), + ).toEqual(testModel.model(testModelInstance).getInstanceProperties()); + expect(testModel.model(clonedModelInstance).serializeDiff()).toEqual( + testModel.model(testModelInstance).serializeDiff(), + ); } expect(s.property.model(testModel).type.clone(undefined)).toBe(undefined); expect(s.property.model(testModel).type.clone(null)).toBe(null); - { // Apply a patch with undefined / NULL values. - expect(s.property.model(testModel).type.applyPatch( - testModel.model(Object.assign(new TestModel(), { id: 1, name: "test", price: 12.548777 })).instance, - undefined, - false - )).toBeUndefined(); - expect(s.property.model(testModel).type.applyPatch( - testModel.model(Object.assign(new TestModel(), { id: 1, name: "test", price: 12.548777 })).instance, - null, - true - )).toBeNull(); + { + // Apply a patch with undefined / NULL values. + expect( + s.property.model(testModel).type.applyPatch( + testModel.model( + Object.assign(new TestModel(), { + id: 1, + name: "test", + price: 12.548777, + }), + ).instance, + undefined, + false, + ), + ).toBeUndefined(); + expect( + s.property.model(testModel).type.applyPatch( + testModel.model( + Object.assign(new TestModel(), { + id: 1, + name: "test", + price: 12.548777, + }), + ).instance, + null, + true, + ), + ).toBeNull(); } - { // Invalid patch. - expect( - () => s.property.model(testModel).type.applyPatch( - testModel.model(Object.assign(new TestModel(), { id: 1, name: "test", price: 12.548777 })).instance, + { + // Invalid patch. + expect(() => + s.property.model(testModel).type.applyPatch( + testModel.model( + Object.assign(new TestModel(), { + id: 1, + name: "test", + price: 12.548777, + }), + ).instance, 5416 as any, - false - ) + false, + ), ).toThrow(InvalidTypeValueError); } - { // Apply a patch with originals update. + { + // Apply a patch with originals update. { const modelInstance = s.property.model(testModel).type.applyPatch( - testModel.model(Object.assign(new TestModel(), { id: 1, name: "test", price: 12.548777 })).instance, - { id: 1, name: "another" }, + testModel.model( + Object.assign(new TestModel(), { + id: 1, + name: "test", + price: 12.548777, + }), + ).instance, + {id: 1, name: "another"}, true, ); - expect(testModel.model(modelInstance).getInstanceProperties()).toStrictEqual({ + expect( + testModel.model(modelInstance).getInstanceProperties(), + ).toStrictEqual({ id: 1, name: "another", price: 12.548777, }); - expect(testModel.model(modelInstance).serializeDiff()).toStrictEqual({ id: 1 }); + expect(testModel.model(modelInstance).serializeDiff()).toStrictEqual({ + id: 1, + }); } { - const modelInstance = s.property.model(testModel).type.applyPatch( - undefined, - { id: 1, name: "test" }, - true - ); + const modelInstance = s.property + .model(testModel) + .type.applyPatch(undefined, {id: 1, name: "test"}, true); - expect(testModel.model(modelInstance).getInstanceProperties()).toStrictEqual({ + expect( + testModel.model(modelInstance).getInstanceProperties(), + ).toStrictEqual({ id: 1, name: "test", price: undefined, }); - expect(testModel.model(modelInstance).serializeDiff()).toStrictEqual({ id: 1 }); + expect(testModel.model(modelInstance).serializeDiff()).toStrictEqual({ + id: 1, + }); } { - const modelInstance = s.property.model(testModel).type.applyPatch( - null, - { id: 1, name: "test" }, - true - ); + const modelInstance = s.property + .model(testModel) + .type.applyPatch(null, {id: 1, name: "test"}, true); - expect(testModel.model(modelInstance).getInstanceProperties()).toStrictEqual({ + expect( + testModel.model(modelInstance).getInstanceProperties(), + ).toStrictEqual({ id: 1, name: "test", price: undefined, }); - expect(testModel.model(modelInstance).serializeDiff()).toStrictEqual({ id: 1 }); + expect(testModel.model(modelInstance).serializeDiff()).toStrictEqual({ + id: 1, + }); } } - { // Apply a patch without originals update. + { + // Apply a patch without originals update. { const modelInstance = s.property.model(testModel).type.applyPatch( - testModel.model(Object.assign(new TestModel(), { id: 1, name: "test", price: 12.548777 })).instance, - { id: 1, name: "another" }, + testModel.model( + Object.assign(new TestModel(), { + id: 1, + name: "test", + price: 12.548777, + }), + ).instance, + {id: 1, name: "another"}, false, ); - expect(testModel.model(modelInstance).getInstanceProperties()).toStrictEqual({ + expect( + testModel.model(modelInstance).getInstanceProperties(), + ).toStrictEqual({ id: 1, name: "another", price: 12.548777, @@ -194,13 +410,13 @@ describe("model type", () => { } { - const modelInstance = s.property.model(testModel).type.applyPatch( - undefined, - { id: 1, name: "test" }, - false - ); + const modelInstance = s.property + .model(testModel) + .type.applyPatch(undefined, {id: 1, name: "test"}, false); - expect(testModel.model(modelInstance).getInstanceProperties()).toStrictEqual({ + expect( + testModel.model(modelInstance).getInstanceProperties(), + ).toStrictEqual({ id: 1, name: "test", price: undefined, @@ -212,13 +428,13 @@ describe("model type", () => { } { - const modelInstance = s.property.model(testModel).type.applyPatch( - null, - { id: 1, name: "test" }, - false - ); + const modelInstance = s.property + .model(testModel) + .type.applyPatch(null, {id: 1, name: "test"}, false); - expect(testModel.model(modelInstance).getInstanceProperties()).toStrictEqual({ + expect( + testModel.model(modelInstance).getInstanceProperties(), + ).toStrictEqual({ id: 1, name: "test", price: undefined, @@ -232,27 +448,78 @@ describe("model type", () => { }); test("invalid parameters types", () => { - expect(() => s.property.model(testModel).type.serialize(5 as any)).toThrowError(InvalidTypeValueError); - expect(() => s.property.model(testModel).type.deserialize(5 as any)).toThrowError(InvalidTypeValueError); - expect(() => s.property.model(testModel).type.serializeDiff(5 as any)).toThrowError(InvalidTypeValueError); - expect(() => s.property.model(testModel).type.resetDiff(5 as any)).toThrowError(InvalidTypeValueError); - expect(() => s.property.model(testModel).type.hasChanged(5 as any, 5 as any)).toThrowError(InvalidTypeValueError); - expect(() => s.property.model(testModel).type.serializedHasChanged(5 as any, 5 as any)).toThrowError(InvalidTypeValueError); - expect(() => s.property.model(testModel).type.clone(5 as any)).toThrowError(InvalidTypeValueError); + expect(() => + s.property.model(testModel).type.serialize(5 as any), + ).toThrowError(InvalidTypeValueError); + expect(() => + s.property.model(testModel).type.deserialize(5 as any), + ).toThrowError(InvalidTypeValueError); + expect(() => + s.property.model(testModel).type.serializeDiff(5 as any), + ).toThrowError(InvalidTypeValueError); + expect(() => + s.property.model(testModel).type.resetDiff(5 as any), + ).toThrowError(InvalidTypeValueError); + expect(() => + s.property.model(testModel).type.hasChanged(5 as any, 5 as any), + ).toThrowError(InvalidTypeValueError); + expect(() => + s.property.model(testModel).type.serializedHasChanged(5 as any, 5 as any), + ).toThrowError(InvalidTypeValueError); + expect(() => s.property.model(testModel).type.clone(5 as any)).toThrowError( + InvalidTypeValueError, + ); - expect(() => s.property.model(testModel).type.serialize([] as any)).toThrowError(InvalidTypeValueError); - expect(() => s.property.model(testModel).type.deserialize([] as any)).toThrowError(InvalidTypeValueError); - expect(() => s.property.model(testModel).type.serializeDiff([] as any)).toThrowError(InvalidTypeValueError); - expect(() => s.property.model(testModel).type.resetDiff([] as any)).toThrowError(InvalidTypeValueError); - expect(() => s.property.model(testModel).type.hasChanged(testModel.model(new TestModel()).instance, [] as any)).toThrowError(InvalidTypeValueError); - expect(() => s.property.model(testModel).type.serializedHasChanged({} as any, [] as any)).toThrowError(InvalidTypeValueError); - expect(() => s.property.model(testModel).type.clone([] as any)).toThrowError(InvalidTypeValueError); + expect(() => + s.property.model(testModel).type.serialize([] as any), + ).toThrowError(InvalidTypeValueError); + expect(() => + s.property.model(testModel).type.deserialize([] as any), + ).toThrowError(InvalidTypeValueError); + expect(() => + s.property.model(testModel).type.serializeDiff([] as any), + ).toThrowError(InvalidTypeValueError); + expect(() => + s.property.model(testModel).type.resetDiff([] as any), + ).toThrowError(InvalidTypeValueError); + expect(() => + s.property + .model(testModel) + .type.hasChanged(testModel.model(new TestModel()).instance, [] as any), + ).toThrowError(InvalidTypeValueError); + expect(() => + s.property + .model(testModel) + .type.serializedHasChanged({} as any, [] as any), + ).toThrowError(InvalidTypeValueError); + expect(() => + s.property.model(testModel).type.clone([] as any), + ).toThrowError(InvalidTypeValueError); - expect(() => s.property.model(testModel).type.serialize(new class{} as any)).toThrowError(InvalidTypeValueError); - expect(() => s.property.model(testModel).type.serializeDiff(new class{} as any)).toThrowError(InvalidTypeValueError); - expect(() => s.property.model(testModel).type.resetDiff(new class{} as any)).toThrowError(InvalidTypeValueError); - expect(() => s.property.model(testModel).type.hasChanged(testModel.model(new TestModel()).instance, new class{} as any)).toThrowError(InvalidTypeValueError); - expect(s.property.model(testModel).type.serializedHasChanged({} as any, new class{} as any)).toBeFalsy(); - expect(() => s.property.model(testModel).type.clone(new class{} as any)).toThrowError(InvalidTypeValueError); + expect(() => + s.property.model(testModel).type.serialize(new (class {})() as any), + ).toThrowError(InvalidTypeValueError); + expect(() => + s.property.model(testModel).type.serializeDiff(new (class {})() as any), + ).toThrowError(InvalidTypeValueError); + expect(() => + s.property.model(testModel).type.resetDiff(new (class {})() as any), + ).toThrowError(InvalidTypeValueError); + expect(() => + s.property + .model(testModel) + .type.hasChanged( + testModel.model(new TestModel()).instance, + new (class {})() as any, + ), + ).toThrowError(InvalidTypeValueError); + expect( + s.property + .model(testModel) + .type.serializedHasChanged({} as any, new (class {})() as any), + ).toBeFalsy(); + expect(() => + s.property.model(testModel).type.clone(new (class {})() as any), + ).toThrowError(InvalidTypeValueError); }); }); diff --git a/tests/model/types/numeric.test.ts b/tests/model/types/numeric.test.ts index 5344ad1..1fe2584 100644 --- a/tests/model/types/numeric.test.ts +++ b/tests/model/types/numeric.test.ts @@ -22,7 +22,9 @@ describe("numeric type", () => { expect(s.property.numeric().type.hasChanged(5.257, 5.257)).toBeFalsy(); expect(s.property.numeric().type.hasChanged(null, null)).toBeFalsy(); - expect(s.property.numeric().type.hasChanged(undefined, undefined)).toBeFalsy(); + expect( + s.property.numeric().type.hasChanged(undefined, undefined), + ).toBeFalsy(); expect(s.property.numeric().type.hasChanged(null, undefined)).toBeTruthy(); expect(s.property.numeric().type.hasChanged(undefined, null)).toBeTruthy(); expect(s.property.numeric().type.hasChanged(null, 5.257)).toBeTruthy(); @@ -30,15 +32,33 @@ describe("numeric type", () => { expect(s.property.numeric().type.hasChanged(5.257, null)).toBeTruthy(); expect(s.property.numeric().type.hasChanged(5.257, undefined)).toBeTruthy(); - expect(s.property.numeric().type.serializedHasChanged(5.257, 5.257)).toBeFalsy(); - expect(s.property.numeric().type.serializedHasChanged(null, null)).toBeFalsy(); - expect(s.property.numeric().type.serializedHasChanged(undefined, undefined)).toBeFalsy(); - expect(s.property.numeric().type.serializedHasChanged(null, undefined)).toBeTruthy(); - expect(s.property.numeric().type.serializedHasChanged(undefined, null)).toBeTruthy(); - expect(s.property.numeric().type.serializedHasChanged(null, 5.257)).toBeTruthy(); - expect(s.property.numeric().type.serializedHasChanged(undefined, 5.257)).toBeTruthy(); - expect(s.property.numeric().type.serializedHasChanged(5.257, null)).toBeTruthy(); - expect(s.property.numeric().type.serializedHasChanged(5.257, undefined)).toBeTruthy(); + expect( + s.property.numeric().type.serializedHasChanged(5.257, 5.257), + ).toBeFalsy(); + expect( + s.property.numeric().type.serializedHasChanged(null, null), + ).toBeFalsy(); + expect( + s.property.numeric().type.serializedHasChanged(undefined, undefined), + ).toBeFalsy(); + expect( + s.property.numeric().type.serializedHasChanged(null, undefined), + ).toBeTruthy(); + expect( + s.property.numeric().type.serializedHasChanged(undefined, null), + ).toBeTruthy(); + expect( + s.property.numeric().type.serializedHasChanged(null, 5.257), + ).toBeTruthy(); + expect( + s.property.numeric().type.serializedHasChanged(undefined, 5.257), + ).toBeTruthy(); + expect( + s.property.numeric().type.serializedHasChanged(5.257, null), + ).toBeTruthy(); + expect( + s.property.numeric().type.serializedHasChanged(5.257, undefined), + ).toBeTruthy(); s.property.numeric().type.resetDiff(5.257); s.property.numeric().type.resetDiff(undefined); @@ -46,20 +66,40 @@ describe("numeric type", () => { expect(s.property.numeric().type.applyPatch(1, 5.257, false)).toBe(5.257); expect(s.property.numeric().type.applyPatch(null, 5.257, true)).toBe(5.257); - expect(s.property.numeric().type.applyPatch(undefined, 5.257, false)).toBe(5.257); - expect(s.property.numeric().type.applyPatch(5.257, undefined, false)).toBeUndefined(); + expect(s.property.numeric().type.applyPatch(undefined, 5.257, false)).toBe( + 5.257, + ); + expect( + s.property.numeric().type.applyPatch(5.257, undefined, false), + ).toBeUndefined(); expect(s.property.numeric().type.applyPatch(5.257, null, false)).toBeNull(); }); test("invalid parameters types", () => { - expect(() => s.property.numeric().type.serialize({} as any)).toThrowError(InvalidTypeValueError); - expect(() => s.property.numeric().type.deserialize({} as any)).toThrowError(InvalidTypeValueError) - expect(() => s.property.numeric().type.serializeDiff({} as any)).toThrowError(InvalidTypeValueError); + expect(() => s.property.numeric().type.serialize({} as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => s.property.numeric().type.deserialize({} as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => + s.property.numeric().type.serializeDiff({} as any), + ).toThrowError(InvalidTypeValueError); expect(() => s.property.numeric().type.resetDiff({} as any)).not.toThrow(); - expect(s.property.numeric().type.hasChanged({} as any, {} as any)).toBeTruthy(); - expect(s.property.numeric().type.hasChanged(false as any, false as any)).toBeFalsy(); - expect(s.property.numeric().type.serializedHasChanged({} as any, {} as any)).toBeTruthy(); - expect(s.property.numeric().type.serializedHasChanged(false as any, false as any)).toBeFalsy(); + expect( + s.property.numeric().type.hasChanged({} as any, {} as any), + ).toBeTruthy(); + expect( + s.property.numeric().type.hasChanged(false as any, false as any), + ).toBeFalsy(); + expect( + s.property.numeric().type.serializedHasChanged({} as any, {} as any), + ).toBeTruthy(); + expect( + s.property + .numeric() + .type.serializedHasChanged(false as any, false as any), + ).toBeFalsy(); expect(s.property.numeric().type.clone({} as any)).toStrictEqual({}); }); }); diff --git a/tests/model/types/object.test.ts b/tests/model/types/object.test.ts index 12609c3..b1063e3 100644 --- a/tests/model/types/object.test.ts +++ b/tests/model/types/object.test.ts @@ -1,5 +1,11 @@ import {describe, expect, test} from "vitest"; -import {InvalidTypeValueError, NumericType, ObjectType, s, StringType} from "../../../src/library"; +import { + InvalidTypeValueError, + NumericType, + ObjectType, + s, + StringType, +} from "../../../src/library"; describe("object type", () => { test("object type definition", () => { @@ -10,10 +16,12 @@ describe("object type", () => { expect(objectType.type).toBeInstanceOf(ObjectType); expect((objectType.type as any).properties).toHaveLength(2); - for (const property of (objectType.type as any).properties) - { // Check all object properties. - if (property.name == "test") expect(property.definition.type).toBeInstanceOf(StringType); - else if (property.name == "another") expect(property.definition.type).toBeInstanceOf(NumericType); + for (const property of (objectType.type as any).properties) { + // Check all object properties. + if (property.name == "test") + expect(property.definition.type).toBeInstanceOf(StringType); + else if (property.name == "another") + expect(property.definition.type).toBeInstanceOf(NumericType); else expect.unreachable(); } }); @@ -24,9 +32,15 @@ describe("object type", () => { }); test("object type functions", () => { - expect(testProperty.type.serialize({ test: "test", another: 12.548777 })).toEqual({ test: "test", another: "12.548777" }); - expect(testProperty.type.deserialize({ test: "test", another: "12.548777" })).toEqual({ test: "test", another: 12.548777 }); - expect(testProperty.type.serializeDiff({ test: "test", another: 12.548777 })).toEqual({ test: "test", another: "12.548777" }); + expect( + testProperty.type.serialize({test: "test", another: 12.548777}), + ).toEqual({test: "test", another: "12.548777"}); + expect( + testProperty.type.deserialize({test: "test", another: "12.548777"}), + ).toEqual({test: "test", another: 12.548777}); + expect( + testProperty.type.serializeDiff({test: "test", another: 12.548777}), + ).toEqual({test: "test", another: "12.548777"}); expect(testProperty.type.serialize(null)).toEqual(null); expect(testProperty.type.deserialize(null)).toEqual(null); @@ -36,41 +50,105 @@ describe("object type", () => { expect(testProperty.type.deserialize(undefined)).toEqual(undefined); expect(testProperty.type.serializeDiff(undefined)).toEqual(undefined); - expect(testProperty.type.hasChanged({ test: "test", another: 12.548777 }, { another: 12.548777, test: "test" })).toBeFalsy(); - expect(testProperty.type.hasChanged({ test: "test", another: 12.548777 }, { test: "test", another: 12.548778 })).toBeTruthy(); + expect( + testProperty.type.hasChanged( + {test: "test", another: 12.548777}, + {another: 12.548777, test: "test"}, + ), + ).toBeFalsy(); + expect( + testProperty.type.hasChanged( + {test: "test", another: 12.548777}, + {test: "test", another: 12.548778}, + ), + ).toBeTruthy(); expect(testProperty.type.hasChanged(null, null)).toBeFalsy(); expect(testProperty.type.hasChanged(undefined, undefined)).toBeFalsy(); expect(testProperty.type.hasChanged(null, undefined)).toBeTruthy(); expect(testProperty.type.hasChanged(undefined, null)).toBeTruthy(); - expect(testProperty.type.hasChanged(null, { test: "test", another: 12.548777 })).toBeTruthy(); - expect(testProperty.type.hasChanged(undefined, { test: "test", another: 12.548777 })).toBeTruthy(); - expect(testProperty.type.hasChanged({ test: "test", another: 12.548777 }, null)).toBeTruthy(); - expect(testProperty.type.hasChanged({ test: "test", another: 12.548777 }, undefined)).toBeTruthy(); + expect( + testProperty.type.hasChanged(null, {test: "test", another: 12.548777}), + ).toBeTruthy(); + expect( + testProperty.type.hasChanged(undefined, { + test: "test", + another: 12.548777, + }), + ).toBeTruthy(); + expect( + testProperty.type.hasChanged({test: "test", another: 12.548777}, null), + ).toBeTruthy(); + expect( + testProperty.type.hasChanged( + {test: "test", another: 12.548777}, + undefined, + ), + ).toBeTruthy(); - expect(testProperty.type.serializedHasChanged({ test: "test", another: "12.548777" }, { another: "12.548777", test: "test" })).toBeFalsy(); - expect(testProperty.type.serializedHasChanged({ test: "test", another: "12.548777" }, { test: "test", another: "12.548778" })).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged( + {test: "test", another: "12.548777"}, + {another: "12.548777", test: "test"}, + ), + ).toBeFalsy(); + expect( + testProperty.type.serializedHasChanged( + {test: "test", another: "12.548777"}, + {test: "test", another: "12.548778"}, + ), + ).toBeTruthy(); expect(testProperty.type.serializedHasChanged(null, null)).toBeFalsy(); - expect(testProperty.type.serializedHasChanged(undefined, undefined)).toBeFalsy(); - expect(testProperty.type.serializedHasChanged(null, undefined)).toBeTruthy(); - expect(testProperty.type.serializedHasChanged(undefined, null)).toBeTruthy(); - expect(testProperty.type.serializedHasChanged(null, { test: "test", another: "12.548777" })).toBeTruthy(); - expect(testProperty.type.serializedHasChanged(undefined, { test: "test", another: "12.548777" })).toBeTruthy(); - expect(testProperty.type.serializedHasChanged({ test: "test", another: "12.548777" }, null)).toBeTruthy(); - expect(testProperty.type.serializedHasChanged({ test: "test", another: "12.548777" }, undefined)).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged(undefined, undefined), + ).toBeFalsy(); + expect( + testProperty.type.serializedHasChanged(null, undefined), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged(undefined, null), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged(null, { + test: "test", + another: "12.548777", + }), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged(undefined, { + test: "test", + another: "12.548777", + }), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged( + {test: "test", another: "12.548777"}, + null, + ), + ).toBeTruthy(); + expect( + testProperty.type.serializedHasChanged( + {test: "test", another: "12.548777"}, + undefined, + ), + ).toBeTruthy(); - testProperty.type.resetDiff({ test: "test", another: 12.548777 }); + testProperty.type.resetDiff({test: "test", another: 12.548777}); testProperty.type.resetDiff(undefined); testProperty.type.resetDiff(null); - { // Test that values are cloned in a different object. - const propertyValue = { test: "test", another: 12.548777 }; + { + // Test that values are cloned in a different object. + const propertyValue = {test: "test", another: 12.548777}; const clonedPropertyValue = testProperty.type.clone(propertyValue); expect(clonedPropertyValue).not.toBe(propertyValue); expect(clonedPropertyValue).toEqual(propertyValue); } - { // Test that values are cloned in a different object. - const propertyValue = { arr: [12, 11] }; - const clonedPropertyValue = s.property.object({ arr: s.property.array(s.property.numeric()) }).type.clone(propertyValue); + { + // Test that values are cloned in a different object. + const propertyValue = {arr: [12, 11]}; + const clonedPropertyValue = s.property + .object({arr: s.property.array(s.property.numeric())}) + .type.clone(propertyValue); expect(clonedPropertyValue).not.toBe(propertyValue); expect(clonedPropertyValue).toEqual(propertyValue); expect(clonedPropertyValue.arr).not.toBe(propertyValue.arr); @@ -79,30 +157,41 @@ describe("object type", () => { expect(testProperty.type.clone(undefined)).toBe(undefined); expect(testProperty.type.clone(null)).toBe(null); - { // Apply a patch with undefined / NULL values. - expect(testProperty.type.applyPatch( - { test: "test", another: 12.548777 }, - undefined, - false - )).toBeUndefined(); - expect(testProperty.type.applyPatch( - { test: "test", another: 12.548777 }, - null, - true - )).toBeNull(); + { + // Apply a patch with undefined / NULL values. + expect( + testProperty.type.applyPatch( + {test: "test", another: 12.548777}, + undefined, + false, + ), + ).toBeUndefined(); + expect( + testProperty.type.applyPatch( + {test: "test", another: 12.548777}, + null, + true, + ), + ).toBeNull(); } - { // Invalid patch. - expect( - () => testProperty.type.applyPatch({ test: "test", another: 12.548777 }, 5416 as any, false) + { + // Invalid patch. + expect(() => + testProperty.type.applyPatch( + {test: "test", another: 12.548777}, + 5416 as any, + false, + ), ).toThrow(InvalidTypeValueError); } - { // Apply a patch. + { + // Apply a patch. { const objectInstance = testProperty.type.applyPatch( - { test: "test", another: 12.548777 }, - { test: "another" }, + {test: "test", another: 12.548777}, + {test: "another"}, true, ); @@ -115,8 +204,8 @@ describe("object type", () => { { const objectInstance = testProperty.type.applyPatch( undefined, - { test: "test" }, - false + {test: "test"}, + false, ); expect(objectInstance).toStrictEqual({ @@ -127,8 +216,8 @@ describe("object type", () => { { const objectInstance = testProperty.type.applyPatch( null, - { test: "test" }, - false + {test: "test"}, + false, ); expect(objectInstance).toStrictEqual({ @@ -139,20 +228,48 @@ describe("object type", () => { }); test("invalid parameters types", () => { - expect(() => testProperty.type.serialize(5 as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.deserialize(5 as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.serializeDiff(5 as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.resetDiff(5 as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.hasChanged(5 as any, 5 as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.serializedHasChanged(5 as any, 5 as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.clone(5 as any)).toThrowError(InvalidTypeValueError); + expect(() => testProperty.type.serialize(5 as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => testProperty.type.deserialize(5 as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => testProperty.type.serializeDiff(5 as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => testProperty.type.resetDiff(5 as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => testProperty.type.hasChanged(5 as any, 5 as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => + testProperty.type.serializedHasChanged(5 as any, 5 as any), + ).toThrowError(InvalidTypeValueError); + expect(() => testProperty.type.clone(5 as any)).toThrowError( + InvalidTypeValueError, + ); - expect(() => testProperty.type.serialize([] as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.deserialize([] as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.serializeDiff([] as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.resetDiff([] as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.hasChanged({} as any, [] as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.serializedHasChanged({} as any, [] as any)).toThrowError(InvalidTypeValueError); - expect(() => testProperty.type.clone([] as any)).toThrowError(InvalidTypeValueError); + expect(() => testProperty.type.serialize([] as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => testProperty.type.deserialize([] as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => testProperty.type.serializeDiff([] as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => testProperty.type.resetDiff([] as any)).toThrowError( + InvalidTypeValueError, + ); + expect(() => + testProperty.type.hasChanged({} as any, [] as any), + ).toThrowError(InvalidTypeValueError); + expect(() => + testProperty.type.serializedHasChanged({} as any, [] as any), + ).toThrowError(InvalidTypeValueError); + expect(() => testProperty.type.clone([] as any)).toThrowError( + InvalidTypeValueError, + ); }); }); diff --git a/tests/model/types/string.test.ts b/tests/model/types/string.test.ts index 252036b..30b55a6 100644 --- a/tests/model/types/string.test.ts +++ b/tests/model/types/string.test.ts @@ -22,7 +22,9 @@ describe("string type", () => { expect(s.property.string().type.hasChanged("test", "test")).toBeFalsy(); expect(s.property.string().type.hasChanged(null, null)).toBeFalsy(); - expect(s.property.string().type.hasChanged(undefined, undefined)).toBeFalsy(); + expect( + s.property.string().type.hasChanged(undefined, undefined), + ).toBeFalsy(); expect(s.property.string().type.hasChanged(null, undefined)).toBeTruthy(); expect(s.property.string().type.hasChanged(undefined, null)).toBeTruthy(); expect(s.property.string().type.hasChanged(null, "test")).toBeTruthy(); @@ -30,40 +32,82 @@ describe("string type", () => { expect(s.property.string().type.hasChanged("test", null)).toBeTruthy(); expect(s.property.string().type.hasChanged("test", undefined)).toBeTruthy(); - expect(s.property.string().type.serializedHasChanged("test", "test")).toBeFalsy(); - expect(s.property.string().type.serializedHasChanged(null, null)).toBeFalsy(); - expect(s.property.string().type.serializedHasChanged(undefined, undefined)).toBeFalsy(); - expect(s.property.string().type.serializedHasChanged(null, undefined)).toBeTruthy(); - expect(s.property.string().type.serializedHasChanged(undefined, null)).toBeTruthy(); - expect(s.property.string().type.serializedHasChanged(null, "test")).toBeTruthy(); - expect(s.property.string().type.serializedHasChanged(undefined, "test")).toBeTruthy(); - expect(s.property.string().type.serializedHasChanged("test", null)).toBeTruthy(); - expect(s.property.string().type.serializedHasChanged("test", undefined)).toBeTruthy(); + expect( + s.property.string().type.serializedHasChanged("test", "test"), + ).toBeFalsy(); + expect( + s.property.string().type.serializedHasChanged(null, null), + ).toBeFalsy(); + expect( + s.property.string().type.serializedHasChanged(undefined, undefined), + ).toBeFalsy(); + expect( + s.property.string().type.serializedHasChanged(null, undefined), + ).toBeTruthy(); + expect( + s.property.string().type.serializedHasChanged(undefined, null), + ).toBeTruthy(); + expect( + s.property.string().type.serializedHasChanged(null, "test"), + ).toBeTruthy(); + expect( + s.property.string().type.serializedHasChanged(undefined, "test"), + ).toBeTruthy(); + expect( + s.property.string().type.serializedHasChanged("test", null), + ).toBeTruthy(); + expect( + s.property.string().type.serializedHasChanged("test", undefined), + ).toBeTruthy(); s.property.string().type.resetDiff("test"); s.property.string().type.resetDiff(undefined); s.property.string().type.resetDiff(null); - expect(s.property.string().type.applyPatch("another", "test", false)).toBe("test"); - expect(s.property.string().type.applyPatch(undefined, "test", true)).toBe("test"); - expect(s.property.string().type.applyPatch(null, "test", false)).toBe("test"); - expect(s.property.string().type.applyPatch("test", undefined, false)).toBeUndefined(); + expect(s.property.string().type.applyPatch("another", "test", false)).toBe( + "test", + ); + expect(s.property.string().type.applyPatch(undefined, "test", true)).toBe( + "test", + ); + expect(s.property.string().type.applyPatch(null, "test", false)).toBe( + "test", + ); + expect( + s.property.string().type.applyPatch("test", undefined, false), + ).toBeUndefined(); expect(s.property.string().type.applyPatch("test", null, false)).toBeNull(); }); test("invalid parameters types", () => { const testDate = new Date(); - expect(s.property.string().type.serialize({} as any)).toBe("[object Object]"); + expect(s.property.string().type.serialize({} as any)).toBe( + "[object Object]", + ); expect(s.property.string().type.serialize(2120 as any)).toBe("2120"); - expect(s.property.string().type.serialize(testDate as any)).toBe(testDate.toString()); - expect(s.property.string().type.deserialize({} as any)).toBe("[object Object]"); + expect(s.property.string().type.serialize(testDate as any)).toBe( + testDate.toString(), + ); + expect(s.property.string().type.deserialize({} as any)).toBe( + "[object Object]", + ); expect(s.property.string().type.deserialize(2120 as any)).toBe("2120"); - expect(s.property.string().type.serializeDiff({} as any)).toBe("[object Object]"); + expect(s.property.string().type.serializeDiff({} as any)).toBe( + "[object Object]", + ); expect(s.property.string().type.serializeDiff(2120 as any)).toBe("2120"); - expect(s.property.string().type.hasChanged({} as any, {} as any)).toBeTruthy(); - expect(s.property.string().type.hasChanged(false as any, false as any)).toBeFalsy(); - expect(s.property.string().type.serializedHasChanged({} as any, {} as any)).toBeTruthy(); - expect(s.property.string().type.serializedHasChanged(false as any, false as any)).toBeFalsy(); + expect( + s.property.string().type.hasChanged({} as any, {} as any), + ).toBeTruthy(); + expect( + s.property.string().type.hasChanged(false as any, false as any), + ).toBeFalsy(); + expect( + s.property.string().type.serializedHasChanged({} as any, {} as any), + ).toBeTruthy(); + expect( + s.property.string().type.serializedHasChanged(false as any, false as any), + ).toBeFalsy(); expect(s.property.string().type.clone({} as any)).toStrictEqual({}); }); }); diff --git a/tsconfig.json b/tsconfig.json index 803756c..3d2ceea 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,30 +1,27 @@ { - "ts-node": { - "compilerOptions": { - "module": "ESNext", - "types": ["node"], - } - }, + "ts-node": { + "compilerOptions": { + "module": "ESNext", + "types": ["node"] + } + }, - "compilerOptions": { - "outDir": "./lib/", - "incremental": true, - "sourceMap": true, - "noImplicitAny": true, - "noImplicitThis": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "resolveJsonModule": true, - "experimentalDecorators": true, - "emitDecoratorMetadata": true, - "declaration": true, - "declarationMap": true, - "module": "ES6", - "target": "ES6", - "moduleResolution": "Bundler", - "lib": [ - "ESNext", - "DOM" - ] - } + "compilerOptions": { + "outDir": "./lib/", + "incremental": true, + "sourceMap": true, + "noImplicitAny": true, + "noImplicitThis": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "declaration": true, + "declarationMap": true, + "module": "ES6", + "target": "ES6", + "moduleResolution": "Bundler", + "lib": ["ESNext", "DOM"] + } } diff --git a/vite.config.ts b/vite.config.ts index 38bff29..21cdd47 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -3,8 +3,8 @@ import dts from "vite-plugin-dts"; // https://vitejs.dev/config/ -export default defineConfig(({ mode }: ConfigEnv): UserConfig => { - return ({ +export default defineConfig(({mode}: ConfigEnv): UserConfig => { + return { build: { outDir: "lib", sourcemap: true, @@ -22,6 +22,6 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => { rollupTypes: true, exclude: ["node_modules"], }), - ] - }); + ], + }; }); diff --git a/yarn.lock b/yarn.lock index 4029691..3e1de71 100644 --- a/yarn.lock +++ b/yarn.lock @@ -664,6 +664,7 @@ __metadata: dependencies: "@types/node": "npm:^22.13.14" "@vitest/coverage-v8": "npm:^3.0.9" + prettier: "npm:^3.6.0" ts-node: "npm:^10.9.2" typescript: "npm:^5.8.2" vite: "npm:^6.2.3" @@ -2379,6 +2380,15 @@ __metadata: languageName: node linkType: hard +"prettier@npm:^3.6.0": + version: 3.6.0 + resolution: "prettier@npm:3.6.0" + bin: + prettier: bin/prettier.cjs + checksum: 10c0/636897c8084b71ef1f740a46199df0d8f6ed896aa497212cc8cc229d3026b9dca82fa92f61e55924c4708cea11e39a88478e2d93c4818741c55b7408a9ac6d91 + languageName: node + linkType: hard + "promise-inflight@npm:^1.0.1": version: 1.0.1 resolution: "promise-inflight@npm:1.0.1"