From d62b84d88327ef69f8fb22541da22cc01054d82b Mon Sep 17 00:00:00 2001 From: Mahabub Date: Sun, 20 Oct 2024 21:59:48 +0600 Subject: [PATCH] docs(api): added refs for array n object --- docs/api/array.md | 475 ++++++++++++++++++++++++- docs/api/object.md | 311 +++++++++++++++- lib/schemas/array.ts | 59 ++- lib/schemas/object.ts | 24 +- lib/validators/__tests__/array.test.ts | 12 - lib/validators/array.ts | 6 +- 6 files changed, 845 insertions(+), 42 deletions(-) diff --git a/docs/api/array.md b/docs/api/array.md index 8a49575..4c329b9 100644 --- a/docs/api/array.md +++ b/docs/api/array.md @@ -1,5 +1,478 @@ # Array +## Summary + +Our array schema is always dependent on others. Becasue, array is a collection of other data-types. You can find all available references here. + +## Table of Contents + +- [Schema & Validators](#schema-and-validators) + - [unique](#unique) + - [min](#min) + - [max](#max) + - [range](#range) + - [objects](#objects) + - [enums](#enums) +- [Conclusion](#conclusion) + +## Schema and Validators + +### Unique `.unique()` + +This validator is used to check if the array has unique values or not. If the array has duplicate values, it will return an error. + +::: warning + +Please note that, this validator will only work for primitive values. If you have an array of objects, it will not work. + +::: + +::: code-group + +```TypeScript +// define a schema of an array of unique numbers +const listOfUniqueNumbers = a.array(a.number()).unique() + +// validate & parse the array +const resultOne = listOfUniqueNumbers.parse([1, 2, 3, 4, 5]) // valid +const resultTow = listOfUniqueNumbers.parse([1, 2, 3, 4, 5, 1]) // invalid + +console.log(resultOne, resultTow) +``` + +```JavaScript +// define a schema of an array of unique numbers +const listOfUniqueNumbers = a.array(a.number()).unique() + +// validate & parse the array +const resultOne = listOfUniqueNumbers.parse([1, 2, 3, 4, 5]) // valid +const resultTow = listOfUniqueNumbers.parse([1, 2, 3, 4, 5, 1]) // invalid + +console.log(resultOne, resultTow) +``` + +::: + +**Output** + +::: code-group + +```bash [TypeScript] +{ + valid: true, + value: [1, 2, 3, 4, 5] +} + +{ + errors: [ + { + reason: "Array has duplicate values", + value: [1, 2, 3, 4, 5, 1] + } + ] +} +``` + +```bash [JavaScript] +{ + valid: true, + value: [1, 2, 3, 4, 5] +} + +{ + errors: [ + { + reason: "Array has duplicate values", + value: [1, 2, 3, 4, 5, 1] + } + ] +} +``` + +::: + +### Min `.min()` + +This validator is used to check if the array has a minimum number of elements or not. If the array has fewer elements than the specified number, it will return an error. + +::: code-group + +```TypeScript +// define a schema of an array of numbers with a minimum of 5 elements +const listOfNumbers = a.array(a.number()).min(5) + +// validate & parse the array +const resultOne = listOfNumbers.parse([1, 2, 3, 4, 5]) // invalid +const resultTow = listOfNumbers.parse([1, 2, 3, 4, 5, 6]) // valid + +console.log(resultOne, resultTow) +``` + +```JavaScript +// define a schema of an array of numbers with a minimum of 5 elements +const listOfNumbers = a.array(a.number()).min(5) + +// validate & parse the array +const resultOne = listOfNumbers.parse([1, 2, 3, 4, 5]) // invalid +const resultTow = listOfNumbers.parse([1, 2, 3, 4, 5, 6]) // valid + +console.log(resultOne, resultTow) +``` + +::: + +**Output** + +::: code-group + +```bash [TypeScript] +{ + errors: [ + { + reason: "Array has fewer elements than the minimum", + value: [1, 2, 3, 4, 5] + } + ] +} + +{ + valid: true, + value: [1, 2, 3, 4, 5, 6] +} +``` + +```bash [JavaScript] +{ + errors: [ + { + reason: "Array has fewer elements than the minimum", + value: [1, 2, 3, 4, 5] + } + ] +} + +{ + valid: true, + value: [1, 2, 3, 4, 5, 6] +} +``` + +::: + +### Max `.max()` + +This validator is used to check if the array has a maximum number of elements or not. If the array has more elements than the specified number, it will return an error. + +::: code-group + +```TypeScript +// define a schema of an array of numbers with a maximum of 5 elements +const listOfNumbers = a.array(a.number()).max(5) + +// validate & parse the array +const resultOne = listOfNumbers.parse([1, 2, 3, 4, 5]) // valid +const resultTow = listOfNumbers.parse([1, 2, 3, 4, 5, 6]) // invalid + +console.log(resultOne, resultTow) +``` + +```JavaScript +// define a schema of an array of numbers with a maximum of 5 elements +const listOfNumbers = a.array(a.number()).max(5) + +// validate & parse the array +const resultOne = listOfNumbers.parse([1, 2, 3, 4, 5]) // valid +const resultTow = listOfNumbers.parse([1, 2, 3, 4, 5, 6]) // invalid + +console.log(resultOne, resultTow) +``` + +::: + +**Output** + +::: code-group + +```bash [TypeScript] +{ + valid: true, + value: [1, 2, 3, 4, 5] +} + +{ + errors: [ + { + reason: "Array has more elements than the maximum", + value: [1, 2, 3, 4, 5, 6] + } + ] +} +``` + +```bash [JavaScript] +{ + valid: true, + value: [1, 2, 3, 4, 5] +} + +{ + errors: [ + { + reason: "Array has more elements than the maximum", + value: [1, 2, 3, 4, 5, 6] + } + ] +} +``` + +::: + +### Range `.range()` + +This validator is used to check if the array has a range of elements or not. If the array has fewer or more elements than the specified range, it will return an error. + +::: code-group + +```TypeScript +// define a schema of an array of numbers with a range of 3 to 5 elements +const listOfNumbers = a.array(a.number()).range(3, 5) + +// validate & parse the array +const resultOne = listOfNumbers.parse([1, 2, 3]) // invalid +const resultTow = listOfNumbers.parse([1, 2, 3, 4, 5]) // valid + +console.log(resultOne, resultTow) +``` + +```JavaScript +// define a schema of an array of numbers with a range of 3 to 5 elements +const listOfNumbers = a.array(a.number()).range(3, 5) + +// validate & parse the array +const resultOne = listOfNumbers.parse([1, 2, 3]) // invalid +const resultTow = listOfNumbers.parse([1, 2, 3, 4, 5]) // valid + +console.log(resultOne, resultTow) +``` + +::: + +**Output** + +::: code-group + +```bash [TypeScript] +{ + errors: [ + { + reason: "Array has fewer elements than the minimum", + value: [1, 2, 3] + } + ] +} + +{ + valid: true, + value: [1, 2, 3, 4, 5] +} +``` + +```bash [JavaScript] +{ + errors: [ + { + reason: "Array has fewer elements than the minimum", + value: [1, 2, 3] + } + ] +} + +{ + valid: true, + value: [1, 2, 3, 4, 5] +} +``` + +::: + +### Objects + +This validator is used to check if the array has a specific object schema or not. If the array has an object that does not match the specified schema, it will return an error. + +::: code-group + +```TypeScript +// define a schema of an array of objects +const listOfObjects = a.array(a.object({ + name: a.string(), + age: a.number() +})) + +// validate & parse the array +const resultOne = listOfObjects.parse([ + { name: 'John Doe', age: 25 }, + { name: 'Jane Doe', age: 23 } +]) // valid + +const resultTow = listOfObjects.parse([ + { name: 'John Doe', age: 25 }, + { name: 'Jane Doe', age: '23' } +]) // invalid + +console.log(resultOne, resultTow) +``` + +```JavaScript +// define a schema of an array of objects +const listOfObjects = a.array(a.object({ + name: a.string(), + age: a.number() +})) + +// validate & parse the array +const resultOne = listOfObjects.parse([ + { name: 'John Doe', age: 25 }, + { name: 'Jane Doe', age: 23 } +]) // valid + +const resultTow = listOfObjects.parse([ + { name: 'John Doe', age: 25 }, + { name: 'Jane Doe', age: '23' } +]) // invalid + +console.log(resultOne, resultTow) +``` + +::: + +**Output** + +::: code-group + +```bash [TypeScript] +{ + valid: true, + value: [ + { name: 'John Doe', age: 25 }, + { name: 'Jane Doe', age: 23 } + ] +} + +{ + errors: [ + { + reason: "Invalid value for age", + value: [ + { name: 'John Doe', age: 25 }, + { name: 'Jane Doe', age: '23' } + ] + } + ] +} +``` + +```bash [JavaScript] +{ + valid: true, + value: [ + { name: 'John Doe', age: 25 }, + { name: 'Jane Doe', age: 23 } + ] +} + +{ + errors: [ + { + reason: "Invalid value for age", + value: [ + { name: 'John Doe', age: 25 }, + { name: 'Jane Doe', age: '23' } + ] + } + ] +} +``` + +::: tip + +You can also use the `min`, `max`, `range` validators with this object based schema here. + +::: + +### Enums + +This validator is used to check if the array has specific values or not. If the array has a value that is not in the specified list, it will return an error. + ::: info -Work in progress ⏳ + +Enums are like experimental feature for now. It may not work as expected. We are working on it to make it better. If you find any issue, please raise an issue [here](https://github.com/mahabubx7/akar/issues). + +::: + +::: code-group + +```TypeScript +// define a schema of an array of numbers with specific values +const listOfStatus = a.array(a.enum(['active', 'inactive'] as const)) + +// validate & parse the array +const resultOne = listOfStatus.parse(['active', 'inactive']) // valid +const resultTow = listOfStatus.parse(['active', 'inactive', 'pending']) // invalid + +console.log(resultOne, resultTow) +``` + +```JavaScript +// define a schema of an array of numbers with specific values +const listOfStatus = a.array(a.enum(['active', 'inactive'])) + +// validate & parse the array +const resultOne = listOfStatus.parse(['active', 'inactive']) // valid +const resultTow = listOfStatus.parse(['active', 'inactive', 'pending']) // invalid + +console.log(resultOne, resultTow) +``` + +::: + +**Output** + +::: code-group + +```bash [TypeScript] +{ + valid: true, + value: ['active', 'inactive'] +} + +{ + errors: [ + { + reason: "Invalid value", + value: ['active', 'inactive', 'pending'] + } + ] +} +``` + +```bash [JavaScript] +{ + valid: true, + value: ['active', 'inactive'] +} + +{ + errors: [ + { + reason: "Invalid value", + value: ['active', 'inactive', 'pending'] + } + ] +} +``` + ::: + +## Conclusion + +This is the end of the array schema. You can raise an issue [here](https://github.com/mahabubx7/akar/issues) if you find any problem. We will try to fix it as soon as possible. diff --git a/docs/api/object.md b/docs/api/object.md index 34db6da..58d3995 100644 --- a/docs/api/object.md +++ b/docs/api/object.md @@ -1,5 +1,312 @@ # Object -::: info -Work in progress ⏳ +The `Object` class is the base class for all objects in the game. It provides a number of methods and properties that are common to all objects. + +## Table of Contents + +- [Schema & Validators](#schema-and-validators) + - [EqualTo](#equal-to) + - [DeepEqualTo](#not-equal-to) + - [ShallowEqualTo](#shallow-equal-to) + - [JsonObject](#json-object) +- [Conclusion](#conclusion) + +## Schema and Validators + +### EqualTo `.equalTo()` + +This validator is used to check if the object is equal to the provided object or not. If the object is not equal to the provided object, it will return an error. + +::: code-group + +```typescript +// define a schema of an object +const user = a + .object({ + name: a.string(), + age: a.number() + }) + .equalTo({ + name: "John Doe", + age: 30 + }) + +// validate & parse the object +const resultOne = user.parse({ + name: "John Doe", + age: 30 +}) // valid + +const resultTow = user.parse({ + name: "Jane Doe", + age: 25 +}) // invalid + +console.log(resultOne, resultTow) +``` + +```javascript +// define a schema of an object +const user = a + .object({ + name: a.string(), + age: a.number() + }) + .equalTo({ + name: "John Doe", + age: 30 + }) + +// validate & parse the object +const resultOne = user.parse({ + name: "John Doe", + age: 30 +}) // valid + +const resultTow = user.parse({ + name: "Jane Doe", + age: 25 +}) // invalid + +console.log(resultOne, resultTow) +``` + +::: + +**Output** + +```bash +{ name: 'John Doe', age: 30 } + +{ + errors: [ + { + reason: 'Object must be equal to "{ name: \'John Doe\', age: 30 }"', + value: { name: 'Jane Doe', age: 25 } + } + ] +} +``` + +### DeepEqualTo `.deepEqualTo()` + +This validator is used to check if the object is deeply equal to the provided object or not. If the object is not deeply equal to the provided object, it will return an error. + +::: code-group + +```typescript +// define a schema of an object +const user = a + .object({ + name: a.string(), + age: a.number() + }) + .deepEqualTo({ + name: "John Doe", + age: 30 + }) + +// validate & parse the object +const resultOne = user.parse({ + name: "John Doe", + age: 30 +}) // valid + +const resultTow = user.parse({ + name: "Jane Doe", + age: 25 +}) // invalid + +console.log(resultOne, resultTow) +``` + +```javascript +// define a schema of an object +const user = a + .object({ + name: a.string(), + age: a.number() + }) + .deepEqualTo({ + name: "John Doe", + age: 30 + }) + +// validate & parse the object +const resultOne = user.parse({ + name: "John Doe", + age: 30 +}) // valid + +const resultTow = user.parse({ + name: "Jane Doe", + age: 25 +}) // invalid + +console.log(resultOne, resultTow) +``` + +::: + +**Output** + +```bash +{ name: 'John Doe', age: 30 } + +{ + errors: [ + { + reason: 'Object must be deeply equal!', + value: { name: 'Jane Doe', age: 25 } + } + ] +} +``` + +### ShallowEqualTo `.shallowEqualTo()` + +This validator is used to check if the object is shallowly equal to the provided object or not. If the object is not shallowly equal to the provided object, it will return an error. + +::: code-group + +```typescript +// define a schema of an object +const user = a + .object({ + name: a.string(), + age: a.number() + }) + .shallowEqualTo({ + name: "John Doe", + age: 30 + }) + +// validate & parse the object +const resultOne = user.parse({ + name: "John Doe", + age: 30 +}) // valid + +const resultTow = user.parse({ + name: "Jane Doe", + age: 25 +}) // invalid + +console.log(resultOne, resultTow) +``` + +```javascript +// define a schema of an object +const user = a + .object({ + name: a.string(), + age: a.number() + }) + .shallowEqualTo({ + name: "John Doe", + age: 30 + }) + +// validate & parse the object +const resultOne = user.parse({ + name: "John Doe", + age: 30 +}) // valid + +const resultTow = user.parse({ + name: "Jane Doe", + age: 25 +}) // invalid + +console.log(resultOne, resultTow) +``` + +::: + +**Output** + +```bash +{ name: 'John Doe', age: 30 } + + { + errors: [ + { + reason: 'Object must be shallowly equal!', + value: { name: 'Jane Doe', age: 25 } + } + ] + } +``` + +### JsonObject `.jsonObject()` + +This validator is used to check if the object is a valid JSON object or not. If the object is not a valid JSON object, it will return an error. + +::: code-group + +```typescript +// define a schema of an object +const user = a + .object({ + name: a.string(), + age: a.number() + }) + .jsonObject() + +// validate & parse the object +const resultOne = user.parse({ + name: "John Doe", + age: 30 +}) // valid + +const resultTow = user.parse({ + name: "Jane Doe", + age: "25" +}) // invalid + +console.log(resultOne, resultTow) +``` + +```javascript +// define a schema of an object +const user = a + .object({ + name: a.string(), + age: a.number() + }) + .jsonObject() + +// validate & parse the object +const resultOne = user.parse({ + name: "John Doe", + age: 30 +}) // valid + +const resultTow = user.parse({ + name: "Jane Doe", + age: "25" +}) // invalid + +console.log(resultOne, resultTow) +``` + ::: + +**Output** + +```bash +{ name: 'John Doe', age: 30 } + +{ + errors: [ + { + reason: 'Object must be a valid JSON object!', + value: { name: 'Jane Doe', age: '25' } + } + ] +} +``` + +## Conclusion + +We covered the latest `Object` schema references so far. We will keep updating the documentation as we add more features to the `Object` schema. If you have any questions or suggestions, please feel free to raise an issue. diff --git a/lib/schemas/array.ts b/lib/schemas/array.ts index f90249d..44418b0 100644 --- a/lib/schemas/array.ts +++ b/lib/schemas/array.ts @@ -6,21 +6,46 @@ * @license MIT */ -import { isArray } from "../validators/array" +import { arrayChecker } from "../validators" import { AkarBase } from "./base" export class AkarArray extends AkarBase { + private miniumLength?: number + private maximumLength?: number + private hasRange: [number, number] = [0, -1] + private isUnique?: boolean + constructor(private schema: AkarBase) { super() } + min(min: number): this { + this.miniumLength = min + return this + } + + max(max: number): this { + this.maximumLength = max + return this + } + + range(min: number, max: number): this { + this.hasRange = [min, max] + return this + } + + unique(): this { + this.isUnique = true + return this + } + parse(input: any): { value?: T[] errors?: { field: string; reason: string; value?: any }[] } { const errors: { field: string; reason: string; value?: any }[] = [] - if (!isArray(input)) { + if (!arrayChecker.isArray(input)) { errors.push({ field: "array", reason: "Invalid type, expected array", @@ -29,6 +54,36 @@ export class AkarArray extends AkarBase { return { errors } } + if ( + this.miniumLength && + !arrayChecker.minLength(input, this.miniumLength) + ) { + errors.push({ + field: "array", + reason: `Expected at least ${this.miniumLength} items`, + value: input + }) + } + + if ( + this.maximumLength && + !arrayChecker.maxLength(input, this.maximumLength) + ) { + errors.push({ + field: "array", + reason: `Expected at most ${this.maximumLength} items`, + value: input + }) + } + + if (this.isUnique && !arrayChecker.isUnique(input)) { + errors.push({ + field: "array", + reason: "Expected unique items", + value: input + }) + } + const result: T[] = [] input.forEach((item, index) => { diff --git a/lib/schemas/object.ts b/lib/schemas/object.ts index df6b3e4..9651cf8 100644 --- a/lib/schemas/object.ts +++ b/lib/schemas/object.ts @@ -14,8 +14,6 @@ import { AkarBase } from "./base" export class AkarObject> extends AkarBase { private shape: { [K in keyof T]: AkarBase } private defaults: Partial - private hasOwnKeys: string[] | null = null - private hasOwnValues: unknown[] | null = null private isJson: boolean = false private compare: T | null = null private isEqual: boolean = false @@ -31,24 +29,6 @@ export class AkarObject> extends AkarBase { this.defaults = defaults } - hasKeys(keys: string[]): this { - if (!this.hasOwnKeys) { - this.hasOwnKeys = keys - return this - } - this.hasOwnKeys = [...this.hasOwnKeys!, ...keys] - return this - } - - hasValues(values: unknown[]): this { - if (!this.hasOwnValues) { - this.hasOwnValues = values - return this - } - this.hasOwnValues = [...this.hasOwnValues!, ...values] - return this - } - equalTo(compare: T): this { this.isEqual = true this.compare = compare @@ -110,7 +90,7 @@ export class AkarObject> extends AkarBase { if (this.isDeepEqual && !objectChecker.isDeepEqual(input, this.compare!)) { errors.push({ field: "object", - reason: `Object must be deeply equal to ${JSON.stringify(this.compare)}`, + reason: `Object must be deeply equal!`, value: input }) } @@ -121,7 +101,7 @@ export class AkarObject> extends AkarBase { ) { errors.push({ field: "object", - reason: `Object must be shallowly equal to ${JSON.stringify(this.compare)}`, + reason: `Object must be shallowly equal!`, value: input }) } diff --git a/lib/validators/__tests__/array.test.ts b/lib/validators/__tests__/array.test.ts index 6796a13..a0d78c1 100644 --- a/lib/validators/__tests__/array.test.ts +++ b/lib/validators/__tests__/array.test.ts @@ -11,18 +11,6 @@ describe("Array validators", () => { expect(arr.isArray(undefined)).toBe(false) }) - test("isEmpty", () => { - expect(arr.isEmpty([])).toBe(true) - expect(arr.isEmpty([1])).toBe(false) - expect(arr.isEmpty([1, 2])).toBe(false) - }) - - test("isNotEmpty", () => { - expect(arr.isNotEmpty([])).toBe(false) - expect(arr.isNotEmpty([1])).toBe(true) - expect(arr.isNotEmpty([1, 2])).toBe(true) - }) - test("length", () => { expect(arr.length([], 0)).toBe(true) expect(arr.length([1], 1)).toBe(true) diff --git a/lib/validators/array.ts b/lib/validators/array.ts index 131156d..f39914d 100644 --- a/lib/validators/array.ts +++ b/lib/validators/array.ts @@ -10,10 +10,10 @@ export const isArray = (input: unknown): input is T[] => Array.isArray(input) // Empty: check if the array is empty -export const isEmpty = (input: T[]): boolean => input.length === 0 +// export const isEmpty = (input: T[]): boolean => input.length === 0 -// Not Empty: check if the array is not empty -export const isNotEmpty = (input: T[]): boolean => input.length > 0 +// // Not Empty: check if the array is not empty +// export const isNotEmpty = (input: T[]): boolean => input.length > 0 // Length: check if the array length is equal to the expected length export const length = (input: T[], expected: number): boolean =>