From def7b23baa18fba34efc0ee349e5f4915f22ffee Mon Sep 17 00:00:00 2001 From: sleep-written Date: Wed, 24 Aug 2022 10:44:40 -0400 Subject: [PATCH] v2.1.0: - Added the option "cut" in "string-type". - Added comments when required. - Updated documentation. - Updated dev dependencies. --- README.md | 39 +++++++++++++++++++++++------ package-lock.json | 46 +++++++++++++++++------------------ package.json | 8 +++--- src/auditor.ts | 29 +++++++++++++++++++--- src/converters/string-conv.ts | 6 ++++- src/interfaces/array-type.ts | 18 ++++++++++++++ src/interfaces/date-type.ts | 7 ++++++ src/interfaces/number-type.ts | 11 +++++++++ src/interfaces/object-type.ts | 3 +++ src/interfaces/string-type.ts | 20 +++++++++++++++ src/tests/string.test.ts | 18 ++++++++++++++ 11 files changed, 166 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index ec5143f..4539c13 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ This module works in __ESM__ projects (using _import_) and __CJS__ (using _requi ## The problem -Usually, when you make an endpoint (with express for example) you need to validate the incomind data before to modify your server state. In thoses cases, just the validation part taket a lot of space in your file, for example: +Usually, when you make an endpoint (with express for example) you need to validate the incoming data before to modify your server state. In those cases, just the validation part taken a lot of space in your file, for example: ```ts import express, { json } from 'express'; @@ -158,9 +158,11 @@ export const auditor = new Auditor({ Options: - `min` _(optional)_: `number`; - > If the incoming string has a length lower than the value setted, the `Auditor` instance will throws an `WrongLengthError` instance. + > If the incoming string has a length __lower__ than the value setted, the `Auditor` instance will throws an `WrongLengthError` instance. - `max` _(optional)_: `number`; - > If the incoming string has a length higher than the value setted, the `Auditor` instance will throws an `WrongLengthError` instance. + > If the incoming string has a length __higher__ than the value setted, the `Auditor` instance will throws an `WrongLengthError` instance. +- `cut` _(optional)_: `boolean`; + > If this option is enabled, when the length of the incoming string is longer than the `max` value settled, the output value will be cutted instead to throws an error. - `trim` _(optional)_: `boolean`; > Trims the incoming string __before to make any length validation__. @@ -180,9 +182,9 @@ export const auditor = new Auditor({ Options: - `min` _(optional)_: `number`; - > If the incoming value has lower than the value setted, the `Auditor` instance will throws an `WrongLengthError` instance. + > If the incoming value has __lower__ than the value setted, the `Auditor` instance will throws an `WrongLengthError` instance. - `max` _(optional)_: `number`; - > If the incoming value has higher than the value setted, the `Auditor` instance will throws an `WrongLengthError` instance. + > If the incoming value has __higher__ than the value setted, the `Auditor` instance will throws an `WrongLengthError` instance. Example: ```ts @@ -217,9 +219,9 @@ Options: - `items` _(required)_: `BaseType`; > With this option you can specify the structure of every item stored in the array, using the same options described in the past types described. __You can declare nested arrays, or object arrays too.__ - `min` _(optional)_: `number`; - > If the incoming array has a length lower than the value setted, the `Auditor` instance will throws an `WrongLengthError` instance. + > If the incoming array has a length __lower__ than the value setted, the `Auditor` instance will throws an `WrongLengthError` instance. - `max` _(optional)_: `number`; - > If the incoming array has a length higher than the value setted, the `Auditor` instance will throws an `WrongLengthError` instance. + > If the incoming array has a length __higher__ than the value setted, the `Auditor` instance will throws an `WrongLengthError` instance. Example 01 (array of `string`): ```ts @@ -339,4 +341,27 @@ export const auditor = new Auditor({ } } }); +``` + +## Utilities +### `this.structure` +Gets the actual structure of the current instance. Whith this you attach them to another more complex instance. + +```ts +const auditorChild = new Auditor({ + type: 'object', + keys: { + id: { type: 'number', min: 1 }, + text: { type: 'string' } + } +}); + +const auditorParent = new Auditor({ + type: 'object', + keys: { + objA: auditor.child.structure, + objB: auditor.child.structure, + } +}); + ``` \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index eacf697..109819f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,17 @@ { "name": "audit-var", - "version": "2.0.1", + "version": "2.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "audit-var", - "version": "2.0.1", + "version": "2.1.0", "license": "MIT", "devDependencies": { - "@types/node": "^18.0.1", - "ava": "^4.3.0", - "ts-node": "^10.8.2", + "@types/node": "^18.7.13", + "ava": "^4.3.1", + "ts-node": "^10.9.1", "typescript": "^4.7.4" } }, @@ -112,9 +112,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.1.tgz", - "integrity": "sha512-CmR8+Tsy95hhwtZBKJBs0/FFq4XX7sDZHlGGf+0q+BRZfMbOTkzkj0AFAuTyXbObDIoanaBBW0+KEW+m3N16Wg==", + "version": "18.7.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.13.tgz", + "integrity": "sha512-46yIhxSe5xEaJZXWdIBP7GU4HDTG8/eo0qd9atdiL+lFpA03y8KS+lkTN834TWJj5767GbWv4n/P6efyTFt1Dw==", "dev": true }, "node_modules/acorn": { @@ -246,9 +246,9 @@ } }, "node_modules/ava": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ava/-/ava-4.3.0.tgz", - "integrity": "sha512-Ap0u8rp8wOBN6CxshgxrPSe191e8g52RWGoXeDB57ubo4fyZyStfI6OxQi/bl0yxIDEOYHhCiGwihbzlMNJw3Q==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ava/-/ava-4.3.1.tgz", + "integrity": "sha512-zdSp9QxRTmN5hJeGmg+ZjUKL5yHFLMcP/0KBla8GH25XD8Xm7Uc34CDFlwqGL6JXtjNbVkJ0Zw+DqcTf4ggCCA==", "dev": true, "dependencies": { "acorn": "^8.7.1", @@ -1836,9 +1836,9 @@ } }, "node_modules/ts-node": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.2.tgz", - "integrity": "sha512-LYdGnoGddf1D6v8REPtIH+5iq/gTDuZqv2/UJUU7tKjuEU8xVZorBM+buCGNjj+pGEud+sOoM4CX3/YzINpENA==", + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", "dev": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -2216,9 +2216,9 @@ "dev": true }, "@types/node": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.1.tgz", - "integrity": "sha512-CmR8+Tsy95hhwtZBKJBs0/FFq4XX7sDZHlGGf+0q+BRZfMbOTkzkj0AFAuTyXbObDIoanaBBW0+KEW+m3N16Wg==", + "version": "18.7.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.13.tgz", + "integrity": "sha512-46yIhxSe5xEaJZXWdIBP7GU4HDTG8/eo0qd9atdiL+lFpA03y8KS+lkTN834TWJj5767GbWv4n/P6efyTFt1Dw==", "dev": true }, "acorn": { @@ -2305,9 +2305,9 @@ "dev": true }, "ava": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ava/-/ava-4.3.0.tgz", - "integrity": "sha512-Ap0u8rp8wOBN6CxshgxrPSe191e8g52RWGoXeDB57ubo4fyZyStfI6OxQi/bl0yxIDEOYHhCiGwihbzlMNJw3Q==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ava/-/ava-4.3.1.tgz", + "integrity": "sha512-zdSp9QxRTmN5hJeGmg+ZjUKL5yHFLMcP/0KBla8GH25XD8Xm7Uc34CDFlwqGL6JXtjNbVkJ0Zw+DqcTf4ggCCA==", "dev": true, "requires": { "acorn": "^8.7.1", @@ -3418,9 +3418,9 @@ } }, "ts-node": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.2.tgz", - "integrity": "sha512-LYdGnoGddf1D6v8REPtIH+5iq/gTDuZqv2/UJUU7tKjuEU8xVZorBM+buCGNjj+pGEud+sOoM4CX3/YzINpENA==", + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", "dev": true, "requires": { "@cspotcode/source-map-support": "^0.8.0", diff --git a/package.json b/package.json index 2551d18..3155daf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "audit-var", - "version": "2.0.1", + "version": "2.1.0", "type": "module", "description": "Inspects variables according to a defined structure", "main": "./dist/cjs/index.js", @@ -41,9 +41,9 @@ }, "homepage": "https://github.com/sleep-written/audit-var#readme", "devDependencies": { - "@types/node": "^18.0.1", - "ava": "^4.3.0", - "ts-node": "^10.8.2", + "@types/node": "^18.7.13", + "ava": "^4.3.1", + "ts-node": "^10.9.1", "typescript": "^4.7.4" } } diff --git a/src/auditor.ts b/src/auditor.ts index 086d956..937cac5 100644 --- a/src/auditor.ts +++ b/src/auditor.ts @@ -2,13 +2,34 @@ import { Types, ResponseType } from './interfaces/index.js'; import { recursiveConv } from './converters/index.js'; export class Auditor { - private _def: T; + private _structure: T; - constructor(definition: T) { - this._def = definition; + /** + * Gets the actual structure declared in the constructor. + * Useful if you want to use this as a nested structure in + * another `Auditor` instance for example. + */ + get structure(): T { + return this._structure; } + /** + * Creates an instance of `Auditor` class. With this instance you can validate + * untyped objects with the structure defined in the constructor. + * @param structure The structure do you want to use to validate objects. + */ + constructor(structure: T) { + this._structure = structure; + } + + /** + * Checks recursively (when is required) the structure of an object. + * If the target doesn't meets the required structured (declared in the + * constructor), this method will throws an error, otherwise will returns + * a typed and normalized version of the incoming target. + * @param target The object do you want to eval its structure. + */ audit(target: any): ResponseType { - return recursiveConv(this._def, target, []); + return recursiveConv(this._structure, target, []); } } diff --git a/src/converters/string-conv.ts b/src/converters/string-conv.ts index d09fa35..870f1c1 100644 --- a/src/converters/string-conv.ts +++ b/src/converters/string-conv.ts @@ -28,7 +28,11 @@ export const stringConv: converterFunct = (d, t, p) => { (typeof d.max === 'number') && (v.length > d.max) ) { - throw new WrongLengthError(p, `The length of the string is higher than ${d.max}.`); + if (!d.cut) { + throw new WrongLengthError(p, `The length of the string is higher than ${d.max}.`); + } else { + return v.slice(0, d.max); + } } // Valid string diff --git a/src/interfaces/array-type.ts b/src/interfaces/array-type.ts index 16716e0..fcb4bde 100644 --- a/src/interfaces/array-type.ts +++ b/src/interfaces/array-type.ts @@ -5,8 +5,26 @@ import { BooleanType } from './boolean-type.js'; import { ObjectType } from './object-type.js'; export interface ArrayType extends BaseType<'array'> { + /** + * If the incoming array has a length __lower__ than the value + * setted, the `Auditor` instance will throws an `WrongLengthError` + * instance. + */ min?: number; + + /** + * If the incoming array has a length __higher__ than the value + * setted, the `Auditor` instance will throws an `WrongLengthError` + * instance. + */ max?: number; + + /** + * With this option you can specify the structure of every + * item stored in the array, using the same options described + * in the past types described. __You can declare nested arrays, + * or object arrays too.__ + */ items: ArrayType | NumberType | diff --git a/src/interfaces/date-type.ts b/src/interfaces/date-type.ts index a4abe6d..771e412 100644 --- a/src/interfaces/date-type.ts +++ b/src/interfaces/date-type.ts @@ -1,5 +1,12 @@ import { BaseType } from './base-type.js'; export interface DateType extends BaseType<'date'> { + /** + * If this value is `true`, the `Auditor` instance will try to parse strings + * with a valid JSON Date format (like `'2022-12-31T03:00:00.000Z'`). If the + * convertion is sucessfull, the returned value will be a `Date` type, + * otherwise, the `Auditor` instance will throws an `InvalidJSONDateError` + * instance. + */ fromJSON?: boolean; } \ No newline at end of file diff --git a/src/interfaces/number-type.ts b/src/interfaces/number-type.ts index 5346c33..c7fa3fb 100644 --- a/src/interfaces/number-type.ts +++ b/src/interfaces/number-type.ts @@ -1,6 +1,17 @@ import { BaseType } from './base-type.js'; export interface NumberType extends BaseType<'number'> { + /** + * If the incoming value has __lower__ than the value setted, + * the `Auditor` instance will throws an `WrongLengthError` + * instance. + */ min?: number; + + /** + * If the incoming value has __higher__ than the value setted, + * the `Auditor` instance will throws an `WrongLengthError` + * instance. + */ max?: number; } diff --git a/src/interfaces/object-type.ts b/src/interfaces/object-type.ts index 2f95778..fbb96d2 100644 --- a/src/interfaces/object-type.ts +++ b/src/interfaces/object-type.ts @@ -7,6 +7,9 @@ import { StringType } from './string-type.js'; import { BooleanType } from './boolean-type.js'; export interface ObjectType extends BaseType<'object'> { + /** + * Defines the type of data expected for every key of the incoming object. + */ keys: Record< string, ArrayType | diff --git a/src/interfaces/string-type.ts b/src/interfaces/string-type.ts index 4509378..6c80df6 100644 --- a/src/interfaces/string-type.ts +++ b/src/interfaces/string-type.ts @@ -1,7 +1,27 @@ import { BaseType } from './base-type.js'; export interface StringType extends BaseType<'string'> { + /** + * Trims the incoming string __before to make any length validation.__ + */ trim?: boolean; + + /** + * If the incoming string has a length __lower__ than the value setted, + * the `Auditor` instance will throws an `WrongLengthError` instance. + */ min?: number; + + /** + * If the incoming string has a length __higher__ than the value setted, + * the `Auditor` instance will throws an `WrongLengthError` instance. + */ max?: number; + + /** + * If this option is enabled, when the length of the incoming string is + * longer than the max value settled, the output value will be cutted + * instead to throws an error. + */ + cut?: boolean; } diff --git a/src/tests/string.test.ts b/src/tests/string.test.ts index 180ac28..5833a3f 100644 --- a/src/tests/string.test.ts +++ b/src/tests/string.test.ts @@ -9,6 +9,24 @@ test('optional = false; value = "jajaja"', t => { t.is(val, 'jajaja'); }); +test('optional = false; value = "jajajajajajaj" (max: 3)', t => { + const aud = new Auditor({ type: 'string', max: 3 }); + t.throws( + () => { + aud.audit('jajajajajajaj'); + }, + { + message: 'The length of the string is higher than 3.' + } + ); +}); + +test('optional = false; value = "jajajajajajaj" (max: 3, cut: true)', t => { + const aud = new Auditor({ type: 'string', max: 3, cut: true }); + const val = aud.audit('jajajajajajaj'); + t.is(val, 'jaj'); +}); + test('optional = false; value = undefined', t => { const aud = new Auditor({ type: 'string' }); t.throws(