Compare commits
No commits in common. "main" and "v1.0.1" have entirely different histories.
1
.gitignore
vendored
1
.gitignore
vendored
@ -12,6 +12,5 @@ lib/
|
|||||||
.yarnrc*
|
.yarnrc*
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
.pnp*
|
.pnp*
|
||||||
node_modules/
|
|
||||||
|
|
||||||
yarn.lock
|
yarn.lock
|
||||||
|
118
README.md
118
README.md
@ -4,22 +4,21 @@
|
|||||||
|
|
||||||
Sharkitek is a Javascript / TypeScript library designed to ease development of client-side models.
|
Sharkitek is a Javascript / TypeScript library designed to ease development of client-side models.
|
||||||
|
|
||||||
With Sharkitek, you define the architecture of your models by specifying their properties and their types.
|
With Sharkitek, you define the architecture of your models by applying decorators (which define their type) on your class properties.
|
||||||
Then, you can use the defined methods like `serialize`, `deserialize` or `serializeDiff`.
|
Then, you can use the defined methods like `serialize`, `deserialize` or `serializeDiff`.
|
||||||
|
|
||||||
```typescript
|
Sharkitek makes use of decorators as defined in the [TypeScript Reference](https://www.typescriptlang.org/docs/handbook/decorators.html).
|
||||||
class Example extends Model<Example>
|
Due to the way decorators work, you must always set a value to your properties when you declare them, even if this value is `undefined`.
|
||||||
{
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
protected SDefinition(): ModelDefinition<Example>
|
```typescript
|
||||||
{
|
class Example extends Model
|
||||||
return {
|
{
|
||||||
id: SDefine(SNumeric),
|
@Property(SNumeric)
|
||||||
name: SDefine(SString),
|
@Identifier
|
||||||
};
|
id: number = undefined;
|
||||||
}
|
|
||||||
|
@Property(SString)
|
||||||
|
name: string = undefined;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -31,60 +30,47 @@ class Example extends Model<Example>
|
|||||||
/**
|
/**
|
||||||
* A person.
|
* A person.
|
||||||
*/
|
*/
|
||||||
class Person extends Model<Person>
|
class Person extends Model
|
||||||
{
|
{
|
||||||
id: number;
|
@Property(SNumeric)
|
||||||
name: string;
|
@Identifier
|
||||||
firstName: string;
|
id: number = undefined;
|
||||||
email: string;
|
|
||||||
createdAt: Date;
|
|
||||||
active: boolean = true;
|
|
||||||
|
|
||||||
protected SIdentifier(): ModelIdentifier<Person>
|
@Property(SString)
|
||||||
{
|
name: string = undefined;
|
||||||
return "id";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected SDefinition(): ModelDefinition<Person>
|
@Property(SString)
|
||||||
{
|
firstName: string = undefined;
|
||||||
return {
|
|
||||||
name: SDefine(SString),
|
@Property(SString)
|
||||||
firstName: SDefine(SString),
|
email: string = undefined;
|
||||||
email: SDefine(SString),
|
|
||||||
createdAt: SDefine(SDate),
|
|
||||||
active: SDefine(SBool),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Important**: You _must_ set a value to all your defined properties. If there is no set value, the decorator will not
|
||||||
|
be applied instantly on object initialization and the deserialization will not work properly.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
/**
|
/**
|
||||||
* An article.
|
* An article.
|
||||||
*/
|
*/
|
||||||
class Article extends Model<Article>
|
class Article extends Model
|
||||||
{
|
{
|
||||||
id: number;
|
@Property(SNumeric)
|
||||||
title: string;
|
@Identifier
|
||||||
|
id: number = undefined;
|
||||||
|
|
||||||
|
@Property(SString)
|
||||||
|
title: string = undefined;
|
||||||
|
|
||||||
|
@Property(SArray(SModel(Author)))
|
||||||
authors: Author[] = [];
|
authors: Author[] = [];
|
||||||
text: string;
|
|
||||||
evaluation: number;
|
|
||||||
|
|
||||||
protected SIdentifier(): ModelIdentifier<Article>
|
@Property(SString)
|
||||||
{
|
text: string = undefined;
|
||||||
return "id";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected SDefinition(): ModelDefinition<Article>
|
@Property(SDecimal)
|
||||||
{
|
evaluation: number = undefined;
|
||||||
return {
|
|
||||||
id: SDefine(SNumeric),
|
|
||||||
title: SDefine(SString),
|
|
||||||
authors: SDefine(SArray(SModel(Author))),
|
|
||||||
text: SDefine(SString),
|
|
||||||
evaluation: SDefine(SDecimal),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -96,38 +82,28 @@ Types are defined by a class extending `Type`.
|
|||||||
|
|
||||||
Sharkitek defines some basic types by default, in these classes:
|
Sharkitek defines some basic types by default, in these classes:
|
||||||
|
|
||||||
- `BoolType`: boolean value in the model, boolean value in the serialized object.
|
|
||||||
- `StringType`: string in the model, string in the serialized object.
|
- `StringType`: string in the model, string in the serialized object.
|
||||||
- `NumericType`: number in the model, number in the serialized object.
|
- `NumericType`: number in the model, number in the serialized object.
|
||||||
- `DecimalType`: number in the model, formatted string in the serialized object.
|
- `DecimalType`: number in the model, formatted string in the serialized object.
|
||||||
- `DateType`: date in the model, ISO formatted date in the serialized object.
|
|
||||||
- `ArrayType`: array in the model, array in the serialized object.
|
- `ArrayType`: array in the model, array in the serialized object.
|
||||||
- `ModelType`: instance of a specific class in the model, object in the serialized object.
|
- `ModelType`: instance of a specific class in the model, object in the serialized object.
|
||||||
|
|
||||||
When you are defining a Sharkitek property, you must provide its type by instantiating one of these classes.
|
When you are defining a Sharkitek property, you must provide its type by instantiating one of these classes.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
class Example extends Model<Example>
|
class Example extends Model
|
||||||
{
|
{
|
||||||
foo: string;
|
@Property(new StringType())
|
||||||
|
foo: string = undefined;
|
||||||
protected SDefinition(): ModelDefinition<Example>
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
foo: new Definition(new StringType()),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
To ease the use of these classes and reduce read complexity, some constant variables and functions are defined in the library,
|
To ease the use of these classes and reduce read complexity, some constant variables and functions are defined in the library,
|
||||||
following a certain naming convention: "S{type_name}".
|
following a certain naming convention: "S{type_name}".
|
||||||
|
|
||||||
- `BoolType` => `SBool`
|
|
||||||
- `StringType` => `SString`
|
- `StringType` => `SString`
|
||||||
- `NumericType` => `SNumeric`
|
- `NumericType` => `SNumeric`
|
||||||
- `DecimalType` => `SDecimal`
|
- `DecimalType` => `SDecimal`
|
||||||
- `DateType` => `SDate`
|
|
||||||
- `ArrayType` => `SArray`
|
- `ArrayType` => `SArray`
|
||||||
- `ModelType` => `SModel`
|
- `ModelType` => `SModel`
|
||||||
|
|
||||||
@ -139,16 +115,10 @@ multiple functions or constants when predefined parameters. (For example, we cou
|
|||||||
be a variable similar to `SArray(SString)`.)
|
be a variable similar to `SArray(SString)`.)
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
class Example extends Model<Example>
|
class Example extends Model
|
||||||
{
|
{
|
||||||
|
@Property(SString)
|
||||||
foo: string = undefined;
|
foo: string = undefined;
|
||||||
|
|
||||||
protected SDefinition(): ModelDefinition<Example>
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
foo: SDefine(SString),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
|
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
|
||||||
|
module.exports = {
|
||||||
export default {
|
|
||||||
preset: "ts-jest",
|
preset: "ts-jest",
|
||||||
testEnvironment: "node",
|
testEnvironment: "node",
|
||||||
|
|
||||||
|
43
package.json
43
package.json
@ -1,42 +1,33 @@
|
|||||||
{
|
{
|
||||||
"name": "@sharkitek/core",
|
"name": "@sharkitek/core",
|
||||||
"version": "2.1.1",
|
"version": "1.0.1",
|
||||||
"description": "Sharkitek core models library.",
|
"description": "Sharkitek core models library.",
|
||||||
"keywords": [
|
|
||||||
"sharkitek",
|
|
||||||
"model",
|
|
||||||
"serialization",
|
|
||||||
"diff",
|
|
||||||
"dirty",
|
|
||||||
"deserialization",
|
|
||||||
"property"
|
|
||||||
],
|
|
||||||
"repository": "https://git.madeorsk.com/Sharkitek/core",
|
"repository": "https://git.madeorsk.com/Sharkitek/core",
|
||||||
"author": "Madeorsk <madeorsk@protonmail.com>",
|
"author": "Madeorsk <madeorsk@protonmail.com>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"publishConfig": {
|
"private": false,
|
||||||
"access": "public"
|
|
||||||
},
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc && vite build",
|
"build": "parcel build",
|
||||||
|
"dev": "parcel watch",
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"main": "lib/index.js",
|
||||||
"source": "src/index.ts",
|
"source": "src/index.ts",
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
"main": "lib/index.js",
|
|
||||||
"files": [
|
"files": [
|
||||||
"lib/**/*"
|
"lib/**/*"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"dependencies": {
|
||||||
"@types/jest": "^29.5.13",
|
"reflect-metadata": "^0.1.13"
|
||||||
"@types/node": "^22.7.4",
|
|
||||||
"jest": "^29.7.0",
|
|
||||||
"ts-jest": "^29.2.5",
|
|
||||||
"ts-node": "^10.9.2",
|
|
||||||
"typescript": "^5.6.2",
|
|
||||||
"vite": "^5.4.8",
|
|
||||||
"vite-plugin-dts": "^4.2.2"
|
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@4.5.0"
|
"devDependencies": {
|
||||||
|
"@parcel/packager-ts": "2.6.2",
|
||||||
|
"@parcel/transformer-typescript-types": "2.6.2",
|
||||||
|
"@types/jest": "^28.1.6",
|
||||||
|
"jest": "^28.1.3",
|
||||||
|
"parcel": "^2.6.2",
|
||||||
|
"ts-jest": "^28.0.7",
|
||||||
|
"typescript": "^4.7.4"
|
||||||
|
},
|
||||||
|
"packageManager": "yarn@3.2.2"
|
||||||
}
|
}
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
import {Type} from "./Types/Type";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Options of a definition.
|
|
||||||
*/
|
|
||||||
export interface DefinitionOptions<SerializedType, SharkitekType>
|
|
||||||
{ //TODO implement some options, like `mandatory`.
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Sharkitek model property definition.
|
|
||||||
*/
|
|
||||||
export class Definition<SerializedType, SharkitekType>
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Initialize a property definition with the given type and options.
|
|
||||||
* @param type - The model property type.
|
|
||||||
* @param options - Property definition options.
|
|
||||||
*/
|
|
||||||
constructor(
|
|
||||||
public type: Type<SerializedType, SharkitekType>,
|
|
||||||
public options: DefinitionOptions<SerializedType, SharkitekType> = {},
|
|
||||||
) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize a property definition with the given type and options.
|
|
||||||
* @param type - The model property type.
|
|
||||||
* @param options - Property definition options.
|
|
||||||
*/
|
|
||||||
export function SDefine<SerializedType, SharkitekType>(type: Type<SerializedType, SharkitekType>, options: DefinitionOptions<SerializedType, SharkitekType> = {}): Definition<SerializedType, SharkitekType>
|
|
||||||
{
|
|
||||||
return new Definition<SerializedType, SharkitekType>(type, options);
|
|
||||||
}
|
|
@ -1,50 +1,89 @@
|
|||||||
import {Definition} from "./Definition";
|
import {Type} from "./Types/Type";
|
||||||
|
import "reflect-metadata";
|
||||||
|
import {ConstructorOf} from "./Types/ModelType";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model properties definition type.
|
* Key of Sharkitek property metadata.
|
||||||
*/
|
*/
|
||||||
export type ModelDefinition<T> = Partial<Record<keyof T, Definition<unknown, unknown>>>;
|
const sharkitekMetadataKey = Symbol("sharkitek");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model identifier type.
|
* Key of Sharkitek model identifier.
|
||||||
*/
|
*/
|
||||||
export type ModelIdentifier<T> = keyof T;
|
const modelIdentifierMetadataKey = Symbol("modelIdentifier");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sharkitek property metadata interface.
|
||||||
|
*/
|
||||||
|
interface SharkitekMetadataInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Property type instance.
|
||||||
|
*/
|
||||||
|
type: Type<any, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class decorator for Sharkitek models.
|
||||||
|
*/
|
||||||
|
export function Sharkitek(constructor: Function)
|
||||||
|
{
|
||||||
|
/*return class extends (constructor as FunctionConstructor) {
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
};*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property decorator to define a Sharkitek model identifier.
|
||||||
|
*/
|
||||||
|
export function Identifier(obj: Model, propertyName: string): void
|
||||||
|
{
|
||||||
|
// Register the current property as identifier of the current model object.
|
||||||
|
Reflect.defineMetadata(modelIdentifierMetadataKey, propertyName, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property decorator for Sharkitek models properties.
|
||||||
|
* @param type - Type of the property.
|
||||||
|
*/
|
||||||
|
export function Property<SerializedType, SharkitekType>(type: Type<SerializedType, SharkitekType>): PropertyDecorator
|
||||||
|
{
|
||||||
|
// Return the decorator function.
|
||||||
|
return (obj: ConstructorOf<Model>, propertyName) => {
|
||||||
|
// Initializing property metadata.
|
||||||
|
const metadata: SharkitekMetadataInterface = {
|
||||||
|
type: type,
|
||||||
|
};
|
||||||
|
// Set property metadata.
|
||||||
|
Reflect.defineMetadata(sharkitekMetadataKey, metadata, obj, propertyName);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Sharkitek model.
|
* A Sharkitek model.
|
||||||
*/
|
*/
|
||||||
export abstract class Model<THIS>
|
export abstract class Model
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Model properties definition function.
|
* Get the Sharkitek model identifier.
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
protected abstract SDefinition(): ModelDefinition<THIS>;
|
private getModelIdentifier(): string
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the name of the model identifier property.
|
|
||||||
*/
|
|
||||||
protected SIdentifier(): ModelIdentifier<THIS>
|
|
||||||
{
|
{
|
||||||
return undefined;
|
return Reflect.getMetadata(modelIdentifierMetadataKey, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get given property definition.
|
* Get the Sharkitek metadata of the property.
|
||||||
* @protected
|
* @param propertyName - The name of the property for which to get metadata.
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
protected getPropertyDefinition(propertyName: string): Definition<unknown, unknown>
|
private getPropertyMetadata(propertyName: string): SharkitekMetadataInterface
|
||||||
{
|
{
|
||||||
return (this.SDefinition() as any)?.[propertyName];
|
return Reflect.getMetadata(sharkitekMetadataKey, this, propertyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the list of the model properties.
|
|
||||||
* @protected
|
|
||||||
*/
|
|
||||||
protected getProperties(): string[]
|
|
||||||
{
|
|
||||||
return Object.keys(this.SDefinition());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calling a function for a defined property.
|
* Calling a function for a defined property.
|
||||||
* @param propertyName - The property for which to check definition.
|
* @param propertyName - The property for which to check definition.
|
||||||
@ -52,15 +91,15 @@ export abstract class Model<THIS>
|
|||||||
* @param notProperty - The function called when the property is not defined.
|
* @param notProperty - The function called when the property is not defined.
|
||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
protected propertyWithDefinition(propertyName: string, callback: (propertyDefinition: Definition<unknown, unknown>) => void, notProperty: () => void = () => {}): unknown
|
protected propertyWithMetadata(propertyName: string, callback: (propertyMetadata: SharkitekMetadataInterface) => void, notProperty: () => void = () => {}): unknown
|
||||||
{
|
{
|
||||||
// Getting the current property definition.
|
// Getting the current property metadata.
|
||||||
const propertyDefinition = this.getPropertyDefinition(propertyName);
|
const propertyMetadata = this.getPropertyMetadata(propertyName);
|
||||||
if (propertyDefinition)
|
if (propertyMetadata)
|
||||||
// There is a definition for the current property, calling the right callback.
|
// Metadata are defined, calling the right callback.
|
||||||
return callback(propertyDefinition);
|
return callback(propertyMetadata);
|
||||||
else
|
else
|
||||||
// No definition for the given property, calling the right callback.
|
// Metadata are not defined, calling the right callback.
|
||||||
return notProperty();
|
return notProperty();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -68,16 +107,19 @@ export abstract class Model<THIS>
|
|||||||
* @param callback - The function to call.
|
* @param callback - The function to call.
|
||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
protected forEachModelProperty(callback: (propertyName: string, propertyDefinition: Definition<unknown, unknown>) => unknown): any|void
|
protected forEachModelProperty(callback: (propertyName: string, propertyMetadata: SharkitekMetadataInterface) => unknown): any|void
|
||||||
{
|
{
|
||||||
for (const propertyName of this.getProperties())
|
for (const propertyName of Object.keys(this))
|
||||||
{ // For each property, checking that its type is defined and calling the callback with its type.
|
{ // For each property, checking that its type is defined and calling the callback with its type.
|
||||||
const result = this.propertyWithDefinition(propertyName, (propertyDefinition) => {
|
const result = this.propertyWithMetadata(propertyName, (propertyMetadata) => {
|
||||||
// If the property is defined, calling the function with the property name and definition.
|
// If the property is defined, calling the function with the property name and metadata.
|
||||||
const result = callback(propertyName, propertyDefinition);
|
const result = callback(propertyName, propertyMetadata);
|
||||||
|
|
||||||
// If there is a return value, returning it directly (loop is broken).
|
// If there is a return value, returning it directly (loop is broken).
|
||||||
if (typeof result !== "undefined") return result;
|
if (typeof result !== "undefined") return result;
|
||||||
|
|
||||||
|
// Update metadata if they have changed.
|
||||||
|
Reflect.defineMetadata(sharkitekMetadataKey, propertyMetadata, this, propertyName);
|
||||||
});
|
});
|
||||||
|
|
||||||
// If there is a return value, returning it directly (loop is broken).
|
// If there is a return value, returning it directly (loop is broken).
|
||||||
@ -111,12 +153,12 @@ export abstract class Model<THIS>
|
|||||||
*/
|
*/
|
||||||
isDirty(): boolean
|
isDirty(): boolean
|
||||||
{
|
{
|
||||||
return this.forEachModelProperty((propertyName, propertyDefinition) => (
|
return this.forEachModelProperty((propertyName, propertyMetadata) => (
|
||||||
// For each property, checking if it is different.
|
// For each property, checking if it is different.
|
||||||
propertyDefinition.type.propertyHasChanged(this._originalProperties[propertyName], (this as any)[propertyName])
|
propertyMetadata.type.propertyHasChanged(this._originalProperties[propertyName], (this as any)[propertyName])
|
||||||
// There is a difference, we should return false.
|
// There is a difference, we should return false.
|
||||||
? true
|
? true
|
||||||
// There is no difference, returning nothing.
|
// There is not difference, returning nothing.
|
||||||
: undefined
|
: undefined
|
||||||
)) === true;
|
)) === true;
|
||||||
}
|
}
|
||||||
@ -126,7 +168,7 @@ export abstract class Model<THIS>
|
|||||||
*/
|
*/
|
||||||
getIdentifier(): unknown
|
getIdentifier(): unknown
|
||||||
{
|
{
|
||||||
return (this as any)[this.SIdentifier()];
|
return (this as any)[this.getModelIdentifier()];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -134,10 +176,10 @@ export abstract class Model<THIS>
|
|||||||
*/
|
*/
|
||||||
resetDiff()
|
resetDiff()
|
||||||
{
|
{
|
||||||
this.forEachModelProperty((propertyName, propertyDefinition) => {
|
this.forEachModelProperty((propertyName, propertyMetadata) => {
|
||||||
// For each property, set its original value to its current property value.
|
// For each property, set its original value to its current property value.
|
||||||
this._originalProperties[propertyName] = (this as any)[propertyName];
|
this._originalProperties[propertyName] = (this as any)[propertyName];
|
||||||
propertyDefinition.type.resetDiff((this as any)[propertyName]);
|
propertyMetadata.type.resetDiff((this as any)[propertyName]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -148,12 +190,12 @@ export abstract class Model<THIS>
|
|||||||
// Creating a serialized object.
|
// Creating a serialized object.
|
||||||
const serializedDiff: any = {};
|
const serializedDiff: any = {};
|
||||||
|
|
||||||
this.forEachModelProperty((propertyName, propertyDefinition) => {
|
this.forEachModelProperty((propertyName, propertyMetadata) => {
|
||||||
// For each defined model property, adding it to the serialized object if it has changed.
|
// For each defined model property, adding it to the serialized object if it has changed.
|
||||||
if (this.SIdentifier() == propertyName
|
if (this.getModelIdentifier() == propertyName
|
||||||
|| propertyDefinition.type.propertyHasChanged(this._originalProperties[propertyName], (this as any)[propertyName]))
|
|| propertyMetadata.type.propertyHasChanged(this._originalProperties[propertyName], (this as any)[propertyName]))
|
||||||
// Adding the current property to the serialized object if it is the identifier or its value has changed.
|
// Adding the current property to the serialized object if it is the identifier or its value has changed.
|
||||||
serializedDiff[propertyName] = propertyDefinition.type.serializeDiff((this as any)[propertyName]);
|
serializedDiff[propertyName] = propertyMetadata.type.serializeDiff((this as any)[propertyName]);
|
||||||
})
|
})
|
||||||
|
|
||||||
return serializedDiff; // Returning the serialized object.
|
return serializedDiff; // Returning the serialized object.
|
||||||
@ -182,9 +224,9 @@ export abstract class Model<THIS>
|
|||||||
// Creating a serialized object.
|
// Creating a serialized object.
|
||||||
const serializedObject: any = {};
|
const serializedObject: any = {};
|
||||||
|
|
||||||
this.forEachModelProperty((propertyName, propertyDefinition) => {
|
this.forEachModelProperty((propertyName, propertyMetadata) => {
|
||||||
// For each defined model property, adding it to the serialized object.
|
// For each defined model property, adding it to the serialized object.
|
||||||
serializedObject[propertyName] = propertyDefinition.type.serialize((this as any)[propertyName]);
|
serializedObject[propertyName] = propertyMetadata.type.serialize((this as any)[propertyName]);
|
||||||
});
|
});
|
||||||
|
|
||||||
return serializedObject; // Returning the serialized object.
|
return serializedObject; // Returning the serialized object.
|
||||||
@ -195,16 +237,16 @@ export abstract class Model<THIS>
|
|||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
protected parse(): void
|
protected parse(): void
|
||||||
{} // Nothing by default. TODO: create an event system to create functions like "beforeDeserialization" or "afterDeserialization".
|
{} // Nothing by default. TODO: create a event system to create functions like "beforeDeserialization" or "afterDeserialization".
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the model.
|
* Deserialize the model.
|
||||||
*/
|
*/
|
||||||
deserialize(serializedObject: any): THIS
|
deserialize(serializedObject: any): this
|
||||||
{
|
{
|
||||||
this.forEachModelProperty((propertyName, propertyDefinition) => {
|
this.forEachModelProperty((propertyName, propertyMetadata) => {
|
||||||
// For each defined model property, assigning its deserialized value to the model.
|
// For each defined model property, assigning its deserialized value to the model.
|
||||||
(this as any)[propertyName] = propertyDefinition.type.deserialize(serializedObject[propertyName]);
|
(this as any)[propertyName] = propertyMetadata.type.deserialize(serializedObject[propertyName]);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reset original property values.
|
// Reset original property values.
|
||||||
@ -212,6 +254,6 @@ export abstract class Model<THIS>
|
|||||||
|
|
||||||
this._originalObject = serializedObject; // The model is not a new one, but loaded from a deserialized one.
|
this._originalObject = serializedObject; // The model is not a new one, but loaded from a deserialized one.
|
||||||
|
|
||||||
return this as unknown as THIS; // Returning this, after deserialization.
|
return this; // Returning this, after deserialization.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import {Type} from "./Type";
|
|||||||
export class ArrayType<SerializedValueType, SharkitekValueType> extends Type<SerializedValueType[], SharkitekValueType[]>
|
export class ArrayType<SerializedValueType, SharkitekValueType> extends Type<SerializedValueType[], SharkitekValueType[]>
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Constructs a new array type of a Sharkitek model property.
|
* Constructs a new array type of Sharkitek model property.
|
||||||
* @param valueType - Type of the array values.
|
* @param valueType - Type of the array values.
|
||||||
*/
|
*/
|
||||||
constructor(protected valueType: Type<SerializedValueType, SharkitekValueType>)
|
constructor(protected valueType: Type<SerializedValueType, SharkitekValueType>)
|
||||||
@ -16,9 +16,6 @@ export class ArrayType<SerializedValueType, SharkitekValueType> extends Type<Ser
|
|||||||
|
|
||||||
serialize(value: SharkitekValueType[]): SerializedValueType[]
|
serialize(value: SharkitekValueType[]): SerializedValueType[]
|
||||||
{
|
{
|
||||||
if (value === undefined) return undefined;
|
|
||||||
if (value === null) return null;
|
|
||||||
|
|
||||||
return value.map((value) => (
|
return value.map((value) => (
|
||||||
// Serializing each value of the array.
|
// Serializing each value of the array.
|
||||||
this.valueType.serialize(value)
|
this.valueType.serialize(value)
|
||||||
@ -27,9 +24,6 @@ export class ArrayType<SerializedValueType, SharkitekValueType> extends Type<Ser
|
|||||||
|
|
||||||
deserialize(value: SerializedValueType[]): SharkitekValueType[]
|
deserialize(value: SerializedValueType[]): SharkitekValueType[]
|
||||||
{
|
{
|
||||||
if (value === undefined) return undefined;
|
|
||||||
if (value === null) return null;
|
|
||||||
|
|
||||||
return value.map((serializedValue) => (
|
return value.map((serializedValue) => (
|
||||||
// Deserializing each value of the array.
|
// Deserializing each value of the array.
|
||||||
this.valueType.deserialize(serializedValue)
|
this.valueType.deserialize(serializedValue)
|
||||||
@ -38,18 +32,12 @@ export class ArrayType<SerializedValueType, SharkitekValueType> extends Type<Ser
|
|||||||
|
|
||||||
serializeDiff(value: SharkitekValueType[]): any
|
serializeDiff(value: SharkitekValueType[]): any
|
||||||
{
|
{
|
||||||
if (value === undefined) return undefined;
|
|
||||||
if (value === null) return null;
|
|
||||||
|
|
||||||
// Serializing diff of all elements.
|
// Serializing diff of all elements.
|
||||||
return value.map((value) => this.valueType.serializeDiff(value));
|
return value.map((value) => this.valueType.serializeDiff(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
resetDiff(value: SharkitekValueType[]): void
|
resetDiff(value: SharkitekValueType[]): void
|
||||||
{
|
{
|
||||||
// Do nothing if it is not an array.
|
|
||||||
if (!Array.isArray(value)) return;
|
|
||||||
|
|
||||||
// Reset diff of all elements.
|
// Reset diff of all elements.
|
||||||
value.forEach((value) => this.valueType.resetDiff(value));
|
value.forEach((value) => this.valueType.resetDiff(value));
|
||||||
}
|
}
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
import {Type} from "./Type";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Type of any boolean value.
|
|
||||||
*/
|
|
||||||
export class BoolType extends Type<boolean, boolean>
|
|
||||||
{
|
|
||||||
deserialize(value: boolean): boolean
|
|
||||||
{
|
|
||||||
return !!value; // ensure bool type.
|
|
||||||
}
|
|
||||||
|
|
||||||
serialize(value: boolean): boolean
|
|
||||||
{
|
|
||||||
return !!value; // ensure bool type.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Type of any boolean value.
|
|
||||||
*/
|
|
||||||
export const SBool = new BoolType();
|
|
@ -1,22 +0,0 @@
|
|||||||
import {Type} from "./Type";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Type of dates.
|
|
||||||
*/
|
|
||||||
export class DateType extends Type<string, Date>
|
|
||||||
{
|
|
||||||
deserialize(value: string): Date
|
|
||||||
{
|
|
||||||
return new Date(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
serialize(value: Date): string
|
|
||||||
{
|
|
||||||
return value.toISOString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Type of dates.
|
|
||||||
*/
|
|
||||||
export const SDate = new DateType();
|
|
@ -17,6 +17,6 @@ export class DecimalType extends Type<string, number>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type of decimal numbers.
|
* Type of decimal numbers;
|
||||||
*/
|
*/
|
||||||
export const SDecimal = new DecimalType();
|
export const SDecimal = new DecimalType();
|
||||||
|
@ -9,7 +9,7 @@ export type ConstructorOf<T> = { new(): T; }
|
|||||||
/**
|
/**
|
||||||
* Type of a Sharkitek model value.
|
* Type of a Sharkitek model value.
|
||||||
*/
|
*/
|
||||||
export class ModelType<M extends Model<M>> extends Type<any, M>
|
export class ModelType<M extends Model> extends Type<any, M>
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Constructs a new model type of a Sharkitek model property.
|
* Constructs a new model type of a Sharkitek model property.
|
||||||
@ -20,28 +20,28 @@ export class ModelType<M extends Model<M>> extends Type<any, M>
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize(value: M|null): any
|
serialize(value: M): any
|
||||||
{
|
{
|
||||||
// Serializing the given model.
|
// Serializing the given model.
|
||||||
return value ? value.serialize() : null;
|
return value.serialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
deserialize(value: any): M|null
|
deserialize(value: any): M
|
||||||
{
|
{
|
||||||
// Deserializing the given object in the new model.
|
// Deserializing the given object in the new model.
|
||||||
return value ? (new this.modelConstructor()).deserialize(value) : null;
|
return (new this.modelConstructor()).deserialize(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
serializeDiff(value: M): any
|
serializeDiff(value: M): any
|
||||||
{
|
{
|
||||||
// Serializing the given model.
|
// Serializing the given model.
|
||||||
return value ? value.serializeDiff() : null;
|
return value.serializeDiff();
|
||||||
}
|
}
|
||||||
|
|
||||||
resetDiff(value: M): void
|
resetDiff(value: M): void
|
||||||
{
|
{
|
||||||
// Reset diff of the given model.
|
// Reset diff of the given model.
|
||||||
value?.resetDiff();
|
value.resetDiff();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ export class ModelType<M extends Model<M>> extends Type<any, M>
|
|||||||
* Type of a Sharkitek model value.
|
* Type of a Sharkitek model value.
|
||||||
* @param modelConstructor - Constructor of the model.
|
* @param modelConstructor - Constructor of the model.
|
||||||
*/
|
*/
|
||||||
export function SModel<M extends Model<M>>(modelConstructor: ConstructorOf<M>)
|
export function SModel<M extends Model>(modelConstructor: ConstructorOf<M>)
|
||||||
{
|
{
|
||||||
return new ModelType(modelConstructor);
|
return new ModelType(modelConstructor);
|
||||||
}
|
}
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
import {Type} from "./Type";
|
|
||||||
import {Definition} from "../Definition";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Type of a simple object.
|
|
||||||
*/
|
|
||||||
export class ObjectType<Keys extends symbol|string> extends Type<Record<Keys, any>, Record<Keys, any>>
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Constructs a new object type of a Sharkitek model property.
|
|
||||||
* @param fieldsTypes Object fields types.
|
|
||||||
*/
|
|
||||||
constructor(protected fieldsTypes: Record<Keys, Definition<unknown, unknown>>)
|
|
||||||
{
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
deserialize(value: Record<Keys, any>): Record<Keys, any>
|
|
||||||
{
|
|
||||||
if (value === undefined) return undefined;
|
|
||||||
if (value === null) return null;
|
|
||||||
|
|
||||||
return Object.fromEntries(
|
|
||||||
// For each defined field, deserialize its value according to its type.
|
|
||||||
(Object.entries(this.fieldsTypes) as [Keys, Definition<any, any>][]).map(([fieldName, fieldDefinition]) => (
|
|
||||||
// Return an entry with the current field name and the deserialized value.
|
|
||||||
[fieldName, fieldDefinition.type.deserialize(value?.[fieldName])]
|
|
||||||
))
|
|
||||||
) as Record<Keys, any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
serialize(value: Record<Keys, any>): Record<Keys, any>
|
|
||||||
{
|
|
||||||
if (value === undefined) return undefined;
|
|
||||||
if (value === null) return null;
|
|
||||||
|
|
||||||
return Object.fromEntries(
|
|
||||||
// For each defined field, serialize its value according to its type.
|
|
||||||
(Object.entries(this.fieldsTypes) as [Keys, Definition<any, any>][]).map(([fieldName, fieldDefinition]) => (
|
|
||||||
// Return an entry with the current field name and the serialized value.
|
|
||||||
[fieldName, fieldDefinition.type.serialize(value?.[fieldName])]
|
|
||||||
))
|
|
||||||
) as Record<Keys, any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
serializeDiff(value: Record<Keys, any>): Record<Keys, any>
|
|
||||||
{
|
|
||||||
if (value === undefined) return undefined;
|
|
||||||
if (value === null) return null;
|
|
||||||
|
|
||||||
return Object.fromEntries(
|
|
||||||
// For each defined field, serialize its diff value according to its type.
|
|
||||||
(Object.entries(this.fieldsTypes) as [Keys, Definition<any, any>][]).map(([fieldName, fieldDefinition]) => (
|
|
||||||
// Return an entry with the current field name and the serialized diff value.
|
|
||||||
[fieldName, fieldDefinition.type.serializeDiff(value?.[fieldName])]
|
|
||||||
))
|
|
||||||
) as Record<Keys, any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
resetDiff(value: Record<Keys, any>): void
|
|
||||||
{
|
|
||||||
// For each field, reset its diff.
|
|
||||||
(Object.entries(this.fieldsTypes) as [Keys, Definition<any, any>][]).forEach(([fieldName, fieldDefinition]) => {
|
|
||||||
// Reset diff of the current field.
|
|
||||||
fieldDefinition.type.resetDiff(value?.[fieldName]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Type of a simple object.
|
|
||||||
* @param fieldsTypes Object fields types.
|
|
||||||
*/
|
|
||||||
export function SObject<Keys extends symbol|string>(fieldsTypes: Record<Keys, Definition<unknown, unknown>>): ObjectType<Keys>
|
|
||||||
{
|
|
||||||
return new ObjectType<Keys>(fieldsTypes);
|
|
||||||
}
|
|
@ -1,14 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
export * from "./Model/Model";
|
export * from "./Model/Model";
|
||||||
|
|
||||||
export * from "./Model/Definition";
|
|
||||||
|
|
||||||
export * from "./Model/Types/Type";
|
export * from "./Model/Types/Type";
|
||||||
export * from "./Model/Types/ArrayType";
|
export * from "./Model/Types/ArrayType";
|
||||||
export * from "./Model/Types/BoolType";
|
|
||||||
export * from "./Model/Types/DateType";
|
|
||||||
export * from "./Model/Types/DecimalType";
|
export * from "./Model/Types/DecimalType";
|
||||||
export * from "./Model/Types/ModelType";
|
export * from "./Model/Types/ModelType";
|
||||||
export * from "./Model/Types/NumericType";
|
export * from "./Model/Types/NumericType";
|
||||||
export * from "./Model/Types/ObjectType";
|
|
||||||
export * from "./Model/Types/StringType";
|
export * from "./Model/Types/StringType";
|
||||||
|
@ -1,84 +1,49 @@
|
|||||||
import {
|
import {SArray, SDecimal, SModel, SNumeric, SString, Identifier, Model, Property} from "../src";
|
||||||
SArray,
|
|
||||||
SDecimal,
|
|
||||||
SModel,
|
|
||||||
SNumeric,
|
|
||||||
SString,
|
|
||||||
SDate,
|
|
||||||
SBool,
|
|
||||||
Model,
|
|
||||||
ModelDefinition,
|
|
||||||
SDefine, ModelIdentifier
|
|
||||||
} from "../src";
|
|
||||||
import {SObject} from "../src/Model/Types/ObjectType";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Another test model.
|
* Another test model.
|
||||||
*/
|
*/
|
||||||
class Author extends Model<Author>
|
class Author extends Model
|
||||||
{
|
{
|
||||||
name: string;
|
@Property(SString)
|
||||||
firstName: string;
|
name: string = undefined;
|
||||||
email: string;
|
|
||||||
createdAt: Date;
|
|
||||||
active: boolean = true;
|
|
||||||
|
|
||||||
protected SDefinition(): ModelDefinition<Author>
|
@Property(SString)
|
||||||
{
|
firstName: string = undefined;
|
||||||
return {
|
|
||||||
name: SDefine(SString),
|
|
||||||
firstName: SDefine(SString),
|
|
||||||
email: SDefine(SString),
|
|
||||||
createdAt: SDefine(SDate),
|
|
||||||
active: SDefine(SBool),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(name: string = "", firstName: string = "", email: string = "", createdAt: Date = new Date())
|
@Property(SString)
|
||||||
|
email: string = undefined;
|
||||||
|
|
||||||
|
constructor(name: string = undefined, firstName: string = undefined, email: string = undefined)
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.firstName = firstName;
|
this.firstName = firstName;
|
||||||
this.email = email;
|
this.email = email;
|
||||||
this.createdAt = createdAt;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A test model.
|
* A test model.
|
||||||
*/
|
*/
|
||||||
class Article extends Model<Article>
|
class Article extends Model
|
||||||
{
|
{
|
||||||
id: number;
|
@Property(SNumeric)
|
||||||
title: string;
|
@Identifier
|
||||||
|
id: number = undefined;
|
||||||
|
|
||||||
|
@Property(SString)
|
||||||
|
title: string = undefined;
|
||||||
|
|
||||||
|
@Property(SArray(SModel(Author)))
|
||||||
authors: Author[] = [];
|
authors: Author[] = [];
|
||||||
text: string;
|
|
||||||
evaluation: number;
|
|
||||||
tags: {
|
|
||||||
name: string;
|
|
||||||
}[];
|
|
||||||
|
|
||||||
protected SIdentifier(): ModelIdentifier<Article>
|
@Property(SString)
|
||||||
{
|
text: string = undefined;
|
||||||
return "id";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected SDefinition(): ModelDefinition<Article>
|
@Property(SDecimal)
|
||||||
{
|
evaluation: number = undefined;
|
||||||
return {
|
|
||||||
id: SDefine(SNumeric),
|
|
||||||
title: SDefine(SString),
|
|
||||||
authors: SDefine(SArray(SModel(Author))),
|
|
||||||
text: SDefine(SString),
|
|
||||||
evaluation: SDefine(SDecimal),
|
|
||||||
tags: SDefine(SArray(
|
|
||||||
SObject({
|
|
||||||
name: SDefine(SString),
|
|
||||||
})
|
|
||||||
)),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
it("deserialize", () => {
|
it("deserialize", () => {
|
||||||
@ -86,38 +51,32 @@ it("deserialize", () => {
|
|||||||
id: 1,
|
id: 1,
|
||||||
title: "this is a test",
|
title: "this is a test",
|
||||||
authors: [
|
authors: [
|
||||||
{ name: "DOE", firstName: "John", email: "test@test.test", createdAt: "2022-08-07T08:47:01.000Z", active: true, },
|
{ name: "DOE", firstName: "John", email: "test@test.test" },
|
||||||
{ name: "TEST", firstName: "Another", email: "another@test.test", createdAt: "2022-09-07T18:32:55.000Z", active: false, },
|
{ name: "TEST", firstName: "Another", email: "another@test.test" },
|
||||||
],
|
],
|
||||||
text: "this is a long test.",
|
text: "this is a long test.",
|
||||||
evaluation: "25.23",
|
evaluation: "25.23",
|
||||||
tags: [ {name: "test"}, {name: "foo"} ],
|
|
||||||
}).serialize()).toStrictEqual({
|
}).serialize()).toStrictEqual({
|
||||||
id: 1,
|
id: 1,
|
||||||
title: "this is a test",
|
title: "this is a test",
|
||||||
authors: [
|
authors: [
|
||||||
{ name: "DOE", firstName: "John", email: "test@test.test", createdAt: "2022-08-07T08:47:01.000Z", active: true, },
|
{ name: "DOE", firstName: "John", email: "test@test.test" },
|
||||||
{ name: "TEST", firstName: "Another", email: "another@test.test", createdAt: "2022-09-07T18:32:55.000Z", active: false, },
|
{ name: "TEST", firstName: "Another", email: "another@test.test" },
|
||||||
],
|
],
|
||||||
text: "this is a long test.",
|
text: "this is a long test.",
|
||||||
evaluation: "25.23",
|
evaluation: "25.23",
|
||||||
tags: [ {name: "test"}, {name: "foo"} ],
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("create and check state then serialize", () => {
|
it("create and check state then serialize", () => {
|
||||||
const now = new Date();
|
|
||||||
const article = new Article();
|
const article = new Article();
|
||||||
article.id = 1;
|
article.id = 1;
|
||||||
article.title = "this is a test";
|
article.title = "this is a test";
|
||||||
article.authors = [
|
article.authors = [
|
||||||
new Author("DOE", "John", "test@test.test", now),
|
new Author("DOE", "John", "test@test.test"),
|
||||||
];
|
];
|
||||||
article.text = "this is a long test.";
|
article.text = "this is a long test.";
|
||||||
article.evaluation = 25.23;
|
article.evaluation = 25.23;
|
||||||
article.tags = [];
|
|
||||||
article.tags.push({name: "test"});
|
|
||||||
article.tags.push({name: "foo"});
|
|
||||||
|
|
||||||
expect(article.isNew()).toBeTruthy();
|
expect(article.isNew()).toBeTruthy();
|
||||||
expect(article.getIdentifier()).toStrictEqual(1);
|
expect(article.getIdentifier()).toStrictEqual(1);
|
||||||
@ -126,11 +85,10 @@ it("create and check state then serialize", () => {
|
|||||||
id: 1,
|
id: 1,
|
||||||
title: "this is a test",
|
title: "this is a test",
|
||||||
authors: [
|
authors: [
|
||||||
{ name: "DOE", firstName: "John", email: "test@test.test", createdAt: now.toISOString(), active: true, },
|
{ name: "DOE", firstName: "John", email: "test@test.test" },
|
||||||
],
|
],
|
||||||
text: "this is a long test.",
|
text: "this is a long test.",
|
||||||
evaluation: "25.23",
|
evaluation: "25.23",
|
||||||
tags: [ {name: "test"}, {name: "foo"} ],
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -140,12 +98,11 @@ it("deserialize then save", () => {
|
|||||||
id: 1,
|
id: 1,
|
||||||
title: "this is a test",
|
title: "this is a test",
|
||||||
authors: [
|
authors: [
|
||||||
{ name: "DOE", firstName: "John", email: "test@test.test", createdAt: new Date(), active: true, },
|
{ name: "DOE", firstName: "John", email: "test@test.test" },
|
||||||
{ name: "TEST", firstName: "Another", email: "another@test.test", createdAt: new Date(), active: false, },
|
{ name: "TEST", firstName: "Another", email: "another@test.test" },
|
||||||
],
|
],
|
||||||
text: "this is a long test.",
|
text: "this is a long test.",
|
||||||
evaluation: "25.23",
|
evaluation: "25.23",
|
||||||
tags: [ {name: "test"}, {name: "foo"} ],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(article.isNew()).toBeFalsy();
|
expect(article.isNew()).toBeFalsy();
|
||||||
@ -167,12 +124,11 @@ it("save with modified submodels", () => {
|
|||||||
id: 1,
|
id: 1,
|
||||||
title: "this is a test",
|
title: "this is a test",
|
||||||
authors: [
|
authors: [
|
||||||
{ name: "DOE", firstName: "John", email: "test@test.test", createdAt: new Date(), active: true, },
|
{ name: "DOE", firstName: "John", email: "test@test.test" },
|
||||||
{ name: "TEST", firstName: "Another", email: "another@test.test", createdAt: new Date(), active: false, },
|
{ name: "TEST", firstName: "Another", email: "another@test.test" },
|
||||||
],
|
],
|
||||||
text: "this is a long test.",
|
text: "this is a long test.",
|
||||||
evaluation: "25.23",
|
evaluation: "25.23",
|
||||||
tags: [ {name: "test"}, {name: "foo"} ],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
article.authors = article.authors.map((author) => {
|
article.authors = article.authors.map((author) => {
|
||||||
|
@ -1,29 +1,21 @@
|
|||||||
{
|
{
|
||||||
"ts-node": {
|
"files": ["src/index.ts"],
|
||||||
"compilerOptions": {
|
|
||||||
"module": "ESNext",
|
|
||||||
"types": ["node"],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "./lib/",
|
"outDir": "./lib/",
|
||||||
"incremental": true,
|
|
||||||
"sourceMap": true,
|
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"esModuleInterop": true,
|
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"resolveJsonModule": true,
|
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"declarationMap": true,
|
"declarationMap": true,
|
||||||
|
"sourceMap": true,
|
||||||
"module": "ES6",
|
"module": "ES6",
|
||||||
"target": "ES6",
|
"moduleResolution": "Node",
|
||||||
"moduleResolution": "Bundler",
|
"target": "ES5",
|
||||||
|
|
||||||
"lib": [
|
"lib": [
|
||||||
"ESNext",
|
"ESNext",
|
||||||
"DOM"
|
"DOM"
|
||||||
],
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
import {ConfigEnv, defineConfig, UserConfig} from "vite";
|
|
||||||
import dts from "vite-plugin-dts";
|
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
|
||||||
|
|
||||||
export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
|
||||||
return ({
|
|
||||||
build: {
|
|
||||||
outDir: "lib",
|
|
||||||
sourcemap: true,
|
|
||||||
minify: "esbuild",
|
|
||||||
lib: {
|
|
||||||
entry: "src/index.ts",
|
|
||||||
formats: ["es"],
|
|
||||||
fileName: "index",
|
|
||||||
},
|
|
||||||
rollupOptions: {
|
|
||||||
external: ["reflect-metadata"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
plugins: [
|
|
||||||
dts({
|
|
||||||
insertTypesEntry: true,
|
|
||||||
rollupTypes: true,
|
|
||||||
exclude: ["node_modules"],
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
});
|
|
||||||
});
|
|
Loading…
Reference in New Issue
Block a user