diff --git a/package-lock.json b/package-lock.json index eb8691e..ea78af0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "@regulaforensics/document-reader-recipes", - "version": "0.0.9", + "version": "0.0.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@regulaforensics/document-reader-recipes", - "version": "0.0.9", + "version": "0.0.11", "license": "MIT", "dependencies": { - "@regulaforensics/document-reader-typings": "^0.0.5", + "@regulaforensics/document-reader-typings": "^0.0.7", "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "reflect-metadata": "^0.2.1", @@ -17,7 +17,7 @@ }, "devDependencies": { "@types/jest": "^29.5.11", - "@types/node": "^20.11.6", + "@types/node": "^20.11.7", "jest": "^29.7.0", "ts-jest": "^29.1.2", "typescript": "^5.3.3", @@ -1478,12 +1478,12 @@ } }, "node_modules/@regulaforensics/document-reader-typings": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/@regulaforensics/document-reader-typings/-/document-reader-typings-0.0.5.tgz", - "integrity": "sha512-BjghYb8X1/M/ayGU8tQ+jLYcp+da3fG/QkG9agvgBrUmmQPRuvQCtnEmnTMlzBmI3pOxCc89sWKQkKI+VUijHQ==", + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@regulaforensics/document-reader-typings/-/document-reader-typings-0.0.7.tgz", + "integrity": "sha512-9Wy9X+VDtUL6EFzkspUcthJm8RyN2nq5oQvu6KgwqPK4K894BM2nSPKeclU+Rv6AqacQZcsDATWRKekNC1J1ew==", "dependencies": { "class-transformer": "^0.5.1", - "class-validator": "^0.14.0", + "class-validator": "^0.14.1", "reflect-metadata": "^0.2.1" } }, @@ -1877,9 +1877,9 @@ } }, "node_modules/@types/node": { - "version": "20.11.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.6.tgz", - "integrity": "sha512-+EOokTnksGVgip2PbYbr3xnR7kZigh4LbybAfBAw5BpnQ+FqBYUsvCEjYd70IXKlbohQ64mzEYmMtlWUY8q//Q==", + "version": "20.11.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.7.tgz", + "integrity": "sha512-GPmeN1C3XAyV5uybAf4cMLWT9fDWcmQhZVtMFu7OR32WjrqGG+Wnk2V1d0bmtUyE/Zy1QJ9BxyiTih9z8Oks8A==", "dev": true, "dependencies": { "undici-types": "~5.26.4" diff --git a/package.json b/package.json index 874ab68..afbd4ef 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "0.0.9", + "version": "0.0.11", "author": "Regula Forensics, Inc.", "name": "@regulaforensics/document-reader-recipes", "description": "Document Reader Recipes", @@ -13,11 +13,11 @@ "class-validator": "^0.14.1", "reflect-metadata": "^0.2.1", "thenby": "^1.3.4", - "@regulaforensics/document-reader-typings": "^0.0.5" + "@regulaforensics/document-reader-typings": "^0.0.7" }, "devDependencies": { "@types/jest": "^29.5.11", - "@types/node": "^20.11.6", + "@types/node": "^20.11.7", "jest": "^29.7.0", "ts-jest": "^29.1.2", "typescript": "^5.3.3", diff --git a/src/decorators/default.decorator.ts b/src/decorators/default.decorator.ts new file mode 100644 index 0000000..0698585 --- /dev/null +++ b/src/decorators/default.decorator.ts @@ -0,0 +1,24 @@ +import { Transform, TransformFnParams } from 'class-transformer' + + +export function Default(defaultValue: any) { + return Transform(({ value }: TransformFnParams) => { + if (value !== null && value !== undefined) { + return value + } + + if (typeof defaultValue === 'function') { + return defaultValue() + } + + if (Array.isArray(defaultValue)) { + return [...defaultValue] + } + + if (typeof defaultValue === 'object') { + return (defaultValue === null) ? null : { ...defaultValue } + } + + return defaultValue + }) +} diff --git a/src/decorators/index.ts b/src/decorators/index.ts new file mode 100644 index 0000000..ccbce37 --- /dev/null +++ b/src/decorators/index.ts @@ -0,0 +1 @@ +export * from './default.decorator' diff --git a/src/recipes/barcode/document-barcodes/get-document-barcodes.recipe.test.ts b/src/recipes/barcode/document-barcodes/get-document-barcodes.recipe.test.ts index a7ecae9..934fae7 100644 --- a/src/recipes/barcode/document-barcodes/get-document-barcodes.recipe.test.ts +++ b/src/recipes/barcode/document-barcodes/get-document-barcodes.recipe.test.ts @@ -1,15 +1,20 @@ import { ProcessResponse } from '@regulaforensics/document-reader-typings' import rawDocReaderResponse from '@/test-data/7.json' +import { RDocumentBarcode } from './models' import { getDocumentBarcodes } from './get-document-barcodes.recipe' describe('getDocumentBarcodes', () => { const docReaderResponse = ProcessResponse.fromPlain(rawDocReaderResponse) + const result = getDocumentBarcodes(docReaderResponse) + const isValid = RDocumentBarcode.isAllValid(result) test('should return non-empty array of images', () => { - const result = getDocumentBarcodes(docReaderResponse) - expect(result.length).toBeGreaterThan(0) }) + + test('should return valid array of images', () => { + expect(isValid).toBe(true) + }) }) diff --git a/src/recipes/barcode/document-barcodes/get-document-barcodes.recipe.ts b/src/recipes/barcode/document-barcodes/get-document-barcodes.recipe.ts index f3536a3..d7c43d3 100644 --- a/src/recipes/barcode/document-barcodes/get-document-barcodes.recipe.ts +++ b/src/recipes/barcode/document-barcodes/get-document-barcodes.recipe.ts @@ -8,6 +8,11 @@ import { import { RDocumentBarcode, RDocumentBarcodeField, RDocumentBarcodeModuleData } from './models' +/** +* Get information about barcodes from the document +* @param {ProcessResponse} input - ProcessResponse from DocReader +* @returns {RDocumentBarcode[]} - array of RDocumentBarcode +*/ export const getDocumentBarcodes = (input: ProcessResponse): RDocumentBarcode[] => { const result: RDocumentBarcode[] = [] diff --git a/src/recipes/barcode/document-barcodes/models/document-barcode-field.model.ts b/src/recipes/barcode/document-barcodes/models/document-barcode-field.model.ts index 6146af2..5257233 100644 --- a/src/recipes/barcode/document-barcodes/models/document-barcode-field.model.ts +++ b/src/recipes/barcode/document-barcodes/models/document-barcode-field.model.ts @@ -5,26 +5,67 @@ import { eBarCodeType, eBarCodeResultCodes } from '@regulaforensics/document-rea import { iRDocumentBarcodeModuleData, RDocumentBarcodeModuleData } from './document-barcode-module-data.model' +/** +* Used for storing document barcode field. +*/ export interface iRDocumentBarcodeField { + /** + * Field index + * @type {number} + */ fieldIndex: number + + /** + * Barcode type + * @type {eBarCodeType} + */ type: eBarCodeType + + /** + * Barcode reading result code + * @type {eBarCodeResultCodes} + */ resultCode: eBarCodeResultCodes + + /** + * Array of barcode modules data + * @type {iRDocumentBarcodeModuleData[]} + */ modulesData: iRDocumentBarcodeModuleData[] } +/** +* Used for storing document barcode field. +*/ export class RDocumentBarcodeField implements iRDocumentBarcodeField { + /** + * Field index + * @type {number} + */ @IsDefined() @IsNumber() fieldIndex: number + /** + * Barcode type + * @type {eBarCodeType} + */ @IsDefined() @IsEnum(eBarCodeType) type: eBarCodeType + /** + * Barcode reading result code + * @type {eBarCodeResultCodes} + */ @IsDefined() @IsEnum(eBarCodeResultCodes) resultCode: eBarCodeResultCodes + /** + * Array of barcode modules data + * @type {RDocumentBarcodeModuleData[]} + */ @IsDefined() @Type(() => RDocumentBarcodeModuleData) @ValidateNested({ each: true }) diff --git a/src/recipes/barcode/document-barcodes/models/document-barcode-module-data.model.ts b/src/recipes/barcode/document-barcodes/models/document-barcode-module-data.model.ts index e152096..6e15819 100644 --- a/src/recipes/barcode/document-barcodes/models/document-barcode-module-data.model.ts +++ b/src/recipes/barcode/document-barcodes/models/document-barcode-module-data.model.ts @@ -2,21 +2,53 @@ import { IsDefined, IsEnum, IsNumber, IsString } from 'class-validator' import { eBarCodeModuleType } from '@regulaforensics/document-reader-typings' +/** +* Used for storing document barcode module data. +*/ export interface iRDocumentBarcodeModuleData { + /** + * Number of significant elements of data + * @type {number} + */ length: number + + /** + * Module type + * @type {eBarCodeModuleType} + */ type: eBarCodeModuleType + + /** + * Read module data + * @type {string} + */ data: string } +/** +* Used for storing document barcode module data. +*/ export class RDocumentBarcodeModuleData implements iRDocumentBarcodeModuleData { + /** + * Number of significant elements of data + * @type {number} + */ @IsDefined() @IsNumber() length: number + /** + * Module type + * @type {eBarCodeModuleType} + */ @IsDefined() @IsEnum(eBarCodeModuleType) type: eBarCodeModuleType + /** + * Read module data + * @type {string} + */ @IsDefined() @IsString() data: string diff --git a/src/recipes/barcode/document-barcodes/models/document-barcode.model.ts b/src/recipes/barcode/document-barcodes/models/document-barcode.model.ts index bd54331..d8531bd 100644 --- a/src/recipes/barcode/document-barcodes/models/document-barcode.model.ts +++ b/src/recipes/barcode/document-barcodes/models/document-barcode.model.ts @@ -1,24 +1,75 @@ -import { IsDefined, IsNumber, ValidateNested } from 'class-validator' +import { IsDefined, IsNumber, ValidateNested, validateSync } from 'class-validator' import { plainToClass, Type } from 'class-transformer' import { AllowPrimitives } from '@/types' import { iRDocumentBarcodeField, RDocumentBarcodeField } from './document-barcode-field.model' +/** +* Used for storing document barcode. +*/ export interface iRDocumentBarcode { + /** + * Page index of the document where the barcode was found + * @type {number} + */ pageIndex: number + + /** + * Array of barcode fields + * @type {iRDocumentBarcodeField[]} + */ fields: iRDocumentBarcodeField[] } +/** +* Used for storing document barcode. +*/ export class RDocumentBarcode implements iRDocumentBarcode { + /** + * Page index of the document where the barcode was found + * @type {number} + */ @IsDefined() @IsNumber() pageIndex: number + /** + * Array of barcode fields + * @type {RDocumentBarcodeField[]} + */ @IsDefined() @Type(() => RDocumentBarcodeField) @ValidateNested({ each: true }) fields: RDocumentBarcodeField[] + /** + * Creates an instance of RDocumentBarcode. + * @param {AllowPrimitives} input - plain object + * @returns {RDocumentBarcode} + */ static fromPlain = (input: AllowPrimitives): RDocumentBarcode => plainToClass(RDocumentBarcode, input) + + /** + * Validates input data + * @param {RDocumentBarcode} input - input data + * @returns {boolean} - true if input data is valid + */ + static isValid = (input: RDocumentBarcode): boolean => { + const errors = validateSync(input) + + if (errors.length) { + console.error('RDocumentBarcode validation errors:', errors) + return false + } + + return true + } + + /** + * Validates array of RDocumentBarcode + * @param {RDocumentBarcode[]} input - input data + * @returns {boolean} - true if input data is valid + */ + static isAllValid = (input: RDocumentBarcode[]): boolean => input.every(RDocumentBarcode.isValid) } diff --git a/src/recipes/image/document-image/index.ts b/src/recipes/image/document-image/index.ts deleted file mode 100644 index 186d007..0000000 --- a/src/recipes/image/document-image/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './models' -export * from './get-document-image.recipe' diff --git a/src/recipes/image/document-image/models/document-image-page.model.ts b/src/recipes/image/document-image/models/document-image-page.model.ts deleted file mode 100644 index f4fe1c2..0000000 --- a/src/recipes/image/document-image/models/document-image-page.model.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { IsDefined, IsInt, IsString } from 'class-validator' - - -export interface iRDocumentImagePage { - pageIndex: number - src: string - width: number - height: number -} - -export class RDocumentImagePage implements iRDocumentImagePage { - @IsDefined() - @IsInt() - pageIndex: number - - @IsDefined() - @IsString() - src: string - - @IsDefined() - @IsInt() - width: number - - @IsDefined() - @IsInt() - height: number -} diff --git a/src/recipes/image/document-image/models/document-image.model.ts b/src/recipes/image/document-image/models/document-image.model.ts deleted file mode 100644 index a316d26..0000000 --- a/src/recipes/image/document-image/models/document-image.model.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { plainToClass, Type } from 'class-transformer' -import { IsDefined, IsEnum, IsString, ValidateNested } from 'class-validator' -import { eLights } from '@regulaforensics/document-reader-typings' - -import { AllowPrimitives } from '@/types' -import { RDocumentImagePage, iRDocumentImagePage } from './document-image-page.model' - - -export interface iRDocumentImage { - light: eLights - name: string - pages: iRDocumentImagePage[] -} - -export class RDocumentImage implements iRDocumentImage { - @IsDefined() - @IsEnum(eLights) - light: eLights - - @IsDefined() - @IsString() - name: string - - @IsDefined() - @Type(() => RDocumentImagePage) - @ValidateNested({ each: true }) - pages: RDocumentImagePage[] - - static fromPlain = (input: AllowPrimitives): RDocumentImage => plainToClass(RDocumentImage, input) -} diff --git a/src/recipes/image/document-image/get-document-image.recipe.test.ts b/src/recipes/image/document-images/get-document-images.recipe.test.ts similarity index 63% rename from src/recipes/image/document-image/get-document-image.recipe.test.ts rename to src/recipes/image/document-images/get-document-images.recipe.test.ts index b37447e..334753f 100644 --- a/src/recipes/image/document-image/get-document-image.recipe.test.ts +++ b/src/recipes/image/document-images/get-document-images.recipe.test.ts @@ -1,14 +1,14 @@ import { ProcessResponse } from '@regulaforensics/document-reader-typings' -import rawDocReaderResponse from '@/test-data/0.json' -import { getDocumentImage } from './get-document-image.recipe' +import rawDocReaderResponse from '@/test-data/2.json' +import { getDocumentImages } from './get-document-images.recipe' describe('getDocumentImage', () => { const docReaderResponse = ProcessResponse.fromPlain(rawDocReaderResponse) test('should return non-empty array of images', async () => { - const result = await getDocumentImage(docReaderResponse) + const result = await getDocumentImages(docReaderResponse) expect(result.length).toBeGreaterThan(0) }) diff --git a/src/recipes/image/document-image/get-document-image.recipe.ts b/src/recipes/image/document-images/get-document-images.recipe.ts similarity index 76% rename from src/recipes/image/document-image/get-document-image.recipe.ts rename to src/recipes/image/document-images/get-document-images.recipe.ts index 5c0d757..c6b0453 100644 --- a/src/recipes/image/document-image/get-document-image.recipe.ts +++ b/src/recipes/image/document-images/get-document-images.recipe.ts @@ -9,7 +9,10 @@ import { getImageDimensions } from '@/helpers' import { RDocumentImage, RDocumentImagePage } from './models' -export const getDocumentImage = async (input: ProcessResponse): Promise => { +export const getDocumentImages = async ( + input: ProcessResponse, + fieldTypes?: eGraphicFieldType[] +): Promise => { const result: RDocumentImage[] = [] const containers = ImagesResultContainer.fromProcessResponse(input) @@ -18,10 +21,10 @@ export const getDocumentImage = async (input: ProcessResponse): Promise i.light === lightIndex) + let index = result.findIndex((i) => i.light === lightIndex && i.fieldType === field.fieldType) if (index < 0) { const current = new RDocumentImage() current.name = fieldName + current.fieldType = field.fieldType current.light = lightIndex current.pages = [] diff --git a/src/recipes/image/document-images/index.ts b/src/recipes/image/document-images/index.ts new file mode 100644 index 0000000..c33b7ba --- /dev/null +++ b/src/recipes/image/document-images/index.ts @@ -0,0 +1,2 @@ +export * from './models' +export * from './get-document-images.recipe' diff --git a/src/recipes/image/document-images/models/document-image-page.model.ts b/src/recipes/image/document-images/models/document-image-page.model.ts new file mode 100644 index 0000000..29c580f --- /dev/null +++ b/src/recipes/image/document-images/models/document-image-page.model.ts @@ -0,0 +1,68 @@ +import { IsDefined, IsInt, IsString } from 'class-validator' + + +/** +* Short version of image representation +*/ +export interface iRDocumentImagePage { + /** + * Page index + * @type {number} + */ + pageIndex: number + + /** + * Image file in base64 url representation + * @type {string} + */ + src: string + + /** + * Image width + * @type {number} + */ + width: number + + /** + * Image height + * @type {number} + */ + height: number +} + +/** +* Short version of image representation +*/ +export class RDocumentImagePage implements iRDocumentImagePage { + /** + * Page index + * @type {number} + */ + @IsDefined() + @IsInt() + pageIndex: number + + /** + * Image file in base64 url representation + * @type {string} + */ + @IsDefined() + @IsString() + src: string + + /** + * Image width + * @type {number} + */ + @IsDefined() + @IsInt() + width: number + + /** + * Image height + * @type {number} + */ + @IsDefined() + @IsInt() + height: number +} diff --git a/src/recipes/image/document-images/models/document-image.model.ts b/src/recipes/image/document-images/models/document-image.model.ts new file mode 100644 index 0000000..5dac43a --- /dev/null +++ b/src/recipes/image/document-images/models/document-image.model.ts @@ -0,0 +1,98 @@ +import { plainToClass, Type } from 'class-transformer' +import { IsDefined, IsEnum, IsString, ValidateNested, validateSync } from 'class-validator' +import { eGraphicFieldType, eLights } from '@regulaforensics/document-reader-typings' + +import { AllowPrimitives } from '@/types' +import { RDocumentImagePage, iRDocumentImagePage } from './document-image-page.model' + + +/** +* Short version of image representation +*/ +export interface iRDocumentImage { + /** + * Lighting scheme used to capture the image + * @type {eLights} + */ + light: eLights + + /** + * Field type + * @type {eGraphicFieldType} + */ + fieldType: eGraphicFieldType + + /** + * Image file name + * @type {string} + */ + name: string + + /** + * Image representation + * @type {iRDocumentImagePage[]} + */ + pages: iRDocumentImagePage[] +} + +/** +* Short version of image representation +*/ +export class RDocumentImage implements iRDocumentImage { + /** + * Lighting scheme used to capture the image + * @type {eLights} + */ + @IsDefined() + @IsEnum(eLights) + light: eLights + + /** + * Field type + * @type {eGraphicFieldType} + */ + @IsDefined() + @IsEnum(eGraphicFieldType) + fieldType: eGraphicFieldType + + /** + * Image file name + * @type {string} + */ + @IsDefined() + @IsString() + name: string + + /** + * Image representation + * @type {iRDocumentImagePage[]} + */ + @IsDefined() + @Type(() => RDocumentImagePage) + @ValidateNested({ each: true }) + pages: RDocumentImagePage[] + + /** + * Create instance of RDocumentImage from plain object + * @param {AllowPrimitives} input - plain object + * @returns {RDocumentImage} + */ + static fromPlain = (input: AllowPrimitives): RDocumentImage => plainToClass(RDocumentImage, input) + + /** + * Check if RDocumentImage is valid + * @param {RDocumentImage} input - RDocumentImage object + * @returns {boolean} + */ + static isValid = (input: RDocumentImage): boolean => { + const errors = validateSync(input) + + if (errors.length) { + console.error(errors) + + return false + } + + return true + } +} diff --git a/src/recipes/image/document-image/models/index.ts b/src/recipes/image/document-images/models/index.ts similarity index 100% rename from src/recipes/image/document-image/models/index.ts rename to src/recipes/image/document-images/models/index.ts diff --git a/src/recipes/image/graphic-field/get-document-front.recipe.test.ts b/src/recipes/image/graphic-field/get-document-front.recipe.test.ts index df765d1..2ac6a60 100644 --- a/src/recipes/image/graphic-field/get-document-front.recipe.test.ts +++ b/src/recipes/image/graphic-field/get-document-front.recipe.test.ts @@ -4,13 +4,15 @@ import rawDocReaderResponse from '@/test-data/0.json' import { getDocumentFront } from './get-document-front.recipe' -describe('getDocumentFront', () => { +describe('getDocumentFront', async () => { const docReaderResponse = ProcessResponse.fromPlain(rawDocReaderResponse) + const result = await getDocumentFront(docReaderResponse) - test('should return valid image', async () => { - const result = await getDocumentFront(docReaderResponse) + test('should be defined', () => { + expect(result).toBeDefined() + }) + test('should return valid image', () => { expect(result.src).toMatch(/^data:image\/jpeg;base64/) - expect(result).toBeDefined() }) }) diff --git a/src/recipes/image/graphic-field/get-graphic-field.recipe.test.ts b/src/recipes/image/graphic-field/get-graphic-field.recipe.test.ts index 8eecf1e..a7440b5 100644 --- a/src/recipes/image/graphic-field/get-graphic-field.recipe.test.ts +++ b/src/recipes/image/graphic-field/get-graphic-field.recipe.test.ts @@ -4,14 +4,16 @@ import rawDocReaderResponse from '@/test-data/0.json' import { getGraphicField } from './get-graphic-field.recipe' -describe('getGraphicField', () => { +describe('getGraphicField', async () => { const docReaderResponse = ProcessResponse.fromPlain(rawDocReaderResponse) + const result = await getGraphicField(docReaderResponse, eGraphicFieldType.DOCUMENT_FRONT) - test('should return valid image', async () => { - const result = await getGraphicField(docReaderResponse, eGraphicFieldType.DOCUMENT_FRONT) + test('should be defined', async () => { + expect(result).toBeDefined() + }) + test('should return valid image', async () => { expect(result.src).toMatch(/^data:image\/jpeg;base64/) - expect(result).toBeDefined() }) test('should be able to return default image', async () => { diff --git a/src/recipes/image/graphic-field/models/graphic-field.model.ts b/src/recipes/image/graphic-field/models/graphic-field.model.ts index ecdbd41..66ac214 100644 --- a/src/recipes/image/graphic-field/models/graphic-field.model.ts +++ b/src/recipes/image/graphic-field/models/graphic-field.model.ts @@ -1,27 +1,81 @@ -import { IsDefined, IsInt, IsString } from 'class-validator' +import { IsDefined, IsInt, IsString, validateSync } from 'class-validator' import { plainToClass } from 'class-transformer' import { AllowPrimitives } from '@/types' +/** +* Short version of graphic field representation +*/ export interface iRGraphicField { + /** + * Image file in base64 url representation + * @type {string} + */ src: string + + /** + * Image width + * @type {number} + */ width: number + + /** + * Image height + * @type {number} + */ height: number } +/** +* Short version of graphic field representation +*/ export class RGraphicField implements iRGraphicField { + /** + * Image file in base64 url representation + * @type {string} + */ @IsDefined() @IsString() src: string + /** + * Image width + * @type {number} + */ @IsDefined() @IsInt() width: number + /** + * Image height + * @type {number} + */ @IsDefined() @IsInt() height: number + /** + * Create instance of RGraphicField from plain object + * @param {AllowPrimitives} input - plain object + * @returns {RGraphicField} + */ static fromPlain = (input: AllowPrimitives): RGraphicField => plainToClass(RGraphicField, input) + + /** + * Check if RGraphicField is valid + * @param {RGraphicField} input - RGraphicField object + * @returns {boolean} + */ + static isValid = (input: RGraphicField): boolean => { + const errors = validateSync(input) + + if (errors.length) { + console.error(errors) + + return false + } + + return true + } } diff --git a/src/recipes/image/image-quality/models/image-quality-check.model.ts b/src/recipes/image/image-quality/models/image-quality-check.model.ts index 80a8cc2..fe2e344 100644 --- a/src/recipes/image/image-quality/models/image-quality-check.model.ts +++ b/src/recipes/image/image-quality/models/image-quality-check.model.ts @@ -2,16 +2,39 @@ import { IsDefined, IsEnum } from 'class-validator' import { eCheckResult, eImageQualityCheckType } from '@regulaforensics/document-reader-typings' +/** +* Short version of image quality check +*/ export interface iRImageQualityCheck { + /** + * Check type + * @type {eImageQualityCheckType} + */ checkType: eImageQualityCheckType + + /** + * Check result + * @type {eCheckResult} + */ checkResult: eCheckResult } +/** +* Short version of image quality check +*/ export class RImageQualityCheck implements iRImageQualityCheck { + /** + * Check type + * @type {eImageQualityCheckType} + */ @IsDefined() @IsEnum(eImageQualityCheckType) checkType: eImageQualityCheckType + /** + * Check result + * @type {eCheckResult} + */ @IsDefined() @IsEnum(eCheckResult) checkResult: eCheckResult diff --git a/src/recipes/image/image-quality/models/image-quality.model.ts b/src/recipes/image/image-quality/models/image-quality.model.ts index 792a8d7..51f6bd3 100644 --- a/src/recipes/image/image-quality/models/image-quality.model.ts +++ b/src/recipes/image/image-quality/models/image-quality.model.ts @@ -1,4 +1,4 @@ -import { IsDefined, IsNumber, ValidateNested } from 'class-validator' +import { IsDefined, IsNumber, ValidateNested, validateSync } from 'class-validator' import { plainToClass, Type } from 'class-transformer' import { AllowPrimitives } from '@/types' @@ -21,4 +21,16 @@ export class RImageQuality implements iRImageQuality { checks: RImageQualityCheck[] static fromPlain = (input: AllowPrimitives): RImageQuality => plainToClass(RImageQuality, input) + + static isValid = (input: RImageQuality): boolean => { + const errors = validateSync(input) + + if (errors.length) { + console.error(errors) + + return false + } + + return true + } } diff --git a/src/recipes/image/index.ts b/src/recipes/image/index.ts index a877729..2c02f04 100644 --- a/src/recipes/image/index.ts +++ b/src/recipes/image/index.ts @@ -1,2 +1,2 @@ -export * from './document-image' +export * from './document-images' export * from './graphic-field' diff --git a/src/recipes/status/detailed-status/get-detailed-status.recipe.test.ts b/src/recipes/status/detailed-status/get-detailed-status.recipe.test.ts index 60c60d7..d2eb246 100644 --- a/src/recipes/status/detailed-status/get-detailed-status.recipe.test.ts +++ b/src/recipes/status/detailed-status/get-detailed-status.recipe.test.ts @@ -7,16 +7,37 @@ import { getDetailedStatus } from './get-detailed-status.recipe' describe('getDetailedStatus', () => { const docReaderResponse = ProcessResponse.fromPlain(rawDocReaderResponse) + const result = getDetailedStatus(docReaderResponse) - test('should return status', () => { - const result = getDetailedStatus(docReaderResponse) + test('should be defined', () => { + expect(result).toBeDefined() + }) + + test('should return DOC_TYPE status', () => { + expect(result.optical[eOpticalStatusField.DOC_TYPE]).toBeDefined() + }) + + test('should return OVERALL status', () => { + expect(result.optical[eOpticalStatusField.OVERALL]).toBeDefined() + }) + + test('should return TEXT status', () => { + expect(result.optical[eOpticalStatusField.TEXT]).toBeDefined() + }) + + test('should return SECURITY status', () => { + expect(result.optical[eOpticalStatusField.SECURITY]).toBeDefined() + }) + + test('should return MRZ status', () => { + expect(result.optical[eOpticalStatusField.MRZ]).toBeDefined() + }) + + test('should return IMAGE_QA status', () => { + expect(result.optical[eOpticalStatusField.IMAGE_QA]).toBeDefined() + }) - expect(result.optical[eOpticalStatusField.DOC_TYPE]).toBe(eCheckResult.OK) - expect(result.optical[eOpticalStatusField.OVERALL]).toBe(eCheckResult.ERROR) - expect(result.optical[eOpticalStatusField.TEXT]).toBe(eCheckResult.ERROR) - expect(result.optical[eOpticalStatusField.SECURITY]).toBe(eCheckResult.WAS_NOT_DONE) - expect(result.optical[eOpticalStatusField.MRZ]).toBe(eCheckResult.ERROR) - expect(result.optical[eOpticalStatusField.IMAGE_QA]).toBe(eCheckResult.OK) - expect(result.optical[eOpticalStatusField.EXPIRY]).toBe(eCheckResult.ERROR) + test('should return EXPIRY status', () => { + expect(result.optical[eOpticalStatusField.EXPIRY]).toBeDefined() }) }) diff --git a/src/recipes/status/detailed-status/get-detailed-status.recipe.ts b/src/recipes/status/detailed-status/get-detailed-status.recipe.ts index de6ec99..b88bebf 100644 --- a/src/recipes/status/detailed-status/get-detailed-status.recipe.ts +++ b/src/recipes/status/detailed-status/get-detailed-status.recipe.ts @@ -22,7 +22,7 @@ export const getDetailedStatus = (input: ProcessResponse): RDetailedStatus => { result.optical = new RDetailedStatusOptical() result.optical[eOpticalStatusField.DOC_TYPE] = status.detailsOptical.docType - result.optical[eOpticalStatusField.OVERALL] = status.overallStatus + result.optical[eOpticalStatusField.OVERALL] = status.detailsOptical.overallStatus result.optical[eOpticalStatusField.TEXT] = status.detailsOptical.text result.optical[eOpticalStatusField.SECURITY] = status.detailsOptical.security result.optical[eOpticalStatusField.MRZ] = status.detailsOptical.mrz diff --git a/src/recipes/status/detailed-status/models/detailed-status-optical.model.ts b/src/recipes/status/detailed-status/models/detailed-status-optical.model.ts index 4ebcfd7..dd596d0 100644 --- a/src/recipes/status/detailed-status/models/detailed-status-optical.model.ts +++ b/src/recipes/status/detailed-status/models/detailed-status-optical.model.ts @@ -5,47 +5,117 @@ import { eOpticalStatusField } from './consts' import { Expose } from 'class-transformer' +/** +* Summary of optical check results +*/ export interface iRDetailedStatusOptical { + /** + * Overall result of optical check + * @type {eCheckResult} + */ [eOpticalStatusField.OVERALL]: eCheckResult + + /** + * The check status if document type was recognized or not. + * @type {eCheckResult} + */ [eOpticalStatusField.DOC_TYPE]: eCheckResult + + /** + * The document validity period verification status. + * @type {eCheckResult} + */ [eOpticalStatusField.EXPIRY]: eCheckResult + + /** + * The input images quality verification status. + * @type {eCheckResult} + */ [eOpticalStatusField.IMAGE_QA]: eCheckResult + + /** + * MRZ verification: values validity, dates, checkdigits verification. + * @type {eCheckResult} + */ [eOpticalStatusField.MRZ]: eCheckResult + + /** + * The authenticity verification status + * @type {eCheckResult} + */ [eOpticalStatusField.SECURITY]: eCheckResult + + /** + * Text fields valitity: values validity for specific fields, cross-comparison of values from different sources, + * dates & checkdigits verification. + * @type {eCheckResult} + */ [eOpticalStatusField.TEXT]: eCheckResult } +/** +* Summary of optical check results +*/ export class RDetailedStatusOptical implements iRDetailedStatusOptical { + /** + * Overall result of optical check + * @type {eCheckResult} + */ @Expose() @IsDefined() @IsEnum(eCheckResult) [eOpticalStatusField.OVERALL]: eCheckResult + /** + * The check status if document type was recognized or not. + * @type {eCheckResult} + */ @Expose() @IsDefined() @IsEnum(eCheckResult) [eOpticalStatusField.DOC_TYPE]: eCheckResult + /** + * The document validity period verification status. + * @type {eCheckResult} + */ @Expose() @IsDefined() @IsEnum(eCheckResult) [eOpticalStatusField.EXPIRY]: eCheckResult + /** + * The input images quality verification status. + * @type {eCheckResult} + */ @Expose() @IsDefined() @IsEnum(eCheckResult) [eOpticalStatusField.IMAGE_QA]: eCheckResult + /** + * MRZ verification: values validity, dates, checkdigits verification. + * @type {eCheckResult} + */ @Expose() @IsDefined() @IsEnum(eCheckResult) [eOpticalStatusField.MRZ]: eCheckResult + /** + * The authenticity verification status + * @type {eCheckResult} + */ @Expose() @IsDefined() @IsEnum(eCheckResult) [eOpticalStatusField.SECURITY]: eCheckResult + /** + * Text fields valitity: values validity for specific fields, cross-comparison of values from different sources, + * dates & checkdigits verification. + * @type {eCheckResult} + */ @Expose() @IsDefined() @IsEnum(eCheckResult) diff --git a/src/recipes/status/detailed-status/models/detailed-status.model.ts b/src/recipes/status/detailed-status/models/detailed-status.model.ts index 9455b8a..abb36bc 100644 --- a/src/recipes/status/detailed-status/models/detailed-status.model.ts +++ b/src/recipes/status/detailed-status/models/detailed-status.model.ts @@ -1,4 +1,4 @@ -import { IsDefined, ValidateNested } from 'class-validator' +import { IsDefined, ValidateNested, validateSync } from 'class-validator' import { plainToClass, Type } from 'class-transformer' import { AllowPrimitives } from '@/types' @@ -16,4 +16,16 @@ export class RDetailedStatus implements iRDetailedStatus { optical: RDetailedStatusOptical static fromPlain = (input: AllowPrimitives): RDetailedStatus => plainToClass(RDetailedStatus, input) + + static isValid = (input: RDetailedStatus): boolean => { + const errors = validateSync(input) + + if (errors.length) { + console.error(errors) + + return false + } + + return true + } } diff --git a/src/recipes/text/document-identification/get-document-identification.recipe.test.ts b/src/recipes/text/document-identification/get-document-identification.recipe.test.ts index b9fa392..02aefd1 100644 --- a/src/recipes/text/document-identification/get-document-identification.recipe.test.ts +++ b/src/recipes/text/document-identification/get-document-identification.recipe.test.ts @@ -6,13 +6,17 @@ import { getDocumentIdentification } from './get-document-identification.recipe' describe('getDocumentIdentification', () => { const docReaderResponse = ProcessResponse.fromPlain(rawDocReaderResponse) + const result = getDocumentIdentification(docReaderResponse) - test('should return valid value', async () => { - const result = getDocumentIdentification(docReaderResponse) + test('should be defined', () => { + expect(result).toBeDefined() + }) - expect(result.documentName).toBeDefined() + test('should return valid value', async () => { expect(result.documentName).toEqual('Serbia - ePassport (2008)') + }) + test('should return pageIndex', async () => { expect(result.pageIndex).toBeDefined() expect(result.pageIndex).toEqual(1) }) diff --git a/src/recipes/text/document-identification/models/document-identification.model.ts b/src/recipes/text/document-identification/models/document-identification.model.ts index ebdb58f..c371dc4 100644 --- a/src/recipes/text/document-identification/models/document-identification.model.ts +++ b/src/recipes/text/document-identification/models/document-identification.model.ts @@ -1,4 +1,4 @@ -import { IsDefined, IsNumber, IsString } from 'class-validator' +import { IsDefined, IsNumber, IsString, validateSync } from 'class-validator' import { plainToClass } from 'class-transformer' import { AllowPrimitives } from '@/types' @@ -19,4 +19,16 @@ export class RDocumentIdentification implements iRDocumentIdentification { documentName: string static fromPlain = (input: AllowPrimitives): RDocumentIdentification => plainToClass(RDocumentIdentification, input) + + static isValid = (input: RDocumentIdentification): boolean => { + const errors = validateSync(input) + + if (errors.length) { + console.error(errors) + + return false + } + + return true + } } diff --git a/src/recipes/text/index.ts b/src/recipes/text/index.ts index cc45bee..37f9f11 100644 --- a/src/recipes/text/index.ts +++ b/src/recipes/text/index.ts @@ -1,2 +1,4 @@ export * from './document-identification' export * from './name-surname' +export * from './text-data' +export * from './text-field-value' diff --git a/src/recipes/text/name-surname/models/name-surname.model.ts b/src/recipes/text/name-surname/models/name-surname.model.ts index 4bf8b73..b99a586 100644 --- a/src/recipes/text/name-surname/models/name-surname.model.ts +++ b/src/recipes/text/name-surname/models/name-surname.model.ts @@ -1,4 +1,4 @@ -import { IsDefined, IsEnum, IsString } from 'class-validator' +import { IsDefined, IsEnum, IsString, validateSync } from 'class-validator' import { plainToClass } from 'class-transformer' import { eCheckResult, eLCID } from '@regulaforensics/document-reader-typings' @@ -64,4 +64,16 @@ export class RNameSurname implements iRNameSurname { * @returns {RNameSurname} */ static fromPlain = (input: AllowPrimitives): RNameSurname => plainToClass(RNameSurname, input) + + static isValid = (input: RNameSurname): boolean => { + const errors = validateSync(input) + + if (errors.length) { + console.error(errors) + + return false + } + + return true + } } diff --git a/src/recipes/text/text-data/get-text-data.recipe.test.ts b/src/recipes/text/text-data/get-text-data.recipe.test.ts new file mode 100644 index 0000000..398e678 --- /dev/null +++ b/src/recipes/text/text-data/get-text-data.recipe.test.ts @@ -0,0 +1,15 @@ +import { ProcessResponse } from '@regulaforensics/document-reader-typings' + +import rawDocReaderResponse from '@/test-data/2.json' +import { getTextData } from './get-text-data.recipe' + + +describe('getTextData', () => { + const docReaderResponse = ProcessResponse.fromPlain(rawDocReaderResponse) + + test('should be defined', () => { + const result = getTextData(docReaderResponse) + + expect(result).toBeDefined() + }) +}) diff --git a/src/recipes/text/text-data/get-text-data.recipe.ts b/src/recipes/text/text-data/get-text-data.recipe.ts new file mode 100644 index 0000000..9304686 --- /dev/null +++ b/src/recipes/text/text-data/get-text-data.recipe.ts @@ -0,0 +1,49 @@ +import { ProcessResponse, TextResultContainer } from '@regulaforensics/document-reader-typings' + +import { RTextData, RTextDataSource } from './models' + + +export const getTextData = (input: ProcessResponse): RTextData[] => { + const result: RTextData[] = [] + const containers = TextResultContainer.fromProcessResponse(input) + + if (!containers.length) { + return result + } + + containers.forEach((container) => { + const availableSources = container.Text.availableSourceList.map(i => i.source) + + container.Text.fieldList.forEach((field) => { + const current = new RTextData() + + current.name = field.fieldName + current.value = field.value + current.lcid = field.lcid + current.checkResult = field.status + + current.bySource = [] + + availableSources.forEach((source) => { + const validity = field.validityList.find(i => i.source === source) + + if (validity) { + const currentSource = new RTextDataSource() + const currentSourceValue = field.valueList.find((i) => i.source === source) + + currentSource.checkResult = validity.status + currentSource.source = source + currentSource.value = currentSourceValue?.value || '' + + current.bySource.push(currentSource) + } + }) + + if (current.bySource.length) { + result.push(current) + } + }) + }) + + return result +} diff --git a/src/recipes/text/text-data/index.ts b/src/recipes/text/text-data/index.ts new file mode 100644 index 0000000..3d6c9d2 --- /dev/null +++ b/src/recipes/text/text-data/index.ts @@ -0,0 +1,2 @@ +export * from './models' +export * from './get-text-data.recipe' diff --git a/src/recipes/text/text-data/models/index.ts b/src/recipes/text/text-data/models/index.ts new file mode 100644 index 0000000..9c7e4f3 --- /dev/null +++ b/src/recipes/text/text-data/models/index.ts @@ -0,0 +1,2 @@ +export * from './text-data.model' +export * from './text-data-source.model' diff --git a/src/recipes/text/text-data/models/text-data-source.model.ts b/src/recipes/text/text-data/models/text-data-source.model.ts new file mode 100644 index 0000000..06963d5 --- /dev/null +++ b/src/recipes/text/text-data/models/text-data-source.model.ts @@ -0,0 +1,26 @@ +import { IsDefined, IsEnum, IsString } from 'class-validator' +import { eCheckResult, eSource } from '@regulaforensics/document-reader-typings' + +import { Default } from '@/decorators' + + +export interface iRTextDataSource { + source: eSource + checkResult: eCheckResult + value: string +} + +export class RTextDataSource implements iRTextDataSource { + @IsDefined() + @IsEnum(eSource) + source: eSource + + @IsDefined() + @IsEnum(eCheckResult) + checkResult: eCheckResult + + @IsDefined() + @IsString() + @Default('') + value: string +} diff --git a/src/recipes/text/text-data/models/text-data.model.ts b/src/recipes/text/text-data/models/text-data.model.ts new file mode 100644 index 0000000..6cc0eab --- /dev/null +++ b/src/recipes/text/text-data/models/text-data.model.ts @@ -0,0 +1,39 @@ +import { IsDefined, IsEnum, IsString, ValidateNested } from 'class-validator' +import { Type } from 'class-transformer' +import { eCheckResult, eLCID } from '@regulaforensics/document-reader-typings' + +import { Default } from '@/decorators' +import { iRTextDataSource, RTextDataSource } from './text-data-source.model' + + +export interface iRTextData { + name: string + value: string + checkResult: eCheckResult + lcid: eLCID + bySource: iRTextDataSource[] +} + +export class RTextData implements iRTextData { + @IsDefined() + @IsString() + name: string + + @IsDefined() + @IsString() + value: string + + @IsDefined() + @IsEnum(eCheckResult) + checkResult: eCheckResult + + @IsDefined() + @IsEnum(eLCID) + @Default(eLCID.ENGLISH_US) + lcid: eLCID + + @IsDefined() + @Type(() => RTextDataSource) + @ValidateNested({ each: true }) + bySource: RTextDataSource[] +} diff --git a/src/recipes/text/text-field-value/get-document-date-of-expiry.recipe.ts b/src/recipes/text/text-field-value/get-document-date-of-expiry.recipe.ts new file mode 100644 index 0000000..6854aab --- /dev/null +++ b/src/recipes/text/text-field-value/get-document-date-of-expiry.recipe.ts @@ -0,0 +1,14 @@ +import { eVisualFieldType, ProcessResponse } from '@regulaforensics/document-reader-typings' + +import { RTextFieldValue } from './models' +import { getTextFieldValue } from './get-text-field-value.recipe' + + +export function getDocumentDateOfExpiry(input: ProcessResponse, allowDefault?: true): RTextFieldValue; +export function getDocumentDateOfExpiry(input: ProcessResponse, allowDefault?: false): RTextFieldValue | undefined; +export function getDocumentDateOfExpiry(input: ProcessResponse, allowDefault: boolean = true): RTextFieldValue | undefined { + if (allowDefault) { + return getTextFieldValue(input, eVisualFieldType.DATE_OF_EXPIRY, true) + } + return getTextFieldValue(input, eVisualFieldType.DATE_OF_EXPIRY, false) +} diff --git a/src/recipes/text/text-field-value/get-document-issuing-state-name.recipe.ts b/src/recipes/text/text-field-value/get-document-issuing-state-name.recipe.ts new file mode 100644 index 0000000..9047f09 --- /dev/null +++ b/src/recipes/text/text-field-value/get-document-issuing-state-name.recipe.ts @@ -0,0 +1,14 @@ +import { eVisualFieldType, ProcessResponse } from '@regulaforensics/document-reader-typings' + +import { RTextFieldValue } from './models' +import { getTextFieldValue } from './get-text-field-value.recipe' + + +export function getDocumentIssuingStateName(input: ProcessResponse, allowDefault?: true): RTextFieldValue; +export function getDocumentIssuingStateName(input: ProcessResponse, allowDefault?: false): RTextFieldValue | undefined; +export function getDocumentIssuingStateName(input: ProcessResponse, allowDefault: boolean = true): RTextFieldValue | undefined { + if (allowDefault) { + return getTextFieldValue(input, eVisualFieldType.ISSUING_STATE_NAME, true) + } + return getTextFieldValue(input, eVisualFieldType.ISSUING_STATE_NAME, false) +} diff --git a/src/recipes/text/text-field-value/get-document-number.recipe.ts b/src/recipes/text/text-field-value/get-document-number.recipe.ts new file mode 100644 index 0000000..c234f10 --- /dev/null +++ b/src/recipes/text/text-field-value/get-document-number.recipe.ts @@ -0,0 +1,14 @@ +import { eVisualFieldType, ProcessResponse } from '@regulaforensics/document-reader-typings' + +import { RTextFieldValue } from './models' +import { getTextFieldValue } from './get-text-field-value.recipe' + + +export function getDocumentNumber(input: ProcessResponse, allowDefault?: true): RTextFieldValue; +export function getDocumentNumber(input: ProcessResponse, allowDefault?: false): RTextFieldValue | undefined; +export function getDocumentNumber(input: ProcessResponse, allowDefault: boolean = true): RTextFieldValue | undefined { + if (allowDefault) { + return getTextFieldValue(input, eVisualFieldType.DOCUMENT_NUMBER, true) + } + return getTextFieldValue(input, eVisualFieldType.DOCUMENT_NUMBER, false) +} diff --git a/src/recipes/text/text-field-value/get-text-field-value.recipe.test.ts b/src/recipes/text/text-field-value/get-text-field-value.recipe.test.ts new file mode 100644 index 0000000..0fd7f61 --- /dev/null +++ b/src/recipes/text/text-field-value/get-text-field-value.recipe.test.ts @@ -0,0 +1,17 @@ +import { eCheckResult, eVisualFieldType, ProcessResponse } from '@regulaforensics/document-reader-typings' + +import rawDocReaderResponse from '@/test-data/2.json' +import { getTextFieldValue } from './get-text-field-value.recipe' + + +describe('getTextFieldValue', () => { + const docReaderResponse = ProcessResponse.fromPlain(rawDocReaderResponse) + + test('should return value', () => { + const result = getTextFieldValue(docReaderResponse, eVisualFieldType.DOCUMENT_NUMBER) + + expect(result).toBeDefined() + expect(result.value).toBe('X80856222') + expect(result.status).toBe(eCheckResult.OK) + }) +}) diff --git a/src/recipes/text/text-field-value/get-text-field-value.recipe.ts b/src/recipes/text/text-field-value/get-text-field-value.recipe.ts new file mode 100644 index 0000000..ce165e5 --- /dev/null +++ b/src/recipes/text/text-field-value/get-text-field-value.recipe.ts @@ -0,0 +1,31 @@ +import { + eCheckResult, + eVisualFieldType, + ProcessResponse, + TextResultContainer +} from '@regulaforensics/document-reader-typings' + +import { RTextFieldValue } from './models' + + +export function getTextFieldValue(input: ProcessResponse, fieldType: eVisualFieldType, allowDefault?: true): RTextFieldValue; +export function getTextFieldValue(input: ProcessResponse, fieldType: eVisualFieldType, allowDefault?: false): RTextFieldValue | undefined; +export function getTextFieldValue(input: ProcessResponse, fieldType: eVisualFieldType, allowDefault: boolean = true): RTextFieldValue | undefined { + const containers = TextResultContainer.fromProcessResponse(input) + + for (let i = 0; i < containers.length; i++) { + const container = containers[i] + const field = container.Text.fieldList.find((i) => i.fieldType === fieldType) + + if (field) { + return RTextFieldValue.fromPlain({ + value: field.value, + status: field.status, + }) + } + } + + return allowDefault + ? RTextFieldValue.fromPlain({ value: '', status: eCheckResult.WAS_NOT_DONE }) + : undefined +} diff --git a/src/recipes/text/text-field-value/index.ts b/src/recipes/text/text-field-value/index.ts new file mode 100644 index 0000000..7fc4bad --- /dev/null +++ b/src/recipes/text/text-field-value/index.ts @@ -0,0 +1,5 @@ +export * from './models' +export * from './get-document-date-of-expiry.recipe' +export * from './get-document-issuing-state-name.recipe' +export * from './get-document-number.recipe' +export * from './get-text-field-value.recipe' diff --git a/src/recipes/text/text-field-value/models/index.ts b/src/recipes/text/text-field-value/models/index.ts new file mode 100644 index 0000000..3444bc0 --- /dev/null +++ b/src/recipes/text/text-field-value/models/index.ts @@ -0,0 +1 @@ +export * from './text-field-value.model' diff --git a/src/recipes/text/text-field-value/models/text-field-value.model.ts b/src/recipes/text/text-field-value/models/text-field-value.model.ts new file mode 100644 index 0000000..bf724dd --- /dev/null +++ b/src/recipes/text/text-field-value/models/text-field-value.model.ts @@ -0,0 +1,26 @@ +import { IsDefined, IsEnum, IsString } from 'class-validator' +import { eCheckResult } from '@regulaforensics/document-reader-typings' +import { plainToClass } from 'class-transformer' + +import { Default } from '@/decorators' +import { AllowPrimitives } from '@/types' + + +export interface iRTextFieldValue { + value: string + status: eCheckResult +} + +export class RTextFieldValue implements iRTextFieldValue { + @IsDefined() + @IsString() + @Default('') + value: string + + @IsDefined() + @IsEnum(eCheckResult) + @Default(eCheckResult.WAS_NOT_DONE) + status: eCheckResult + + static fromPlain = (input: AllowPrimitives): RTextFieldValue => plainToClass(RTextFieldValue, input) +}