From ec1590df11be54b65dcf2555c4260e87aa33efb1 Mon Sep 17 00:00:00 2001 From: Mahabub Date: Wed, 16 Oct 2024 20:34:29 +0600 Subject: [PATCH 1/5] refactor: updated author anchor link --- .vscode/settings.json | 3 ++- README.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 9aa72d0..fd472d4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,6 @@ "editor.codeActionsOnSave": { "source.fixAll.eslint": "always", "source.organizeImports": "always" - } + }, + "deno.enable": true } diff --git a/README.md b/README.md index 152c30f..caebcbe 100644 --- a/README.md +++ b/README.md @@ -79,4 +79,4 @@ Made with 💚 by @mahabubx7 Thanks, -~/[Mahabub](https://github.com/mahabubx7) +~/[Mahabub](https://mahabubx7.netlify.app) From 8dcf2defb841612fba3cebf36bd2c6b452ce5302 Mon Sep 17 00:00:00 2001 From: Mahabub Date: Wed, 16 Oct 2024 22:01:49 +0600 Subject: [PATCH 2/5] fix: added missing password validator --- lib/schemas/string.ts | 18 +++++++++++++++++- lib/validators/string.ts | 27 +++++++++++++-------------- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/lib/schemas/string.ts b/lib/schemas/string.ts index ff3e8e9..6f44eef 100644 --- a/lib/schemas/string.ts +++ b/lib/schemas/string.ts @@ -8,7 +8,7 @@ import { CountryNameKey, CountryNames, CountryPhoneCode } from "../helpers" import { stringChecker } from "../validators" -import { isString } from "../validators/string" +import { isString, PwdOptions } from "../validators/string" import { AkarBase } from "./base" export class AkarString extends AkarBase { @@ -44,6 +44,7 @@ export class AkarString extends AkarBase { private isCountry: boolean = false private isPostalCode: boolean = false private isPassport: boolean = false + private isPassword: null | PwdOptions = null private isCurrency: boolean = false private isDataUri: boolean = false private isMimeType: boolean = false @@ -215,6 +216,11 @@ export class AkarString extends AkarBase { return this } + password(options: PwdOptions): this { + this.isPassword = options + return this + } + currency(): this { this.isCurrency = true return this @@ -588,6 +594,16 @@ export class AkarString extends AkarBase { }) } + if ( + this.isPassword !== null && + !stringChecker.isPassword(input, this.isPassword) + ) { + errors.push({ + field: "string", + reason: "Invalid password" + }) + } + if (this.isCurrency && !stringChecker.isCurrency(input)) { errors.push({ field: "string", diff --git a/lib/validators/string.ts b/lib/validators/string.ts index 515c6a4..0f1b962 100644 --- a/lib/validators/string.ts +++ b/lib/validators/string.ts @@ -14,6 +14,18 @@ import { getCountryByNameValue } from "../helpers" +export interface PwdOptions { + uppercase?: boolean + minUppercase?: number + lowercase?: boolean + minLowercase?: number + number?: boolean + minNumber?: number + special?: boolean + minSpecial?: number + min?: number +} + // String: check the type export const isString = (input: unknown): input is string => typeof input === "string" @@ -225,20 +237,7 @@ export const isHSL = (input: string): boolean => /^hsl\(\d{1,3},\d{1,3}%,\d{1,3}%\)$/i.test(input) // Password: check if the string is a valid password -export const isPassword = ( - input: string, - options: { - uppercase?: boolean - minUppercase?: number - lowercase?: boolean - minLowercase?: number - number?: boolean - minNumber?: number - special?: boolean - minSpecial?: number - min?: number - } -): boolean => { +export const isPassword = (input: string, options: PwdOptions): boolean => { if (options.min && input.length < options.min) return false if ( options.minUppercase && From 21974387e3dbeefbe7ff1a258e787a80cd1f897b Mon Sep 17 00:00:00 2001 From: Mahabub Date: Wed, 16 Oct 2024 23:17:05 +0600 Subject: [PATCH 3/5] docs: added schema and validation guide --- docs/.vitepress/config.mts | 4 +- docs/greetings.md | 4 +- docs/guide/get-started.md | 22 +- docs/guide/infer-types.md | 36 +++ docs/guide/schema-validation.md | 395 ++++++++++++++++++++++++++++++++ docs/guide/schema.md | 64 ------ docs/guide/validation.md | 36 --- 7 files changed, 447 insertions(+), 114 deletions(-) create mode 100644 docs/guide/infer-types.md create mode 100644 docs/guide/schema-validation.md delete mode 100644 docs/guide/schema.md delete mode 100644 docs/guide/validation.md diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index aa54886..2457fef 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -51,8 +51,8 @@ export default defineConfig({ base: "/guide", items: [ { text: "Get Started", link: "/get-started" }, - { text: "Define Schema", link: "/schema" }, - { text: "Data Validation", link: "/validation" } + { text: "Schema & Validation", link: "/schema-validation" }, + { text: "Infer Types", link: "/infer-types" } ] }, { diff --git a/docs/greetings.md b/docs/greetings.md index 153c463..f0af2f2 100644 --- a/docs/greetings.md +++ b/docs/greetings.md @@ -1,8 +1,8 @@ # Welcome! ::: info -This package is almost ready for its first release `v1.0.0-beta`. -It is still in `development` and very soon will be available in npm. +This package is available with its latest release `v1.0.1`. +It is still in `development` and very soon will have its first stable/lts release. ::: If you consider this project useful or worth the attentions of developers, then please give its GitHub repository a star. Also, you can contribute to this open-source project. Follow the guidelines to contribute. diff --git a/docs/guide/get-started.md b/docs/guide/get-started.md index a70228f..3cf6933 100644 --- a/docs/guide/get-started.md +++ b/docs/guide/get-started.md @@ -17,23 +17,25 @@ To install the npm package, follow these steps: 1. Open your terminal. 2. Run the following command to install the package: - - +::: code-group -```sh -npm install akarjs +```sh [npm] +$ npm add akarjs ``` - +```sh [pnpm] +$ pnpm add akarjs +``` - +```sh [yarn] +$ yarn add akarjs +``` -```sh -yarn add akarjs +```sh [bun] +$ bun add akarjs ``` - - +::: 3. Verify the installation by checking the package version: diff --git a/docs/guide/infer-types.md b/docs/guide/infer-types.md new file mode 100644 index 0000000..4df0780 --- /dev/null +++ b/docs/guide/infer-types.md @@ -0,0 +1,36 @@ +# Infer Types + +## Summary + +While working in TypeScript, we often need to use types for various usages. Our library gives the opportunity to generate types from your defined schemas. + +## Table of Contents + +- [Infer Schema](#infer-schema) +- [Infer Schema With Conditions](#infer-schema-with-conditions) +- [Why Conditional Types?](#why-conditional-types) +- [Conclusion](#conclusion) + +## Infer Schema + +:::info +We are wotking on it. +::: + +## Infer Schema With Conditions + +:::info +We are wotking on it. +::: + +## Why Conditional Types? + +:::info +We are wotking on it. +::: + +## Conclusion + +:::info +We are wotking on it. +::: diff --git a/docs/guide/schema-validation.md b/docs/guide/schema-validation.md new file mode 100644 index 0000000..d76a475 --- /dev/null +++ b/docs/guide/schema-validation.md @@ -0,0 +1,395 @@ +# Schema & Validation + +## Summary + +We need to define schema for the validation process and each schema will contain its own rules, types-casts and other utilities. + +## Table of Contents + +- [Hello Schema](#hello-schema) +- [Array](#array) +- [Object](#object) +- [String](#string) +- [Number](#number) +- [Enum](#enum) +- [Boolean](#boolean) +- [Conclusion](#conclusion) + +## Hello Schema + +::: code-group + +```TypeScript +import { a } from "akarjs" + +// create user-schema +const user = a.object({ + name: a.string().min(4), + email: a.string().email(), + password: a + .string() + .password({ min: 6 }) +}) + +// parse your input with validation +// returns value (if success) or errors (if caught error) +console.log(user.parse({ + name: "Mahabub", + email: "mahabub@akar.js.org", + password: "123456" +})) // <-- success + +console.log(user.parse({ + name: "Mahabub", + // email: "mahabub@akar.js.org", + password: "12345" +})) // <-- errors +``` + +```JavaScript +import { a } from "akarjs" + +// create user-schema +const user = a.object({ + name: a.string().min(4), + email: a.string().email(), + password: a + .string() + .password({ min: 6 }) +}) + +// parse your input with validation +// returns value (if success) or errors (if caught error) +console.log(user.parse({ + name: "Mahabub", + email: "mahabub@akar.js.org", + password: "123456" +})) // <-- success + +console.log(user.parse({ + name: "Mahabub", + // email: "mahabub@akar.js.org", + password: "12345" +})) // <-- errors +``` + +::: + +**Output** + +```sh [TypeScript] +{ + value: { + name: "Mahabub", + email: "mahabub@akar.js.org", + password: "123456" + } +} + +{ + errors: [ + { + reason: "Email is required.", + field: "email", + value: undefined, + }, + { + reason: "Minimum length is 6 characters long.", + field: "password", + value: "12345", + }, + ] +} +``` + +## Array + +::: code-group + +```TypeScript +// an array of strings, minimum 2 items are requried +const hobbies = a.array(a.string()).min(2) // <-- array schema is always nested + +console.log(hobbies.parse(['traveling', 'gardening'])) // <-- success + +console.log(hobbies.parse(['traveling'])) // <-- errors +``` + +```JavaScript +// an array of strings, minimum 2 items are requried +const hobbies = a.array(a.string()).min(2) // <-- array schema is always nested + +console.log(hobbies.parse(['traveling', 'gardening'])) // <-- success + +console.log(hobbies.parse(['traveling'])) // <-- errors +``` + +::: + +**Output** + +```sh +{ + value: ['traveling', 'gardening'], +} + +{ + errors: [ + { + reason: "Minimum lenght is 2.", + value: ["traveling"] + field: "array", + } + ] +} +``` + +## Object + +::: code-group + +```TypeScript +// object specials +const createTodo = a.object({ + title: a.string().min(3), + completed: a.boolean().optional() +}) + +// tests +console.log(createTodo.parse({ + title: "Make a coffee!", + completed: true, +})) // <-- filling all of the properties + +console.log(createTodo.parse({ + title: "10 push-ups!", +})) // <-- ignoring optional properties +``` + +```JavaScript +// object specials +const createTodo = a.object({ + title: a.string().min(3), + completed: a.boolean().optional() +}) + +// tests +console.log(createTodo.parse({ + title: "Make a coffee!", + completed: true, +})) // <-- filling all of the properties + +console.log(createTodo.parse({ + title: "10 push-ups!", +})) // <-- ignoring optional properties +``` + +::: + +**Output** + +```sh +{ + value: { + title: "Make a coffee!", + completed: true + } +} + +{ + value: { + title: "10 push-ups!", + completed: undefined + } +} +``` + +## String + +::: info + +We already have a big list of validators for strings. Such as, `email`, `phone`, `otp`, `uuid`, `MongoDbId`, etc. But, still we are looking forward add more as requested. + +::: + +::: code-group + +```TypeScript +const ip = a.string().ip() // <-- expects an IP address only + +console.log(ip.parse('127.0.0.1')) // <-- success + +console.log(ip.parse('https://akar.js.org')) // <-- errors +``` + +```JavaScript +const ip = a.string().ip() // <-- expects an IP address only + +console.log(ip.parse('127.0.0.1')) // <-- success + +console.log(ip.parse('https://akar.js.org')) // <-- errors +``` + +::: + +**Output** + +```sh +{ + value: "127.0.0.1" +} + +{ + errors: [ + { + reason: "Invalid IP address.", + value: "https://akar.js.org", + field: "string" + } + ] +} +``` + +## Number + +::: code-group + +```TypeScript +const port = a.number().port() // <-- expects a valid port number + +console.log(port.parse(3000)) // <-- success +console.log(port.parse(80)) // <-- success +console.log(port.parse(65999)) // <-- errors +``` + +```JavaScript +const port = a.number().port() // <-- expects a valid port number + +console.log(port.parse(3000)) // <-- success +console.log(port.parse(80)) // <-- success +console.log(port.parse(65999)) // <-- errors +``` + +::: + +**Output** + +```sh +{ + value: 3000 +} + +{ + value: 80 +} + +{ + errors: [ + { + reason: "Invalid port number.", + value: 65999, + field: "number" + } + ] +} +``` + +## Enum + +::: warning + +If you face any issue or problem using this in JavaScript, please let us know. You can also create an issue for that. + +::: + +::: code-group + +```TypeScript +// enum schema can have default value +const status = a.enum(['pending', 'approved'] as const).default('pending') + +console.log(status.parse()) // <-- success +console.log(status.parse('pending')) // <-- success +console.log(status.parse('approved')) // <-- success +console.log(status.parse('wrong')) // <-- errors +``` + +```JavaScript +// enum schema can have default value +const status = a.enum(['pending', 'approved']).default('pending') + +console.log(status.parse()) // <-- success +console.log(status.parse('pending')) // <-- success +console.log(status.parse('approved')) // <-- success +console.log(status.parse('wrong')) // <-- errors +``` + +::: + +**Output** + +```sh +{ + value: 'pending' +} + +{ + value: 'pending' +} + +{ + value: 'approved' +} + +{ + errors: [ + { + reason: "Invalid enum value.", + value: 'wrong', + field: "enum" + } + ] +} +``` + +## Boolean + +::: code-group + +```TypeScript +const isAgreed = a.boolean().exact(true) // <-- exact enforces boolean to be exactly TRUE or FALSE + +console.log(isAgreed.parse(true)) // <-- success +console.log(isAgreed.parse(false)) // <-- errors +``` + +```JavaScript +const isAgreed = a.boolean().exact(true) // <-- exact enforces boolean to be exactly TRUE or FALSE + +console.log(isAgreed.parse(true)) // <-- success +console.log(isAgreed.parse(false)) // <-- errors +``` + +::: + +**Output** + +```sh +{ + value: true +} + +{ + errors: [ + { + reason: "Invalid boolean value.", + value: false, + field: "boolean" + } + ] +} +``` + +## Conclusion + +To get more details, please follow the API References. Here we have just tutorials about the schema defination and its usages. diff --git a/docs/guide/schema.md b/docs/guide/schema.md deleted file mode 100644 index 4a01001..0000000 --- a/docs/guide/schema.md +++ /dev/null @@ -1,64 +0,0 @@ -# Define Schema - -## Summary - -We need to define schema for the validation process and each schema will contain its own rules, types-casts and other utilities. - -## Table of Contents - -- [Hello Schema](#hello-schema) -- [Array](#array) -- [Object](#object) -- [String](#string) -- [Number](#number) -- [Enum](#enum) -- [Boolean](#boolean) -- [Conclusion](#conclusion) - -## Hello Schema - -::: info -We are wotking on it. -::: - -## Array - -::: info -We are wotking on it. -::: - -## Object - -::: info -We are wotking on it. -::: - -## String - -::: info -We are wotking on it. -::: - -## Number - -::: info -We are wotking on it. -::: - -## Enum - -::: info -We are wotking on it. -::: - -## Boolean - -::: info -We are wotking on it. -::: - -## Conclusion - -::: info -We are wotking on it. -::: diff --git a/docs/guide/validation.md b/docs/guide/validation.md deleted file mode 100644 index e6f7db3..0000000 --- a/docs/guide/validation.md +++ /dev/null @@ -1,36 +0,0 @@ -# Data Validation - -## Summary - -To validate you data, you must have the schema defined at first. Then you can use it to validate your data as payload or input. - -## Table of Contents - -- [Parser](#parser) -- [Result](#result) -- [Errors](#errors) -- [Conclusion](#conclusion) - -## Parser - -:::info -We are wotking on it. -::: - -## Result - -:::info -We are wotking on it. -::: - -## Errors - -:::info -We are wotking on it. -::: - -## Conclusion - -:::info -We are wotking on it. -::: From 8497c58f2b2ca4829480dfba9bedb71ab63017f0 Mon Sep 17 00:00:00 2001 From: Mahabub Date: Wed, 16 Oct 2024 23:43:42 +0600 Subject: [PATCH 4/5] docs: added infer-types guide --- docs/guide/infer-types.md | 84 +++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 12 deletions(-) diff --git a/docs/guide/infer-types.md b/docs/guide/infer-types.md index 4df0780..f6d227a 100644 --- a/docs/guide/infer-types.md +++ b/docs/guide/infer-types.md @@ -13,24 +13,84 @@ While working in TypeScript, we often need to use types for various usages. Our ## Infer Schema -:::info -We are wotking on it. -::: +```TypeScript +import { a, InferSchema } from 'akarjs' + +// Sample | for example, an object-schema +const createTodo = a.object({ + title: a.string().min(3), + completed: a.boolean().optional(), +}) + +type CreateTodo = InferSchema + +/* +/// Infers as: + +type CreateTodo { + title: string; + completed: boolean | undefined; +} +*/ + +``` ## Infer Schema With Conditions -:::info -We are wotking on it. -::: +```TypeScript +import { a, InferSchemaWithConditions } from 'akarjs' + +// conditional for types +const updateUser = a.object({ + name: a.string().min(3), + age: a.number().optional(), + role: a.enum(['customer', 'vendor'] as const).optional(), +}) + +type UpdateUser = InferSchemaWithConditions + +/* +/// Infers as: + +type UpdateUser { + name: string; +} & { + age?: number; +} & { + role?: 'customer' | 'vendor'; +} +*/ + +``` ## Why Conditional Types? -:::info -We are wotking on it. -::: +We have noticed that when you infer a type and try to use it, you might face a problem. For example, + +```TypeScript +const updateUser = a.object({ + name: a.string().min(3), + age: a.number().optional(), + role: a.enum(['customer', 'vendor'] as const).optional(), +}) + +type UpdateUserT1 = InferSchema +type UpdateUserT2 = InferSchemaWithConditions + +const user1: UpdateUserT1 = { + name: "Mahabub", + age: undefined, // property must be declared, otherwise it might make problems + role: undefined, // property must be declared, otherwise it might make problems +}; + +const user2: UpdateUserT2 = { + name: "Mahabub", + // no need to add optional properties + // Enjoy 👍 +}; + +``` ## Conclusion -:::info -We are wotking on it. -::: +In conclusion, leveraging the power of TypeScript with our library allows for robust type inference directly from your schemas. This not only ensures type safety but also enhances code maintainability and readability. By using conditional types, you can further refine your type definitions, making your code more flexible and easier to work with. We hope this guide helps you understand how to effectively use inferred types in your projects. From 797926f505b7e7cff1e9a088bb9c1c85dbcd6b11 Mon Sep 17 00:00:00 2001 From: Mahabub Date: Thu, 17 Oct 2024 00:06:21 +0600 Subject: [PATCH 5/5] docs: guides are completed --- docs/api/array.md | 2 +- docs/api/boolean.md | 2 +- docs/api/enum.md | 2 +- docs/api/index.md | 4 ++-- docs/api/number.md | 2 +- docs/api/object.md | 2 +- docs/api/string.md | 2 +- docs/greetings.md | 2 +- docs/guide/get-started.md | 6 ++++++ docs/guide/index.md | 2 +- docs/guide/schema-validation.md | 2 +- docs/team.md | 2 +- 12 files changed, 18 insertions(+), 12 deletions(-) diff --git a/docs/api/array.md b/docs/api/array.md index cd11081..8a49575 100644 --- a/docs/api/array.md +++ b/docs/api/array.md @@ -1,5 +1,5 @@ # Array ::: info -We are wotking on it. +Work in progress ⏳ ::: diff --git a/docs/api/boolean.md b/docs/api/boolean.md index 6c90eb4..2786843 100644 --- a/docs/api/boolean.md +++ b/docs/api/boolean.md @@ -1,5 +1,5 @@ # Boolean ::: info -We are wotking on it. +Work in progress ⏳ ::: diff --git a/docs/api/enum.md b/docs/api/enum.md index f3950fb..ced2b34 100644 --- a/docs/api/enum.md +++ b/docs/api/enum.md @@ -1,5 +1,5 @@ # Enum ::: info -We are wotking on it. +Work in progress ⏳ ::: diff --git a/docs/api/index.md b/docs/api/index.md index 1554f4e..27d6ff8 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -4,6 +4,6 @@ Welcome to the `Akar.js`. This page will walk you through the available API references of this library. -:::info -We are wotking on it. +::: info +Work in progress ⏳ ::: diff --git a/docs/api/number.md b/docs/api/number.md index 7685760..0cf9515 100644 --- a/docs/api/number.md +++ b/docs/api/number.md @@ -1,5 +1,5 @@ # Number ::: info -We are wotking on it. +Work in progress ⏳ ::: diff --git a/docs/api/object.md b/docs/api/object.md index dc1cb32..34db6da 100644 --- a/docs/api/object.md +++ b/docs/api/object.md @@ -1,5 +1,5 @@ # Object ::: info -We are wotking on it. +Work in progress ⏳ ::: diff --git a/docs/api/string.md b/docs/api/string.md index 69d858f..dc0be9b 100644 --- a/docs/api/string.md +++ b/docs/api/string.md @@ -1,5 +1,5 @@ # String ::: info -We are wotking on it. +Work in progress ⏳ ::: diff --git a/docs/greetings.md b/docs/greetings.md index f0af2f2..084b15d 100644 --- a/docs/greetings.md +++ b/docs/greetings.md @@ -1,7 +1,7 @@ # Welcome! ::: info -This package is available with its latest release `v1.0.1`. +This package is available with its latest release `v1.0.1` or later. It is still in `development` and very soon will have its first stable/lts release. ::: diff --git a/docs/guide/get-started.md b/docs/guide/get-started.md index 3cf6933..2f2572c 100644 --- a/docs/guide/get-started.md +++ b/docs/guide/get-started.md @@ -17,6 +17,12 @@ To install the npm package, follow these steps: 1. Open your terminal. 2. Run the following command to install the package: +::: tip + +We are assuming that `Deno ^2.0` runtime can use our package with its built-in node.js runtime supports. + +::: + ::: code-group ```sh [npm] diff --git a/docs/guide/index.md b/docs/guide/index.md index c204fb5..a7431e9 100644 --- a/docs/guide/index.md +++ b/docs/guide/index.md @@ -6,4 +6,4 @@ We recommend **node.js** `>=20.x` as the runtime to use our library without any ## Conclusion -This pkg was developed in Node.js runtime. Still it can be used in other `node.js` like runtimes such as `bun` or `deno 2.0` _(coming soon)_ +This pkg was developed in Node.js runtime. Still it can be used in other `node.js` like runtimes such as `bun` or `deno ^2.0` diff --git a/docs/guide/schema-validation.md b/docs/guide/schema-validation.md index d76a475..a0b1382 100644 --- a/docs/guide/schema-validation.md +++ b/docs/guide/schema-validation.md @@ -298,7 +298,7 @@ console.log(port.parse(65999)) // <-- errors ::: warning -If you face any issue or problem using this in JavaScript, please let us know. You can also create an issue for that. +If you face any issue or problem using this in JavaScript/TypeScript, please let us know. You can also create an issue for that. ::: diff --git a/docs/team.md b/docs/team.md index f064e1f..5f52394 100644 --- a/docs/team.md +++ b/docs/team.md @@ -16,7 +16,7 @@ const members = [ title: 'Creator', links: [ { icon: 'github', link: 'https://github.com/mahabubx7' }, - // { icon: '', link: ''}, + { icon: 'twitter', link: 'https://x.com/iam_mahabub'}, { icon: 'linkedin', link: 'https://linkedin.com/in/mahabubx7' } ] },