[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Desktop (please complete the following information):**\n - OS: [e.g. iOS]\n - Browser [e.g. chrome, safari]\n - Version [e.g. 22]\n\n**Smartphone (please complete the following information):**\n - Device: [e.g. iPhone6]\n - OS: [e.g. iOS8.1]\n - Browser [e.g. stock browser, safari]\n - Version [e.g. 22]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where the package manifests are located.\n# Please see the documentation for all configuration options:\n# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates\n\nversion: 2\nupdates:\n  - package-ecosystem: \"npm\" # See documentation for possible values\n    directory: \"/\" # Location of package manifests\n    schedule:\n      interval: \"weekly\"\n\n"
  },
  {
    "path": ".github/workflows/main.yml",
    "content": "# This is a basic workflow to help you get started with Actions\n\nname: CI\n\n# Controls when the action will run. \non:\n  # Triggers the workflow on push or pull request events but only for the main branch\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: [ main ]\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\n# A workflow run is made up of one or more jobs that can run sequentially or in parallel\njobs:\n  # This workflow contains a single job called \"build\"\n  build:\n    # The type of runner that the job will run on\n    runs-on: ubuntu-latest\n\n    # Steps represent a sequence of tasks that will be executed as part of the job\n    steps:\n      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it\n      - uses: actions/checkout@v3\n      - uses: actions/setup-node@v3\n        with:\n          node-version: 18\n\n      # Runs a single command using the runners shell\n      - name: Install dependencies\n        run: yarn install\n\n      # Runs a set of commands using the runners shell\n      - name: Run all tests\n        run: yarn test\n\n      # Runs a set of commands using the runners shell\n      - name: Run typescript check\n        run: yarn tsc --noEmit"
  },
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n*.lcov\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# TypeScript v1 declaration files\ntypings/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Microbundle cache\n.rpt2_cache/\n.rts2_cache_cjs/\n.rts2_cache_es/\n.rts2_cache_umd/\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n.env.test\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n\n# Next.js build output\n.next\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n\n# Gatsby files\n.cache/\n# Comment in the public line in if your project uses Gatsby and *not* Next.js\n# https://nextjs.org/blog/next-9-1#public-directory-support\n# public\n\n# vuepress build output\n.vuepress/dist\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# TernJS port file\n.tern-port\n\nbuild\n\n.vscode/\n\npackages/*/*.js\npackages/*/*.d.ts\npackages/*/tsconfig.build.tsbuildinfo\n\n.npmrc\n.nx/\n"
  },
  {
    "path": ".husky/pre-commit",
    "content": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nnpm run check:types\nnpx lint-staged\n"
  },
  {
    "path": ".husky/pre-push",
    "content": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nnpm run test\n"
  },
  {
    "path": ".prettierignore",
    "content": "# Ignore everything:\n/*\n/__snapshots__/*\n*.ts.snap\n\n# Except:\n!/lib\n!/example\n!/tests\n!jest.config.ts\n!package.json\n!tsconfig.json\n!tsconfig.lib.json\n!webpack.config.ts\n\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n\t\"useTabs\": true,\n\t\"arrowParens\": \"always\",\n\t\"singleQuote\": true,\n\t\"semi\": true,\n    \"bracketSpacing\": true,\n    \"endOfLine\": \"lf\",\n    \"tabWidth\": 4\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n## Unreleased\n\n---\n\n## Released\n\n---\n\n### [4.1.0] - 2024-12-15\n\n#### Feat\n\n- Atualizando lib core para nova versão\n- rich-domain v1.25.0\n\n---\n\n### [4.0.5] - 2024-11-28\n\n### Fix\n\n- update rich-domain lib to check nullish type: now 'create' return a possibly null value in Result instance.\n\n---\n\n### [4.0.4] - 2024-09-26\n\n### Fix\n\n- Corrected `\"files\"` in `package.json` to include `utils.js` and `utils.d.ts`, resolving module not found errors during compilation in email and password.\n\n---\n\n### [4.0.2] - 2024-06-26\n\n### Fix\n\n- update: update rich-domain to v1.23.3\n\n---\n\n\n### [4.0.0] - 2024-05-31\n\n### Refactor (Break Change)\n\n- refactor: change lib to individual packages\n\n---\n\n### [3.9.0] - 2024-04-28\n\n### Update (Break Change)\n\n- Update core to v1.23.0\n- check [Core Changelog](https://github.com/4lessandrodev/rich-domain/blob/main/CHANGELOG.md)\n\n---\n\n## Released\n\n### [3.8.3] - 2024-04-13\n\n### Update\n\n- Update core\n- Added support to multi context name\n- Details [Commit](https://github.com/4lessandrodev/rich-domain/commit/00db292f0604469c8bf2f2fddf6460901a084cc6)\n\n```ts\n\n// Example Usage\nconst context = Context.events();\n\nconst handler = (event) => console.log(event);\n\n// Subscribing to events under different contexts\ncontext.subscribe('Context-A:SIGNUP', handler);\ncontext.subscribe('Context-B:SIGNUP', handler);\ncontext.subscribe('Context-C:SIGNUP', handler);\ncontext.subscribe('Context-B:NOTIFY', handler);\ncontext.subscribe('Context-B:SEND-EMAIL', handler);\n\n// Dispatching events to specific contexts\n// Dispatches the SIGNUP event to Context-B\ncontext.dispatchEvent('Context-B:SIGNUP');\n// Dispatches the SIGNUP event to all contexts\ncontext.dispatchEvent('*:SIGNUP');\n// Dispatches all events to all contexts. Not recommended\ncontext.dispatchEvent('*:*');\n// Dispatches all events under Context-B\ncontext.dispatchEvent('Context-B:*');\n\n```\n\n---\n\n### [3.8.2] - 2024-04-12\n\n### Update\n\n- Update core\n- Added support to global events [ChangeLog](https://github.com/4lessandrodev/rich-domain/pull/139)\n\n---\n\n### [3.8.1] - 2024-03-18\n\n### Update\n\n- Update core\n- Fix logger messages\n\n---\n\n### [3.8.0] - 2024-03-18\n\n### Update\n\n- update deps core to v1.20.0 see [changes](https://github.com/4lessandrodev/rich-domain/blob/main/CHANGELOG.md)\n\n---\n\n### [3.7.2] - 2024-03-15\n\n### Update\n\n- update deps\n- added support to nodejs v21\n\n---\n\n### [3.7.1] - 2023-12-15\n\n### Update\n\n- update deps\n\n---\n\n### [3.7.0] - 2023-09-30\n\n### Update\n\n- Update core\n- update deps\n- rich-domain: update lib core to 1.19.0\n- remove support for deprecated history method\n- improve performance and save memory usage\n\n---\n\n### [3.6.4] - 2023-08-24\n\n### Update\n\n- Update core\n- update deps\n- rich-domain: update lib core to 1.18.4\n\n---\n\n### [3.6.3] - 2023-07-30\n\n### Update\n\n- Update core\n- rich-domain: update lib core to 1.18.3 #272 #282\n\n---\n\n### [3.6.2] - 2023-07-09\n\n### Update\n\n- Update core\n- rich-domain: update lib core to 1.18.2 #272\n\n---\n\n---\n### [3.6.1] - 2023-06-30\n\n### Update\n\n- Update core\n- rich-domain: update lib core to 1.18.1\n\n---\n### [3.6.0] - 2023-04-21\n\n### Update\n\n- Update core\n- rich-domain: update lib core to 1.18.0 [More](https://github.com/4lessandrodev/rich-domain/blob/main/CHANGELOG.md)\n\n\n---\n### [3.5.3] - 2023-02-18\n\n### Update\n\n- Update core\n- rich-domain: update lib core to 1.17.3\n\n---\n\n### [3.5.2] - 2023-02-18\n\n### Changed\n\n- validation to `url.value-object` use URL default validation and remove regex. by @ArturHamannRonconi\n\n### Added \n\n- added separator as optional param to `getInitials`method from `user-name.value-object`\n\n---\n### [3.5.1] - 2023-01-27\n\n### Update\n\n- Update core\n- rich-domain: update lib core to 1.17.1\n\n---\n### [3.5.0] - 2023-01-21\n\n### Update\n\n- Update core\n\n### Breaking Change\n- rich-domain: update lib core to 1.17.0 check on [pull request 33](https://github.com/4lessandrodev/rich-domain/pull/33)\n\n```ts\n\n// Example using set now\n\nconst changed = user.set(\"name\").to(age);\n\nconsole.log(changed);\n\n> true\n\n```\n\n```ts\n\n// Example using clone now\n\nconst copy = user.clone();\n\nconsole.log(copy.get(\"name\").get(\"value\"))\n\n> \"Jane Doe\"\n\n```\n\n---\n### [3.4.7] - 2023-01-19\n\n### Update\n\n- rich-domain: update lib core to 1.16.2\n\n---\n### [3.4.6] - 2023-01-18\n\n### Update\n\n- rich-domain: update lib core to 1.16.1\n\n---\n### [3.4.5] - 2023-01-14\n\n### Changed\n\n- date.value-object: rename method from `isEqual` to `isEqualDate`\n\n### Update\n\n- rich-domain: update lib core to 1.16.0\n- Entity: added method isEqual to compare current instance with another one.\n- ValueObject: added method isEqual to compare current instance with another one. [Issue 27](https://github.com/4lessandrodev/rich-domain/issues/27)\n\n---\n\n### [3.4.4] - 2023-01-12\n\n### Added\n\n- custom-string.value-object: By: [VinnyLima](https://github.com/VinnyLima)\n- removeSpecialChars and onlyNumbers: [Issue 223](https://github.com/4lessandrodev/types-ddd/issues/223)\n- email.value-object: added MESSAGE as customizable value\n\n---\n\n### [3.4.3] - 2023-01-05\n\n### Updated\n\n- rich-domain: update lib core to 1.15.2\n\n---\n\n### [3.4.2] - 2023-01-03\n\n### Fix\n\n- node version: update requirements. node version required >=16 and < 19\n\n---\n\n### [3.4.1] - 2023-01-03\n\n### Fix\n\n- user-name.value-object: remove empty spaces. By: [VinnyLima](https://github.com/VinnyLima)\n\n---\n### [3.4.0] - 2022-12-25\n\n### Update\n\n- rich-domain: update lib core to 1.15.0\n- value-objects: added MESSAGE attribute to instance\n\nNow its possible to customize error message\n\nExample:\n\n```ts\n\n// custom-user-name.ts\n\nimport { UserNameValueObject } from 'types-ddd';\n\nReflect.set(UserNameValueObject, \"MIN_LENGTH\", 3);\nReflect.set(UserNameValueObject, \"MAX_LENGTH\", 20);\nReflect.set(UserNameValueObject, \"MESSAGE\", \"Username must be a maximum of 3 and a minimum of 20 characters\");\n\nconst CustomName = UserNameValueObject;\n\nexport CustomName; // > import this to create your user name\nexport default CustomName;\n\n```\n\n---\n\n### [3.3.7] - 2022-11-27\n\n### Update\n\n- rich-domain: update lib core to 1.14.6\n\n---\n\n### [3.3.6] - 2022-11-25\n\n### Update\n\n- rich-domain: update lib core to 1.14.5\n\n---\n\n### [3.3.5] - 2022-11-22\n\n### Update\n\n- rich-domain: update lib core to 1.14.4\n\n---\n\n### [3.3.4] - 2022-11-22\n\n### Update\n\n- rich-domain: update lib core to 1.14.3\n\n---\n\n### [3.3.3] - 2022-11-17\n\n### Changed\n\n- Ok and Fail: ensure export from lib\n\n---\n\n### [3.3.2] - 2022-11-07\n\n### Changed\n\n- chore: deps - update deps\n\n---\n\n### [3.3.1] - 2022-11-03\n\n### Fixed\n\n- value-objects: calc validation\n\n---\n### [3.3.0] - 2022-10-05\n\n### Changed\n\n- value-objects: implement customization for value objects\n\n---\n### [3.2.2] - 2022-10-03\n\n### Changed\n\n- result: implement freeze result instance\n- password: define protected props as MAX_LENGTH and MIN_LENGTH\n- update deps: rich-domain\n\n---\n### [3.2.1] - 2022-09-26\n\n### Changed\n\n- update deps: rich-domain\n\n\n- refactor: Fail\n- refactor: Ok\n- refactor: Result.Ok\n- refactor: Result.fail\n\nChange generic types order for `Result.fail` and `Result.Ok`\n\nNow each method has your own order\nExample: \n\n```ts\n\n// for implementation: \nIResult<Payload, Error, MetaData>;\n\n// before the generic order was the same for both method.\n// now for \nResult.Ok\n\n// the generic order is \nResult.Ok<Payload, MetaData, Error>(payload metaData);\n\n// for \nResult.fail \n\n//the generic order is \nResult.fail<Error, MetaData, Payload>(error, metaData);\n\n```\n\nChanges made on Ok\n\n```ts\n\nimport { Ok } from 'rich-domain';\n\n// simple use case for success. no arg required\nreturn Ok();\n\n// arg required \n\nreturn Ok<string>('my payload');\n\n// arg and metaData required \n\ninterface MetaData {\n  arg: string;\n}\n\nreturn Ok<string, MetaData>('payload', { arg: 'sample' });\n\n```\n\nChanges made on Fail\n\n```ts\n\nimport { Fail } from 'rich-domain';\n\n// simple use case for success. no arg required\nreturn Fail();\n\n// arg required \n\nreturn Fail<string>('my payload');\n\n// arg and metaData required \n\ninterface MetaData {\n  arg: string;\n}\n\nreturn Fail<string, MetaData>('payload', { arg: 'sample' });\n\n```\n\n---\n### [3.2.0] - 2022-09-26\n\n### Added\n\n- update deps: rich-domain\n- feat: implement function Fail \n- feat: implement function Ok\n\n---\n### [3.1.5] - 2022-09-26\n\n### Fixed\n\n- EmailValueObject: remove regex and added function validation\n\n---\n### [3.1.4] - 2022-09-20\n\n### Update\n\ndeps: update dependencies\n\n- rich-domain to v1.12.0\n\n---\n### [3.1.3] - 2022-09-03\n\n### Update\n\ndeps: update dependencies\n\n- rich-domain to v1.11.2\n- typescript to 4.8.2\n\n---\n### [3.1.2] - 2022-08-14\n\n### Update\n\ndocs: update readme and documentation\ndeps: update dependencies \n\n### Added\n\nci: install dependabot to check deps\n\n---\n### [3.1.1] - 2022-08-14\n\n### Update\n\ndocs: update readme and documentation\n\n---\n### [3.1.0] - 2022-08-10\n\n### Changed\n\n- deps: update dependencies rich-domain to version 1.11.0\n\nChange order validation args in value objects\n\n```ts\n\n  // from\n  validation<Key extends keyof Props>(key: Key, value: Props[Key]): boolean {};\n\n  // to\n  validation<Key extends keyof Props>(value: Props[Key], key: Key): boolean {};\n\n```\n\n---\n\n### [3.0.2] - 2022-08-07\n\n### Update\n\n- deps: update dependencies rich-domain to version 1.10.0\n\n---\n\n### [3.0.1-beta.0] - 2022-08-05\n\n### Update\n\n- deps: update dependencies rich-domain to version 1.9.0\n\n\n---\n\n### [3.0.0-beta.0] - 2022-08-05\n\n### Update\n\n- deps: update dependencies\n\n\n---\n\n### [3.0.0-beta] - 2022-08-04\n\n### Change\n\n- change core (**breaking changes**). using now rich-domain lib [npm rich-domain](https://www.npmjs.com/package/rich-domain)\n\n\n---\n\n### [2.12.1] - 2022-07-18\n\n### Update\n\n- deps: update dependencies\n\n---\n\n### [2.12.0] - 2022-04-18\n\n### Changes\n\n- TSProxy: change context param from function to instance of class [pull request](https://github.com/4lessandrodev/types-ddd/pull/144)\n- deps: update dependencies\n\n---\n\n### [2.11.0] - 2022-04-02\n\n### Added\n\n- TSProxy: added abstract class as proxy implementation [pull request](https://github.com/4lessandrodev/types-ddd/pull/142)\n\n---\n\n### [2.10.3] - 2022-03-28\n\n### Changes\n\n- logger: make instance a singleton\n\n---\n\n### [2.10.2] - 2022-03-28\n\n### Changes\n\n- logger: update configs\n### Update\n\n- deps: update dependencies\n\n---\n\n### [2.10.1] - 2022-03-23\n\n### Update\n\n- deps: update dependencies\n\n---\n### [2.10.0] - 2022-02-27\n\n### Fixed\n\n- toObject: return string when there is a domainId as value-object attribute\n\n---\n### [2.9.13] - 2022-02-14\n\n### Fixed\n\n- toObject: added support to convert a simple object on entity\n\n---\n\n### [2.9.11] ~ [2.9.12] - 2022-02-13\n\n### Changed\n\n- toObject: added support to convert a value object inside another one\n\n---\n\n### [2.9.9] ~ [2.9.10] - 2022-02-13\n\n### Changed\n\n- update dependencies\n- update documentation\n\n---\n### [2.9.8] - 2022-02-09\n\n### Fixed\n\n- toObject: fix adding support for string, boolean and numbers to domain entity attributes on call toObject method.\n- create: ensure all domain entity implements create method\n\n### Added\n\n- clone: added method to clone a domain entity\n\n---\n### [2.9.7] - 2022-01-31\n\n### Added\n\n- logs deactivation: now its possible deactivate all logs;\n```sh\nNODE_ENV=production # automatically turn off all logs\nTYPES_DDD_LOGS=off # manual turn off logs\nTYPES_DDD_LOGS=error # show only errors log\nTYPES_DDD_LOGS=info # show only info log\nTYPES_DDD_LOGS=warn # show only warn log\n```\n---\n### [2.9.6] - 2022-01-30\n\n### Fixed\n\n- toObject: ensure to convert a moderately complex value object\n\n---\n\n### [2.9.5] - 2022-01-30\n\n### Added \n\n- toObject: update types on entity.toObject method\n\n### Changed\n\n- update and change some documentation and examples\n- mark IMapper interface as deprecated tool. Use TMapper instead\n\n---\n\n### [2.9.4] - 2022-01-29\n\n### Added \n\n- Imports: Create shortcuts for imports : Issue #114\n\n---\n\n### [2.9.3] - 2022-01-21\n\n### Fixed \n\n- AutoMapper: get string value when prop is DomainId or ShortDomainId\n\n---\n\n### [2.9.1] ~ [2.9.2] - 2022-01-21\n\n### Changed \n\n- DomainId: added clone method to create a new id from an instance\n- ShortDomainId: added clone method to create a new id from an instance\n\n### Added\n\n- Available AutoMapper to convert Entity, Aggregate and ValueObject from domain instance to a persistence model\n\n---\n\n### [2.9.0] - 2022-01-21\n\n### Changed \n\n- DomainId and ShortDomainId: added property isNew to identify if is a new id\n- Entity, Aggregate and ValueObject: added method toObject to convert domain instance to a persistence model\n\n### Added\n\n- Available AutoMapper to convert Entity, Aggregate and ValueObject from domain instance to a persistence model\n\n---\n\n### [2.8.8] - 2021-12-29\n\n---\n### Added\n\n- Entity: hasSomeTypes method to validate different types from instance keys\n\n### Changed \n\n- Entity: isSome method > new accepted type: 'null'\n- Entity: isAll method > new accepted type: 'null'\n\n\n### [2.8.7] - 2021-12-28\n\n---\n\n### Added\n\n- State: addManyState<T, E> method add many results to state and return unique keys\n- State: getStateByKeys<T, E> method get many results by keys\n\n\n### [2.8.6]- 2021-12-26\n\n---\n\n### Added\n\n- Entity: toObject<T, E> method transform instance in persistence object\n\n\n### [2.8.5]  - 2021-12-25\n\n---\n\n### Added\n\n- Entity: added method checkProps to entity instance\n\n### [2.8.4]  - 2021-12-24\n\n---\n\n### Changed \n\n- State: define exists method as protected\n\n### Added \n\n- State: added callback on state\n\n### [2.8.3]  - 2021-12-23\n\n---\n\n### Changed \n\n- State: define exists method as protected\n\n### [2.8.2]  - 2021-12-22\n\n---\n\n### Changed \n\n- Mapper: rename to State\n- Mapper: added exists method\n\n### [2.8.1]  - 2021-12-22\n\n---\n\n### Changed \n\n- Mapper: added logger if state key does not exits\n\n### [2.8.0]  - 2021-12-22\n\n---\n\n### Changed \n\n- static method on domain entities\n- buildFromDto > change to build\n- buildFromModel > change to build\n- buildToModel > change to build\n- IMapper2 > change to TMapper\n\n### [2.7.15]  - 2021-12-21\n\n---\n\n### Added \n\n- static method on domain entities\n- buildFromDto\n- buildFromModel\n- buildToModel\n\n### [2.7.14]  - 2021-12-21\n\n---\n\n### Added \n\n- abstract class Mapper with state management methods\n- IMappers interface with new methods\n\n### [2.7.12] - [2.7.13]  - 2021-12-14\n\n---\n\n### Changed\n\n- DomainId and ShortDomainId: make both compatible\n\n### [2.7.11] - 2021-12-14\n\n---\n\n### Changed\n\n- BaseDomainEntity: ID accept DomainId or ShortDomainId\n- Entity: getHashCode - now returns uid value base value added to ID\n- Breaking change - Remove methods from DomainId:\n- toShort()\n- shortUid\n\n### [2.7.10] - 2021-12-14\n\n---\n### Fix \n\n- ShortDomainId: export resource\n\n### [2.7.9] - 2021-12-14\n\n---\n### Added \n\n- ShortDomainId: default short domain id - 16 bit\n\n### [2.7.8] - 2021-11-22\n\n---\n\n### Fixed\n\n- PasswordValueObject: validate if instance value already is encrypted.\n\n\n### [2.7.7] - 2021-11-22\n\n---\n\n### Changed\n\n- DimensionValueObject: now update methods returns updated instance.\n- PasswordValueObject: now encrypt method returns updated instance.\n- UserNameValueObject: now capitalize method returns updated instance.\n- WeightValueObject: now update methods returns updated instance.\n\n### [2.7.6] - 2021-11-21\n\n---\n### Fixed\n\n- util: change regex to validate email (includes dot as valid char).\n\n### [2.7.5] - 2021-10-11\n\n---\n### Changed\n\n- entities and aggregates: getHashCode > combination of class name and id. Now using short uid.\n\n### Fixed\n\n- lib: publish only dist to keep lib small\n\n### [2.7.4] - 2021-10-09\n\n---\n### Fixed\n\n- removeUndefinedKeysFromObject: do not remove dates\n\n### [2.7.3] - 2021-10-08\n\n---\n### Changed\n\n- DateValueObject: added comparators methods\n\n### [2.7.2] - 2021-10-08\n\n---\n### Changed\n\n- DateValueObject: added validation on create a new instance\n\n### [2.7.1] - 2021-10-08\n\n---\n### Added \n\n- DateValueObject\n\n### [2.7.0] - 2021-10-06\n\n---\n### Changed\n\n- DomainId > change getters method\n\n### [2.6.2] ~ [2.6.4] - 2021-10-06\n\n---\n### Changed\n\n- DomainId > added toShort method\n- DomainId > toShort method. Now you can choose length\n\n### [2.6.1] - 2021-09-30\n\n---\n### Changed\n\n- getUndefinedKeysAsObject > added new option to return as value\n\n### [2.6.0] - 2021-09-29\n\n---\n### Changed\n\n- CurrencyValueObject > added functions to compare values\n- getUndefinedKeysAsObject > added option to get path as string\n\n### [2.5.7] ~ 2.5.10 - 2021-09-25\n\n---\n\n### Added\n\n- removeUndefinedKeysFromObject\n\n### [2.5.6] - 2021-09-23\n\n---\n### Changed\n\n- dist > update build\n\n### [2.5.5] - 2021-09-24\n\n---\n### Changed\n\n- getUndefinedKeysAsObject > define value to be applied\n\n### [2.5.4] - 2021-09-24\n\n---\n### Changed\n\n- DimensionValueObject > validate unit before create value object\n- WeightValueObject > validate unit before create value object\n\n### [2.5.3] - 2021-09-22\n\n---\n### Changed\n\n- DimensionEntity > changed to value object: DimensionValueObject\n- WeightEntity > changed to value object: WeightValueObject\n\n### [2.5.2] - 2021-09-21\n\n---\n### Changed\n\n- dist: remove unused files on dist\n\n### [2.5.1] - 2021-09-20\n\n---\n### Changed\n\n- Lib utils: Imports path\n\n### Added\n\n- WeightUnitValueObject\n- UnitOfMeasureValueObject\n- DimensionEntity\n- WeightEntity\n\n### [2.5.0] - 2021-09-18\n\n---\n### Changed\n\n- PinValueObject: Define pin props as optional\n- Rename folder: from src to lib\n\n### Added\n\n- CPFValueObject\n- CNPJValueObject\n- CustomStringValueObject\n- CustomNumberValueObject\n- HEXColorValueObject: Ensure don't generate light color like white\n- RGBColorValueObject: Ensure don't generate light color like white\n\n### [2.4.2] ~ [2.4.10] - 2021-09-09\n\n---\n### Fixed\n\n- Update dependencies\n\n### [2.4.1] - 2021-09-09\n\n---\n### Fixed\n\n- UrlValueObject: export value object\n\n### [2.4.0] - 2021-09-07\n\n---\n### Changed\n\n- PinValueObject: util value object\n\n### [2.3.6] - 2021-08-29\n\n---\n### Changed\n\n- CurrencyValueObject: docs - identify max safe number\n\n### [2.3.5] - 2021-08-29\n\n---\n\n### Changed\n\n- Result - Change default generic type on `combine` method to `unknown` instead `any`\n\n\n### [2.3.4] - 2021-08-29\n\n---\n\n### Changed\n\n- ChangesObserver - Fix added possibility to get all added results `getAllAddedResults`\n\n### [2.3.3] - 2021-08-28\n\n---\n\n### Changed\n\n- Result - Fix possibility to return a void instance. Create a specific method `Result.success`\n\n### [2.3.2] - 2021-08-28\n\n---\n\n### Changed\n\n- Result - Fix possibility to return a void instance\n\n### [2.3.1]- 2021-08-28\n\n---\n\n### Changed\n\n- Result - added an internationalization error message\n\n### [2.3.0] - 2021-08-27\n\n---\n\n### Added\n\n- StatusCodeEnum\n\n### Changed\n\n- Result - provide an enum as string declaration instead number\n\n### [2.2.3] - 2021-08-24\n\n---\n\n### Added\n\n- SpecificationComposite\n\n### Changed\n\n- IBaseRepository - rename params and doc comments\n\n### [2.2.2] - 2021-08-19\n\n---\n\n### Fixed\n\n- colorGenerator\n\n### [2.2.1] - 2021-08-17\n\n---\n\n### Fixed\n\n- index (exports)\n\n### [2.2.0] - 2021-08-17\n\n---\n\n### Added\n\n- getUndefinedKeysAsArray\n- getUndefinedKeysAsObject\n\n### [2.1.0] - 2021-08-14\n\n---\n\n### Changed\n\n- CurrencyValueObject\n\n### Added\n\n- ChangesObserver\n\n### [2.0.4] - 2021-08-13\n\n---\n\n### Fixed\n\n- Result\n\n### [2.0.3] - 2021-08-13\n\n---\n\n### Fixed\n\n- Result: new approach\n\n### [2.0.2] - 2021-08-12\n\n---\n\n### Changed\n\n- Dynamic types to Filter on IBaseRepository\n\n### [2.0.1] - 2021-08-12\n\n- Entity\n\n### [2.0.0] - 2021-08-12\n\n---\n\n### Changed\n\n- DomainId\n- AggregateRoot: new approach\n- Entity: new approach\n- Filter\n\n### Added\n\n- OrderStatusValueObject\n\n### Fixed\n\n- AggregateRoot\n\n### [1.5.1] - 2021-08-11\n\n---\n\n### Changed\n\n- BirthdayValueObject\n\n### [1.5.0] - 2021-08-11\n\n---\n\n### Added\n\n- colorConverter\n- colorGenerator\n\n### Changed\n\n- RGBColorValueObject\n- HEXColorValueObject\n\n### [1.4.1] - 2021-08-11\n\n---\n\n### Added\n\n- RGBColorValueObject\n- HEXColorValueObject\n- PostalCodeValueObject\n- UrlValueObject\n\n### Changed\n\n- Result\n\n### [1.3.1] - 2021-08-10\n\n---\n\n### Fixed\n\n- TrackingCodeValueObject\n\n### [1.3.0] - 2021-08-10\n\n---\n\n### Changed\n\n- Result StatusCode\n\n### Added\n\n- Logger\n- HomePhoneValueObject\n- MobilePhoneValueObject\n- DomainId\n- TrackingCodeValueObject\n\n### [1.2.0] - 2021-08-09\n\n---\n\n### Added\n\n- PasswordValueObject\n- passwordGenerator\n- CurrencyValueObject\n- EmailValueObject\n- UserNameValueObject\n- BirthdayValueObject\n\n### [1.1.0] - 2021-07-28\n\n---\n\n### Added\n\n- Dynamic types to Filter\n- Types validation to IBaseRepository\n\n### [1.0.3] - 2021-07-16\n\n---\n\n### Fixed\n\n- Define Node crash version on package.json\n\n### [1.0.2] - 2021-07-09\n\n---\n\n### Changed\n\n- Update documentation\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, religion, or sexual identity\nand orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the\n  overall community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or\n  advances of any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email\n  address, without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at\n.\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series\nof actions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or\npermanent ban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior,  harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within\nthe community.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.0, available at\nhttps://www.contributor-covenant.org/version/2/0/code_of_conduct.html.\n\nCommunity Impact Guidelines were inspired by [Mozilla's code of conduct\nenforcement ladder](https://github.com/mozilla/diversity).\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see the FAQ at\nhttps://www.contributor-covenant.org/faq. Translations are available at\nhttps://www.contributor-covenant.org/translations.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nWhen contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change.\n\nPlease note we have a code of conduct, please follow it in all your interactions with the project.\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 Alessandro dev.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "# Define the targets and the commands to be executed\n.PHONY: startVerdaccio stopVerdaccio publishVerdaccio addUser login build graph publish update\n\n# Start Verdaccio Docker container (local NPM registry)\n# This will install 'expect', pull the latest Verdaccio image, and run it.\nstartVerdaccio:\n# Install the 'expect' package needed for some automation scripts\n\tsudo apt-get update && sudo apt-get install expect\n# Pull the latest nightly version of the Verdaccio image\n\tdocker pull verdaccio/verdaccio:nightly-master\n# Run Verdaccio in detached mode with port 4873 exposed\n\tdocker run -it -d --rm --name lib_verdaccio -p 4873:4873 verdaccio/verdaccio:nightly-master\n# Clear any existing NPM configuration\n\techo \"\" > ./.npmrc\n# Set the registry to the local Verdaccio instance for project-specific use\n\tnpm config set registry http://localhost:4873/ --location project\n\n# Stop the running Verdaccio Docker container\nstopVerdaccio:\n# Stop the Verdaccio container with the name 'lib_verdaccio'\n\tdocker stop lib_verdaccio\n\n# Add a new user to the local NPM registry (Verdaccio)\n# This will execute the script that interacts with the registry to add a user\naddUser:\n\t./scripts/make-user.sh\n\n# Log in to the local NPM registry (Verdaccio)\n# This will execute the login script to authenticate the user with Verdaccio\nlogin:\n\t./scripts/login.sh\n\n# Build the project and its dependencies using npm\n# This includes running the general build process and the Lerna build process\nbuild:\n\tnpm run build && npm run build:lerna\n\n# Build and publish packages to the local Verdaccio registry\n# This builds all packages using Yarn and Lerna and publishes them to the local registry\npublishVerdaccio:\n\tyarn build\n\tyarn build:lerna\n\tyarn lerna exec \"npm publish --registry http://localhost:4873\"\n\n# Generate and visualize the dependency graph of the project using Nx\n# This will show a graphical representation of the dependencies in the monorepo\ngraph:\n\tyarn nx graph\n\n# Publish packages using Lerna\n# This command publishes packages to the specified registry using Lerna\npublish:\n\tyarn lerna publish\n\n# Update a specific peer dependency across all packages in the monorepo\n# Example usage: make update lib=rich-domain v=1.1.0\n# This will update the specified peer dependency (e.g., 'rich-domain') to the given version (e.g., '1.1.0') in all package.json files in the ./packages directory\n# update peer dependency in all packages once\nupdate:\n\t./update-peer-dependency.sh $(lib) $(v)\n"
  },
  {
    "path": "README.md",
    "content": "\n# @type-ddd/core\n\n> Now with individual packages\n\nThis package provide utils file and interfaces to assistant build a complex application as domain driving design and nodeJS with typescript.\n\n---\n\n<a href=\"https://www.npmjs.com/package/types-ddd\" rel=\"nofollow\" class=\"keychainify-checked\">\n <img src=\"https://badgen.net/github/checks/4lessandrodev/types-ddd/main\" \n alt=\"checks\" \n style=\"max-width: 100%;\">\n</a>\n<a href=\"https://www.npmjs.com/package/types-ddd\" rel=\"nofollow\" class=\"keychainify-checked\">\n <img src=\"https://badgen.net/github/stars/4lessandrodev/types-ddd\" \n alt=\"stars\" \n style=\"max-width: 100%;\">\n</a>\n<a href=\"https://www.npmjs.com/package/types-ddd\" rel=\"nofollow\" class=\"keychainify-checked\">\n <img src=\"https://badgen.net/github/commits/4lessandrodev/types-ddd/main\" \n alt=\"commits\" \n style=\"max-width: 100%;\">\n</a>\n<a href=\"https://www.npmjs.com/package/types-ddd\" rel=\"nofollow\" class=\"keychainify-checked\">\n <img src=\"https://badgen.net/github/last-commit/4lessandrodev/types-ddd/main\" \n alt=\"last commit\" \n style=\"max-width: 100%;\">\n</a>\n<a href=\"https://www.npmjs.com/package/types-ddd\" rel=\"nofollow\" class=\"keychainify-checked\">\n <img src=\"https://badgen.net/github/license/4lessandrodev/types-ddd\" \n alt=\"license\" \n style=\"max-width: 100%;\">\n</a>\n<a href=\"https://www.npmjs.com/package/types-ddd\" rel=\"nofollow\" class=\"keychainify-checked\">\n <img src=\"https://badgen.net/github/dependabot/4lessandrodev/types-ddd\" \n alt=\"dependabot\" \n style=\"max-width: 100%;\">\n</a>\n<a href=\"https://www.npmjs.com/package/types-ddd\" rel=\"nofollow\" class=\"keychainify-checked\">\n <img src=\"https://badgen.net/github/tag/4lessandrodev/types-ddd\" \n alt=\"tags\" \n style=\"max-width: 100%;\">\n</a>\n<a href=\"https://www.npmjs.com/package/types-ddd\" rel=\"nofollow\" class=\"keychainify-checked\">\n <img src=\"https://badgen.net/github/closed-issues/4lessandrodev/types-ddd\" \n alt=\"issues\" \n style=\"max-width: 100%;\">\n</a>\n\n---\n## Install core\n\nInstall full available packages \n\n```sh\n$ npm i @type-ddd/core\n\n# or \n\n$ yarn add @type-ddd/core\n\n```\n\n## Individual\n\nAlternatively you can install individual packages\n\n- `@type-ddd/cpf` [Docs](./packages/cpf)\n- `@type-ddd/cnpj` [Docs](./packages/cnpj)\n- `@type-ddd/date` [Docs](./packages/date)\n- `@type-ddd/email` [Docs](./packages/email)\n- `@type-ddd/password` [Docs](./packages/password)\n- `@type-ddd/patterns` [Docs](./packages/patterns)\n- `@type-ddd/phone` [Docs](./packages/phone)\n- `@type-ddd/username` [Docs](./packages/username)\n- `@type-ddd/zip-code` [Docs](./packages/zip-code)\n- `@type-ddd/money` [Docs](./packages/money)\n\n---\n\n<img src=\"./readme/cover.png\" alt=\"image\" width=\"100%\">\n\n---\n\n## 1. Ubiquitous language:\n\n- Language and terms agreed upon by both business users and developers, within a bounded context\n- Entities with the same name in a different context can have different behavior and data\n- Bounded context helps in single responsibility for domain models\n\n## 2. Rich domain model:\n\n- Models (entities, value objects, aggregates) with rich behavior are preferred over anemic domain models (entities without behavior, which only keep data and represent the DB tables)\n- Due to single responsibility principle (a class or method should have only one reason to change), non-cohesive behavior should be delegated to other classes (or even handled inside domain services) when necessary\n- Model methods can also delegate the task to domain services by raising domain events\n\n## 3. Thin domain service working on rich domain models:\n\n- Domain services should not hold state (application services are not domain services, they are on the outer layer close to the UI layer, and can hold application/task state)\n- Domain services have very little behavior and only which does not fit cohesively in any domain model\n- Domain services sit in the core domain layer along with entities, value objects, aggregates and domain events, and expose domain models in their interfaces\n\n## 4. Layers in a DDD application:\n\n- Core domain layer (domain services, entities, value objects, aggregates and domain events)\n- Core domain layer is surrounded by the UI/Application layer and Infrastructure layer\n- UI/Application layer (UI and application service facade with messaging, JSON, XML capabilities, session, etc.)\n- Infrastructure layer (persistence, file system, network, mail, logging, etc.)\n\n## 5. Entities:\n\n- Live longer than the application, should endure restarts, and are persisted and read from data sources (DB, file system, network, etc.)\n- Have an id (preferably a GUID rather than a DB generated int because business transactions do not rely on persistence, can be persisted after other operations carried out in model's behavior)\n- Have entity semantics (equality and `GetHashCode()` defined by class name + id)\n- Behavior in an entity mostly orchestrates value objects for a use case\n- Entity class should not have public property setters, setting a property should be a behavior method\n- Entities should not have bidirectional relations (depending on the bounded context, either an egg can have a chicken or a chicken can have eggs, but not both)\n- Entity relations should not reflect the complete set of DB foreign key relationships, should be bare down to the minimum for performing the behavior inside the bounded context\n- Entity relations should not hold a reference to another entity class, it can only keep the id of another entity\n- If a business transaction needs a reference to other entities in relation, aggregates should be used instead (aggregates can hold a reference to other aggregate roots, which are entity classes by definition)\n\n## 6. Value objects:\n\n- Are only identified by their values, not by their ids (for example money is a value object as long as we are not tracking individual banknotes, if we need to track individual banknotes then it should be a banknote entity)\n- Can be used to measure or describe things (name, description, amount, height, date, time, range, address, etc.)\n- You can combine other value types that usually go together into a new value object type, like address (city, street, country, postal code) or ...range, or ...type\n- Prefer to put the behavior on value objects rather than on entities because value objects are immutable and do not have side effects (like changing their state or changing the state of any entity)\n- Can be part of an entity\n- Have value semantics (equality and `GetHashCode()` defined by property values)\n- Should be immutable, behaviors should not change the state of a value object, but can rather create a new value object (should act similar to C# strings, structs, ints, and other value types)\n- Can be persisted but only as part of an entity, not individually\n\n## 7. Factories:\n\n- Create, build aggregates and entities:\n- Static Create...() factory method on a model class is used to guard against the construction of an invalid or incomplete model\n- The model class should not have a public default constructor (however if it is to be persisted, for Entity Framework to work, it can have a protected or private default constructor)\n\n## 8. Aggregates:\n\n- Encapsulate and are composed of entity classes and value objects that change together in a business transaction\n- Aggregates are a transactional graph of model objects\n- Aggregate root should be an entity, an aggregate can even be a single entity\n- Aggregate can keep a reference to other aggregate roots, but not to other entity classes which are not aggregate roots themselves\n- Aggregate should not keep a reference to other aggregate root entity classes if those other entities do not change together with this aggregate root entity\n- Aggregate can also keep the id of another entity, but keeping too many foreign key ids is a code smell (why?)\n- If deleting an entity has a cascade effect on the other entities referenced by class in the object graph, these entities are part of the same aggregate, if not, they should not be inside this aggregate\n\n## 9. Repositories:\n\n- Persist and read aggregates to/from DB or file system\n- Should have an interface close to a collection but should allow only the necessary operations needed for this aggregate (for example an aggregate might not need to be allowed to get updated or deleted)\n- Should not be generic (should be specific for the aggregate type)\n- Can have specific query methods if needed (like `FindByName()` etc.)\n- Do not use lazy loading, instead use eager loading (use Include(...) in Entity Framework), else you can face \"N+1 problem\"s and excessive number of queries sent to DB\n- Can have specific methods that only load some of the columns from a table\n- Repository add/update/remove operation should commit to DB by itself (call Entity Framework ...Context.SaveChanges() at the end), because aggregate operations should be ACID transactions\n- Repository interface sits inside Core domain layer, but implementations are inside Infrastructure layer\n- Repositories are not used inside the domain models (entities, value objects, aggregates)\n\n## 10. Shared kernel:\n\n- Is where cross-cutting concerns or common types shared by all bounded contexts sit (like entity abstract base type, value object abstract base type, common value objects, authorization, etc.)\n\n## 11. Domain events:\n\n- Can be raised when a state change occurs in an entity\n- Decouple models from each other\n- Only used when an event needs to be handled inside a different model than the one raising this event, or handled inside a domain service or even an application service\n- Are immutable classes, that represent past, named in the past tense, and cannot change (...Changed, ...Happened, etc.)\n- Should include the time that this event was raised, as well as any other useful info for handling the event, as well as the id of the entity which raised the event\n- Should not have behavior\n- Domain events are subscribed to with a callback (lambda), or using pub sub interfaces, on a singleton or static event message bus\n- Domain events implemented this way can be subscribed to and handled in the aggregate root of the entity which raised the event, or in domain services, or even in UI/Application layer\n- Domain events are raised synchronously, if an asynchronous task needs to be carried out, it can be done inside the event handler (async-await pattern)\n- Outside applications can also be triggered by using a message queue or an enterprise service bus (ESB) inside the domain event handler\n\n## 12. Anti-corruption layer:\n\n- Used to translate models from outside systems or legacy apps to models inside the bounded context and vice versa, and also to ease the communication with legacy services\n- Can use service facades and model adapters\n\n\n---\n\n## Individual Packages \n\nInstall individual package\n\n- `@type-ddd/cpf` [Docs](./packages/cpf)\n- `@type-ddd/cnpj` [Docs](./packages/cnpj)\n- `@type-ddd/date` [Docs](./packages/date)\n- `@type-ddd/email` [Docs](./packages/email)\n- `@type-ddd/password` [Docs](./packages/password)\n- `@type-ddd/patterns` [Docs](./packages/patterns)\n- `@type-ddd/phone` [Docs](./packages/phone)\n- `@type-ddd/username` [Docs](./packages/username)\n- `@type-ddd/zip-code` [Docs](./packages/zip-code)\n- `@type-ddd/money` [Docs](./packages/money)\n\n---\n\n### Value Object\n\n> A value object is a small, simple object that represents a single value or characteristic, such as a monetary amount or a date. It is characterized by having no identity of its own, meaning it is equal to another value object if its values are equal, regardless of its reference. Value objects are often used in domain-driven design to represent simple entities in the system.\n\n#### Create a value object with business rules.\n\n```ts\n\nimport { ValueObject, Ok, Fail, Result } from '@type-ddd/core';\n\ninterface Props {\n    amount: number;\n}\n\n// simple example as monetary value object business behavior\nexport default class Money extends ValueObject<Props> {\n    \n    // private constructor. Avoid public new.\n    private constructor(props: Props) {\n        super(props);\n    }\n\n    // any business rule behavior. Check.\n    public isGt(x: Money): boolean {\n        const { number: Check } = this.validator;\n        const xValue = x.get('amount');\n        const currentValue = this.get('amount');\n        return Check(xValue).isGreaterThan(currentValue);\n    }\n\n    // any business rule behavior. Calc.\n    public sum(x: Money): Money {\n        const { number: Calc } = this.util;\n        const value = x.get('amount');\n        const current = this.get('amount');\n        const amount = Calc(current).sum(value);\n        return new Money({ amount });\n    }\n\n    // any business rule behavior. Calc.\n    public subtract(x: Money): Money {\n        const { number: Calc } = this.util;\n        const value = x.get('amount');\n        const current = this.get('amount');\n        const amount = Calc(current).subtract(value);\n        return new Money({ amount });\n    }\n\n    // any business rule to validate state.\n    public static isValidProps({ amount }: Props): boolean {\n        const { number: Check } = this.validator;\n        return Check(amount).isPositive();\n    }\n\n    // shortcut to create a zero value\n    public static zero(): Money {\n        return new Money({ amount: 0 });\n    }\n\n    // factory method to create an instance and validate value.\n    public static create(amount: number): Result<Money | null> {\n\n        const isValid = this.isValidProps({ amount });\n        if(!isValid) return Fail(\"Invalid amount for money\");\n\n        return Ok(new Money({ amount }));\n    }\n}\n\n```\n\nHow to use value object instance\n\n```ts\n\n// operation result\nconst resA = Money.create(500);\n\n// check if provided a valid value\nconsole.log(resA.isOk());\n\n// > true\n\n\n// money instance\nconst moneyA = resA.value() as Money;\n\nmoneyA.get(\"amount\"); \n\n// 500\n\n// using methods \nmoneyA.isGt(Money.zero());\n\n// > true\n\nconst moneyB = Money.create(100).value() as Money;\n\nconst moneyC = moneyA.sum(moneyB);\n\nconst value = moneyC.get('amount');\n\nconsole.log(value); \n\n// > 600\n\n\n```\n\n---\n\n### Entity\n\n> An entity in domain-driven design is an object that represents a concept in the real world and has a unique identity and attributes. It is a fundamental building block used to model complex business domains.\n\n#### Create an entity with business rules.\n\n```ts\n\nimport { Entity, Ok, Fail, Result, UID } from '@type-ddd/core';\n\ninterface Props {\n    id?: UID;\n    total: Money;\n    discount: Money;\n    fees: Money;\n}\n\n// simple example as payment entity using money value object\nexport default class Payment extends Entity<Props> {\n\n    // private constructor\n    private constructor(props: Props){\n        super(props);\n    }\n\n    // any business rule behavior. Update total.\n    public applyFees(fees: Money): Payment {\n        const props = this.props;\n        const total = props.total.sum(fees);\n        return new Payment({ ...props, total, fees });\n    }\n\n    // any business rule behavior. Discount must be less or equal total.\n    public applyDiscount(discount: Money): Payment {\n        const props = this.props;\n        const total = props.total.subtract(discount);\n        return new Payment({ ...props, total, discount });\n    }\n\n    // factory method to create a instance. Value must be positive.\n    public static create(props: Props): Result<Payment> {\n        return Ok(new Payment(props));\n    }\n}\n\n```\n\nHow to use entity instance\n\n```ts\n\n// operation result\nconst total = Money.create(500).value() as Money;\nconst discount = Money.zero();\nconst fees = Money.zero();\n\n// create a payment\nconst payment = Payment.create({ total, discount, fees }).value() as Payment;\n\n// create fee and discount\nconst fee = Money.create(17.50).value();\nconst disc = Money.create(170.50).value();\n\n// apply fee and discount\nconst result = payment.applyFees(fee).applyDiscount(disc);\n\n// get object from domain entity\nconsole.log(result.toObject());\n\n{\n    \"id\": \"d7fc98f5-9711-4ad8-aa16-70cb8a52244a\",\n    \"total\": { \n        \"amount\": 347 \n    },\n    \"discount\": {\n         \"amount\": 170.50\n    },\n    \"fees\": { \n        \"amount\": 17.50\n    },\n    \"createdAt\":\"2023-01-30T23:11:17.815Z\",\n    \"updatedAt\":\"2023-01-30T23:11:17.815Z\"\n}\n\n```\n\n\n### Aggregate\n\nEncapsulate and are composed of entity classes and value objects that change together in a business transaction\n\n#### Create an aggregate to compose your context.\n\nIn my example, let's use the context of payment. All payment transactions are encapsulated by an order (payment order) that represents a user's purchasing context.\n\n```ts\n\nimport { Aggregate, Ok, Fail, Result, UID, EventHandler } from '@type-ddd/core';\n\n// Entities and VO that encapsulate context.\ninterface Props {\n    id?: UID;\n    payment: Payment;\n    items: List<Item>;\n    status: OrderStatus;\n    customer: Customer;\n}\n\n// Simple example of an order aggregate encapsulating entities and \n// value objects for context.\nexport default class Order extends Aggregate<Props> {\n\n    // Private constructor to ensure instances creation through static methods.\n    private constructor(props: Props){\n        super(props);\n    }\n\n    // Static method to begin a new order. \n    // Takes a customer as parameter and returns an instance of Order.\n    public static begin(customer: Customer): Order {\n        // Initialize the status of the order as \"begin\".\n        const status = OrderStatus.begin();\n        // Initialize the list of items as empty.\n        const items: List<Item> = List.empty();\n        // Initialize the payment as zero, since the order hasn't been paid yet.\n        const payment = Payment.none();\n        // Create a new instance of Order with the provided parameters.\n        const order = new Order({ status, payment, items, customer });\n\n        // Add an event to indicate that the order has begun.\n        order.addEvent('ORDER_HAS_BEGUN', (order) => {\n        // Perform some important operation when the order begins.\n            console.log('Do something important...');\n        });\n\n        // Alternatively, add an event by creating an\n        // instance of a class that extends EventHandler.\n        order.addEvent(new OrderBeganEventHandler());\n\n        // Return the created order instance.\n        return order;\n    }\n\n    // Method to add an item to the order. \n    // Takes an item as parameter and returns the Order instance.\n    addItem(item: Item): Order {\n        // Add the item to the order's items list.\n        this.props.items.add(item);\n        // Sum item price to payment amount\n        this.props.payment.sum(item.price);\n        // Return the Order instance itself to allow chained calls.\n        return this;\n    }\n\n    // Method to perform the payment of the order. \n    // Takes a payment object as parameter.\n    pay(payment: Payment): Order {\n        // Set the status of the order to \"paid\".\n        this.props.status = OrderStatus.paid();\n        // Set the provided payment object.\n        this.props.payment = payment;\n        // Add an event to indicate that the order has been paid.\n        // Assuming OrderPaidEvent is a class representing \n        // the event of order payment.\n        this.addEvent(new OrderPaidEventHandler());\n        return this; \n    }\n\n    // Static method to create an instance of Order.\n    // Returns a Result, which can be Ok (success) or Fail (failure).\n    // The value of the Result is an instance of Order, \n    // if creation is successful.\n    public static create(props: Props): Result<Order> {\n        return Ok(new Order(props));\n    }\n}\n\n```\n\n#### How to use events\n\nEvent Handler\n\n```ts\n\nimport { Context, EventHandler } from '@type-ddd/core';\n\n\nclass OrderCreatedEvent extends EventHandler<Order> {\n\n    constructor() {\n        super({ eventName: 'OrderCreated' });\n    }\n\n    dispatch(order: Order): void {\n        // dispatch event to another context\n        order.context().dispatchEvent('Context:Event', order.toObject());\n    };\n}\n\n```\n\nAggregates domain events\n\n\n```ts\n\norder.addEvent('Event', (...args) => {\n    console.log(args);\n});\n\n// Or add an EventHandler instance\norder.addEvent(new OrderCreatedEvent());\n\norder.dispatchEvent('OrderBegun');\n\n// dispatch with args\norder.dispatchEvent('Event', { info: 'custom_args' });\n\n// OR call all added events\nawait order.dispatchAll();\n\n\n```\n\n#### How to subscribe to a global event\n\n```ts\n\nimport { Context } from '@type-ddd/core';\n\nconst context = Context.events();\n\ncontext.subscribe('Context:Event', (event) => {\n   const [model] = event.detail;\n   console.log(model);\n});\n\n// dispatch an event to a context with args\ncontext.dispatchEvent('Context:Event', { name: 'Jane' });\n\n// Dispatching events to specific contexts\n// Dispatches the SIGNUP event to Context-X\ncontext.dispatchEvent('Context-X:Signup'); \n\n// Dispatches the SIGNUP event to all contexts\ncontext.dispatchEvent('*:Signup'); \n\n// Dispatches all events to all contexts. Not recommended\ncontext.dispatchEvent('*:*'); \n\n// Dispatches all events under Context-Y\ncontext.dispatchEvent('Context-Y:*'); \n\n``` \n\n\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\n## Supported Versions\n\nVersions of types-ddd are currently being supported with security updates.\n\n| Version | Supported          |\n| ------- | ------------------ |\n| 4.x.x   | :white_check_mark: |\n| 3.9.x   | :white_check_mark: |\n| <= 3.8   | :x:               |\n\n## Reporting a Vulnerability\n\nIf you find some vulnerability please report as issue.\n\nEvery month security updates are published as 0.0.x version.\n"
  },
  {
    "path": "check-dev-deps.sh",
    "content": "#!/bin/sh\n\nDEV_DEPS=\"$(cat package.json | grep -A 100 \"devDependencies\" | grep -B 100 \"\\}\\,\" | \\\nawk \"NR>1\" | sed -e \"s/},//\" | tr -d '\":.^0-9,')\";\n\nfor dep in \"$(echo $DEV_DEPS)\"; do\n\techo $dep | sed -e 's/ /\\n/g' > deps;\ndone;\n\nwhile IFS= read -r line; do \n\tyarn list --depth 0 | grep $line@\ndone < ./deps;\n\nrm -rf ./deps\n"
  },
  {
    "path": "docs/README.md",
    "content": "# types-ddd documentation\n\n## About the lib\n\nThe library was created to support developers in developing domain-rich applications.\n\nFull documentation.\nVersion 3.x\n\n\nThis lib use as core [rich-domain](https://www.npmjs.com/package/rich-domain)\n\n### Simple App Example\n\nA simple app example available on [link](https://github.com/4lessandrodev/ddd-app)\n\n---\n## Documentation\n\n### Folders\nFolders structure suggestion\nDivided by\n\n- Domain layer\n- Application layer\n- Infra layer\n\n```shell\n  $ tree\n  .\n  ├── package.json\n  ├── README.md\n  └── src\n       ├── configs\n       │    └── env\n       │\n       ├── shared\n       │    └── infra\n       │         └── server  \n       │\n       └── modules\n            │ \n            └── [module-name]\n                  │ \n                  │── domain\n                  │     ├── value-objects\n                  │     ├── entities\n                  │     ├── aggregates\n                  │     ├── events\n                  │     ├── subscriptions\n                  │     ├── adapter\n                  │     ├── repository-interface\n                  │     └── domain-services\n                  │ \n                  ├── application\n                  │     └── use-cases \n                  │ \n                  └── infra\n                        ├── models\n                        └── repository\n\n```\n\n---\n\n### Result\n\nWhat is Result:\n\n`Result` is a class that encapsulates the result of an operation and stores the success or failure state without throws the application.\n\n#### Interface and Generic Types\n\n- A = `Payload` optional default `void`\n- B = `Error` optional default `string`\n- C = `MetaData` optional default `{}`\n\n```ts\n\nIResult<A, B, C>;\n\n```\n\nAlternative shortcuts\n\n```ts\n\nimport { Ok, Fail } from 'types-ddd';\n\n// Success use case\n\nreturn Ok();\n\n// OR \n\nreturn Ok<string>('success message');\n\n// Failure use case\n\nreturn Fail('error message here');\n\n```\n\nExample how to use generic types.\nFirst let's create our interfaces to use as generic type.\n- The type of data to be retrieved can be any type you want.\n\n\n```tS\n\n// Payload type\ninterface IData { data: string };\n\n// Error type\ninterface IError { message: string };\n\n// MetaData type\ninterface IMeta { arg: number };\n\n```\n\nNow let's implement a function that return the result below\n\n```ts\n\nIResult<IData, IError, IMeta>;\n\n```\nSo let's implement that on a simple function.\n\n```ts\n\nconst isEven = (value: number): Result<IData, IError, IMeta> => {\n\n\tconst isPairValue = value % 2 === 0;\n\tconst metaData: IMeta = { arg: value };\n\t\n\tif (isPairValue) {\n\t\t\n\t\t// success payload \n\t\tconst payload: IData = { data: `${value} is even` };\n\n\t\t// return success\n\t\treturn Ok(payload, metaData);\n\t}\n\n\t// failure payload \n\tconst error: IError = { message: `${value} is not even` };\n\n\t// return failure\n\treturn Fail(error, metaData);\n};\n\n\n```\nHere we have a function that returns success if the value informed is even and returns failure if it is odd.\n\nSuccess Case\n\n```ts\n\nconst result = isEven(42);\n\nconsole.log(result.isOk());\n\n> true\n\nconsole.log(result.value());\n\n> 'Object { data: \"42 is even\" }'\n\nconsole.log(result.metaData());\n\n> 'Object { arg: 42 }'\n\nconsole.log(result.error());\n\n> null\n\n```\nFailure Case\n\n```ts\n\nconst result = isEven(43);\n\nconsole.log(result.isFail());\n\n> true\n\nconsole.log(result.error());\n\n> 'Object { message: \"43 is not even\" }'\n\nconsole.log(result.metaData());\n\n> 'Object { arg: 43 }'\n\nconsole.log(result.value());\n\n> null\n\n```\n\n#### Void\n\nThe most simple void success example.<br>\nLet's see the same example using void.\n\n```ts\n\nconst checkEven = (value: number): Result<void> => {\n\n\tconst isPair = value % 2 === 0;\n\n\t// success case\n\tif(isPair) return Ok(); \n\t\n\t// failure case\n\treturn Fail('not enven');\n}\n\n```\nUsing the function as success example\n\n```ts\n\nconst result: Result<void> = checkEven(42);\n\nconsole.log(result.isOk());\n\n> true\n\nconsole.log(result.isFail());\n\n> false\n\nconsole.log(result.error());\n\n> null\n\nconsole.log(result.value());\n\n> null\n\nconsole.log(result.metaData());\n\n> 'Object {}'\n\n```\n\nFail example\n\n```ts\n\nconst result: Result<void> = checkEven(43);\n\nconsole.log(result.isFail());\n\n> true\n\nconsole.log(result.isOk());\n\n> false\n\nconsole.log(result.error());\n\n> \"not even\"\n\nconsole.log(result.value());\n\n> null\n\nconsole.log(result.metaData());\n\n> 'Object {}'\n\n```\n\n#### toObject method\nyou can get a summarized object with the properties of an instance of a `Result`\n\n```ts\n\nconsole.log(result.toObject());\n\n> Object\n`{\n\t\"data\": null, \n\t\"error\": \"not even\", \n\t\"isFail\": true, \n\t\"isOk\": false, \n\t\"metaData\": Object {}\n }`\n\n```\n\n#### Hooks\n\nIn the instances of a Result there are two hooks that allow the execution of a command according to the state.\n\n```ts\n\nclass Command implements ICommand<void, void> {\n\texecute(): void {\n\t\tconsole.log(\"running command ...\");\n\t}\n}\n\nconst myCommand = new Command();\n\nconst result = Result.Ok();\n\nresult.execute(myCommand).on('Ok');\n\n> \"running command ...\"\n\n```\n\nYou might also want to pass arguments to the command\n\n```ts\n\nclass Command implements ICommand<string, void> {\n\texecute(error: string): void {\n\t\tconsole.log(error);\n\t}\n}\n\nconst myCommand = new Command();\n\nconst result = Result.fail('something went wrong');\n\nresult.execute(myCommand).withData(result.error()).on('fail');\n\n> \"something went wrong\"\n\n```\n\n#### Combine\n\nYou can use the static `combine` function of `Result` to check many instances if any are failed it will return the instance with error state.\n\nSuccess example \n\n```ts\n\nconst resultA = Result.Ok();\nconst resultB = Result.Ok();\nconst resultC = Result.Ok();\n\nconst result = Result.combine([resultA, resultB, resultC]);\n\nconsole.log(result.isOk());\n\n> true\n\n```\nFailure example \n\n```ts\n\nconst resultA = Result.Ok();\nconst resultB = Result.fail('oops err');\nconst resultC = Result.Ok();\n\nconst result = Result.combine([resultA, resultB, resultC]);\n\n// OR you can use Combine function\n\nconst result = Combine([resultA, resultB, resultC]);\n\nconsole.log(result.isOk());\n\n> false\n\nconsole.log(result.error());\n\n> 'oops err'\n\n```\n\n---\n\n\n### ID\n\nWhat is ID:\nA symbol which uniquely identifies an object or record.<br>\nIn this Lib all IDs are generated by domain and uses uuid v4.\n\n#### Create New\nCreate a new uuid.\n\n```ts\n\n// ID main\n\nconst id = ID.create();\n\n// OR Id as function\n\nconst id = Id();\n\n// OR id instance\n\nconst id = id.create();\n\nconsole.log(id.value());\n\n> \"eb9c563c-719d-4872-b303-0a82921351f7\"\n\n```\n\n#### Short New\nCreate a short id\n\n```ts\n\nconst id = ID.short();\n\nconsole.log(id.value());\n\n> \"EB9C563DB4872BF7\"\n\n```\n\n#### Create Existing\nCreate a id with provided value\n\n```ts\n\nconst id = ID.create('this-is-my-id-01');\n\nconsole.log(id.value());\n\n> \"this-is-my-id-01\"\n\n```\n\n#### Compare ids\nThe id instance has a method to compare two ids.\n\n```ts\n\nconst idA = ID.short('this-is-my-id-01');\nconst idB = ID.short('this-is-my-id-02');\n\nconsole.log(idA.equal(idB));\n\n> false\n\nconsole.log(idB.equal(idB));\n\n> true\n\n```\n\n#### IsNew\nCheck if id instance is has a new value\n\n```ts\n\nconst idA = ID.create('this-is-my-id-01');\nconst idB = ID.create();\n\nconsole.log(idA.isNew());\n\n> false\n\nconsole.log(idB.isNew());\n\n> true\n\n```\n\n#### Type for ID\nDefine type for ID\n\n```ts\n\nimport { UID, ID } from 'types-ddd';\n\n// UID type\nlet id: UID;\n\n// ID value\nid = ID.create();\n\n\n```\n\n---\n\n### ValueObject\n\nWhat is value object:\n\n- Are only identified by their values, not by their ids (for example money is a value object as long as we are not tracking individual banknotes, if we need to track individual banknotes then it should be a banknote entity)\n- Can be used to measure or describe things (name, description, amount, height, date, time, range, address, etc.)\n- You can combine other value types that usually go together into a new value object type, like address (city, street, country, postal code) or ...range, or ...type\n- Prefer to put the behavior on value objects rather than on entities because value objects are immutable and do not have side effects (like changing their state or changing the state of any entity)\n- Can be part of an entity\n- Should be immutable, behaviors should not change the state of a value object, but can rather create a new value object (should act similar to C# strings, structs, ints, and other value types)\n- Can be persisted but only as part of an entity, not individually.\n\n\n#### Simple Value Object.\n\nValue objects extend to `ValueObject` class have private constructor and public static method called `create`.<br>\nThe `create` method receives the props which by default is an object with the key `value`.\n\nthe value object below is a base example without any kind of validation\n\n```ts\n\nimport { IResult, Result, ValueObject } from \"types-ddd\";\n\nexport interface NameProps {\n\tvalue: string;\n}\n\nexport class Name extends ValueObject<NameProps>{\n\tprivate constructor(props: NameProps) {\n\t\tsuper(props);\n\t}\n\n\tpublic static create(value: string): IResult<Name> {\n\t\treturn Ok(new Name({ value }));\n\t}\n}\n\nexport default Name;\n\n```\n\nNow that we have defined our value object class, we can create an instance.<br>\nThe `create` method returns an instance of Name encapsulated by the `Result`, so it is important to always assess whether the result is a success before getting the value.\n\n```ts\n\nconst result = Name.create('Jane');\n\nconsole.log(result.isOk());\n\n> true\n\nconst name = result.value();\n\nconsole.log(name.get('value'));\n\n> \"Jane\"\n\n```\n\nOnce we have an instance of a value object, we can use some methods that the library makes available.\n\nBy default setters are enabled\n\n```ts\n\n// Prefer to create new instance instead of changing value to value object. Do not use set to value object.\n\nname.set('value').to('John');\n\nconsole.log(name.get('value'));\n\n> \"John\"\n\n```\n\nWhen you use the `set` or `change` function to modify the state, each change is saved in a history\n\n```ts\n\nconsole.log(name.history().count());\n\n> 2\n\n// back to old value on history\nname.history().back();\n\nconsole.log(name.get('value'));\n\n> \"Jane\"\n\n```\n\n> **We don't advise you to use state change of a value object. Create a new one instead of changing its state. However the library will leave that up to you to decide.**\n\nTo disable the setters of a value object use the parameters below in the super.<br>\nThis property disables the set function of the value object.\n\n```ts\n\nconstructor(props: NameProps){\n\tsuper(props, { disableSetters: true })\n}\n\n```\n\nNow when trying to change the value using `set` or `change` it will not be modified.\n\n```ts\n\nconsole.log(name.get('value'));\n\n> \"John\"\n\nname.set('value').to('James');\n\nconsole.log(name.get('value'));\n\n> \"John\"\n\n```\n\n#### Using validation\n\nValidation before create instance.<br>\nA validator instance is available in the \"Value Object\" domain class.\n\n```ts\n\nimport { Ok, Fail, Result, ValueObject } from \"types-ddd\";\n\nexport interface NameProps {\n\tvalue: string;\n}\n\nexport class Name extends ValueObject<NameProps>{\n\tprivate constructor(props: NameProps) {\n\t\tsuper(props);\n\t}\n\n\tpublic static isValidProps({ value }: NameProps): boolean {\n\t\tconst { string } = this.validator;\n\t\treturn string(value).hasLengthBetweenOrEqual(3, 30);\n\t}\n\n\tpublic static create(value: string): Result<Name> {\n\t\tconst message = 'name must have length min 3 and max 30 char';\n\n\t\tif (!this.isValidProps({ value })) return Fail(message);\n\n\t\treturn Ok(new Name({ value }));\n\t}\n}\n\nexport default Name;\n\n```\n\nNow when you try to instantiate a name, the value will be checked and if it doesn't meet the validation requirements, a `Result` will be returned with an error state.\n\n```ts\n\nconst empty = '';\n\nconst result = Name.create(empty);\n\nconsole.log(result.isFail());\n\n> true\n\nconsole.log(result.error());\n\n> \"name must have length min 3 and max 30 char\"\n\nconsole.log(result.value());\n\n> null\n\n```\n\n#### Validation before set\n\nThe `isValidProps` Method validates properties when creating a new instance, but which method validates before modifying a value?\nFor this there is the method `validation`\n\nThe validation method takes two arguments, the first the `key` of props and the second the `value`.\nSo when calling the `set` or `change` function, this method will be called automatically to validate the value, if it doesn't pass the validation, the value is not changed.\n\n> There must be a validation for each \"props\" key\n\n```ts\n\nvalidation<Key extends keyof Props>(value: Props[Key], key: Key): boolean {\n\t\n\tconst { number } = this.validator;\n\n\tconst options: IPropsValidation<Props> = {\n\t\tvalue: (value: number) => number.isBetween(0, 130),\n\t} \n\n\treturn options[key](value);\n};\n\n```\n\nIn case your value object has only one attribute you can simply use the already created static validation method.<br>\nLet's see a complete example as below\n\n```ts\n\nimport { Result, Result, ValueObject } from \"types-ddd\";\n\nexport interface NameProps {\n\tvalue: string;\n}\n\nexport class Name extends ValueObject<NameProps>{\n\tprivate constructor(props: NameProps) {\n\t\tsuper(props);\n\t}\n\n\tvalidation(value: string): boolean {\n\t\treturn Name.isValidProps({ value });\n\t}\n\n\tpublic static isValidProps({ value }: NameProps): boolean {\n\t\tconst { string } = this.validator;\n\t\treturn string(value).hasLengthBetween(3, 30);\n\t}\n\n\tpublic static create(value: string): IResult<Name> {\n\t\tconst message = 'name must have length min 3 and max 30 char';\n\n\t\tif (!this.isValidProps({ value })) return Fail(message);\n\n\t\treturn Ok(new Name({ value }));\n\t}\n}\n\nexport default Name;\n\n```\n\nLet's test the instance and the validation method.<br>\nValue is not modified if it does not pass validation.\n\n```ts\n\nconst result = Name.create('Jane');\n\nconsole.log(result.isOk());\n\n> true\n\nconst name = result.value();\n\nconsole.log(name.get('value'));\n\n> \"Jane\"\n\nconst empty = '';\n\nname.set('value').to(empty);\n\nconsole.log(name.get('value'));\n\n> \"Jane\"\n\nname.set('value').to(\"Jack\");\n\nconsole.log(name.get('value'));\n\n> \"Jack\"\n\n```\n\n#### toObject\nThis method transforms a complex object into a simple object or value.<br>\nThis method is useful for cases where you have value objects inside other value objects\n\n```ts\n\nconst street = Street.create('Dom Juan').value();\n\nconst number = Number.create(42).value();\n\nconst result = Address.create({ street, number });\n\nconst address = result.value();\n\nconsole.log(address.toObject());\n\n> Object \n`{\n\t\"street\": \"Dom Juan\", \n\t\"number\": 42,\n }`\n\n```\n\n#### Clone\nThis method creates a new instance with the same properties as the current value object.\n\n```ts\n\nconst result = Name.create('Sammy');\n\nconst originalName = result.value();\n\nconsole.log(originalName.value());\n\n> \"Sammy\"\n\nconst clone = originalName.clone();\n\nconsole.log(clone.isOk());\n\n> true\n\nconst clonedName = clone.value();\n\nconsole.log(clonedName.value());\n\n> \"Sammy\"\n\n```\n\nClone being a new instance does not change the properties of the original value object\n\n```ts\n\nclonedName.change('value', 'Jones');\n\nconsole.log(clonedName.value());\n\n> \"Jones\"\n\nconsole.log(originalName.value());\n\n> \"Sammy\"\n\n```\n\n#### createMany\n\nSometimes you will need to create many instances of different value objects and for that there is static method available `createMany` on value objects, entity and aggregate.\n\n```ts\n\nconst itemPrice = Class<PriceProps>(ProductPrice, { value: price });\nconst itemName = Class<NameProps>(ProductName, { value: name });\nconst itemQtd = Class<QtdProps>(ProductQtd, { value: qtd });\n\nconst { data, result } = ValueObject.createMany([ itemPrice, itemName, itemQtd ]);\n\n// you check if all value objects are ok\nif (result.isFail()) return Result.fail(result.error());\n\n// you can get instances from iterator data. In the same order as the array\nconst price = data.next().value() as ProductPrice;  // index 0\nconst name = data.next().value() as ProductName;    // index 1\nconst quantity = data.next().value() as ProductQtd; // index 2\n\nconst product = Product.create({ name, price, quantity });\n\n```\n\n---\n\n### Entity\n\nWhat is value object:\n\n- Live longer than the application, should endure restarts, and are persisted and read from data sources (DB, file system, network, etc.)\n- Have an id (preferably a GUID rather than a DB generated int because business transactions do not rely on persistence, can be persisted after other operations carried out in model's behavior)\n- Have entity semantics (equality and `GetHashCode()` defined by class name + id)\n- Behavior in an entity mostly orchestrates value objects for a use case\n- Entity class should not have public property setters, setting a property should be a behavior method\n- Entities should not have bidirectional relations (depending on the bounded context, either an egg can have a chicken or a chicken can have eggs, but not both)\n- Entity relations should not reflect the complete set of DB foreign key relationships, should be bare down to the minimum for performing the behavior inside the bounded context\n- Entity relations should not hold a reference to another entity class, it can only keep the id of another entity\n- If a business transaction needs a reference to other entities in relation, aggregates should be used instead (aggregates can hold a reference to other aggregate roots, which are entity classes by definition)\n\n#### Simple Entity\n\nEntities extend to `Entity` class, have private constructor and public static method called `create`.\nThe `create` method receives the props which by default is an object with the key `id`.\n\nthe entity below is a base example without any kind of validation\n\n```ts\n\ninterface UserProps { id?: UID, name: Name, age: Age };\n\nexport class User extends Entity<UserProps>{\n\tprivate constructor(props: UserProps){\n\t\tsuper(props)\n\t}\n\n\tpublic static create(props: UserProps): IResult<User> {\n\t\treturn Result.Ok(new User(props));\n\t}\n}\n\nexport default User;\n\n```\n\n`id` is a reserved word and must have the type `UID` or `string`.\n\nAll attributes for an entity must be value object except id.\n\n```ts\n\nconst nameAttr = Name.create('James');\nconst ageAttr = Age.create(21);\n\n// always check if value objects are success\nconst voResult = Combine([ nameAttr, ageAttr ])\n\nconsole.log(voResult.isOk());\n\n> true\n\nconst name = nameAttr.value();\n\nconst age = ageAttr.value();\n\n// if you don't provide a value for the id it will be generated automatically\nconst result = User.create({ name, age });\n\nconsole.log(result.isOk());\n\n> true\n\n```\n\n#### toObject\n\nwhen you extend entity class you get some methods from domain class, one of them is `toObject` method.<br>\nIn the entity, this method aims to transform a domain class into a simple object, that is, all value objects are transformed into simple attributes.\n\n```ts\n\nconst user = result.value();\n\nconsole.log(user.toObject());\n\n> Object\n`{\n\tage: 21,\n\tname: \"James\",\n\tcreatedAt: \"2022-08-13T03:51:25.738Z\",\n\tupdatedAt: \"2022-08-13T03:51:25.738Z\"\n\tid: \"0709220f-7c2f-41e2-b535-151926286893\",\n }`\n\n```\n\n#### with id value\n\nyou can create an instance by entering an id\n\n```ts\n\nconst name = nameAttr.value();\n\nconst id = ID.create('a3a5ea9d-7c57-4743-8a9b-5315fad365d0');\n\nconst result = User.create({ id, age, name });\n\nconsole.log(result.isOk());\n\n> true \n\nconst user = result.value();\n\nconsole.log(user.toObject());\n\n> Object\n`{\n\tage: 21,\n\tname: \"James\",\n\tcreatedAt: \"2022-08-13T03:51:25.738Z\",\n\tupdatedAt: \"2022-08-13T03:51:25.738Z\"\n\tid: \"a3a5ea9d-7c57-4743-8a9b-5315fad365d0\",\n }`\n\n```\n\n#### isNew\n\nCheck if instance is a new entity.<br> if you provide do not provide an id the entity will be considered as a new created entity instance.\n\n```ts\n\n// no id provided\nconst newUserResult = User.create({ name, age });\n\ncons newUser = newUserResult.value();\n\nconsole.log(newUser.isNew());\n\n> true\n\n// id provided\nconst userResult = User.create({ id, name, age });\n\ncons user = userResult.value();\n\nconsole.log(user.isNew());\n\n> false\n\n```\n\n#### isValidProps\n\nValidating props before create an instance.<br> Here you can apply your business validation.\n\n```ts\n\npublic static isValidProps({ name, age }: UserProps): boolean {\n\t\n\t// your business validation \n\tconst isValidName = doSomeBusinessValidation(name);\n\tconst isValidAge = doSomeBusinessValidation(age);\n\n\treturn isValidName && isValidAge;\n}\n\n```\n\nLet's apply our props validation method to our entity class\n\n```ts\n\ninterface UserProps { id?: UID, name: Name, age: Age };\n\nexport class User extends Entity<UserProps>{\n\tprivate constructor(props: UserProps){\n\t\tsuper(props)\n\t}\n\n\tpublic static isValidProps({ name, age }: UserProps): boolean {\n\t\t// your business validation \n\t\tconst isValidName = doSomeBusinessValidation(name);\n\t\tconst isValidAge = doSomeBusinessValidation(age);\n\n\t\treturn isValidName && isValidAge;\n\t}\n\n\tpublic static create(props: UserProps): IResult<User> {\n\n\t\tconst isValidRules = User.isValidProps(props);\n\t\tif(!isValidRules) return Result.fail('invalid props');\n\n\t\treturn Result.Ok(new User(props));\n\t}\n}\n\nexport default User;\n\n```\n\n#### change\n\nin entities you can easily change an attribute with `change` or `set` method\n\n```ts\n\nconst result = Name.create('Larry');\n\nconst newName = result.value();\n\nuser.change(\"name\", newName);\n\nconsole.log(user.get(\"name\").value());\n\n> \"Larry\"\n\n```\n\n#### Validation before change\n\nThe `isValidProps` Method validates properties when creating a new instance, but which method validates before modifying a value?<br>\nFor this there is the method `validation`\n\nThe validation method takes two arguments, the first the `key` of props and the second the `value`.\nSo when calling the `set` or `change` function, this method will be called automatically to validate the value, if it doesn't pass the validation, the value is not changed.\n\n> There must be a validation for each \"props\" key\n\n```ts\n\nvalidation<Key extends keyof Props>(value: Props[Key], key: Key): boolean {\n\n\tconst options: IPropsValidation<Props> = {\n\t\tname: (value: Name) => doSomeBusinessValidation(value),\n\t\tage: (value: Age) => doSomeBusinessValidation(value)\n\t} \n\n\treturn options[key](value);\n};\n\n```\n\nLet's apply our validation method to our entity.<br> Now if the validation does not pass the value will not be changed.\n\n```ts\n\ninterface UserProps { id?: UID, name: Name, age: Age };\n\nexport class User extends Entity<UserProps>{\n\tprivate constructor(props: UserProps){\n\t\tsuper(props)\n\t}\n\n\tvalidation<Key extends keyof Props>(value: Props[Key], key: Key): boolean {\n\t\tconst options: IPropsValidation<Props> = {\n\t\t\tname: (value: Name) => doSomeBusinessValidation(value),\n\t\t\tage: (value: Age) => doSomeBusinessValidation(value)\n\t\t} \n\t\treturn options[key](value);\n\t};\n\n\tpublic static isValidProps({ name, age }: UserProps): boolean {\n\t\t// your business validation \n\t\tconst isValidName = doSomeBusinessValidation(name);\n\t\tconst isValidAge = doSomeBusinessValidation(age);\n\t\treturn isValidName && isValidAge;\n\t}\n\n\tpublic static create(props: UserProps): IResult<User> {\n\n\t\tconst isValidRules = User.isValidProps(props);\n\t\tif(!isValidRules) return Result.fail('invalid props');\n\n\t\treturn Result.Ok(new User(props));\n\t}\n}\n\nexport default User;\n\n```\n\n#### disableSetters\n\nTo disable the setters of an entity use the parameters below in the super.<br>\nThis property disables the set function of the entity.\n\n```ts\n\nconstructor(props: NameProps){\n\tsuper(props, { disableSetters: true })\n}\n\n```\n\n#### clone entity\n\nyou can clone an entity and get a new instance\n\n```ts\n\nconst result = User.create({ id, age, name });\n\nconsole.log(result.isOk());\n\n> true \n\nconst user = result.value();\n\n const clonedUser = user.clone();\n\n const newUser = clonedUser.value();\n\n const newNameResult = Name.create('Luke');\n\n const newName = newNameResult.value();\n\n clonedUser.set('name').to(newName);\n\n console.log(user.get('name').value());\n\n > \"James\"\n\n console.log(clonedUser.get('name').value());\n\n > \"Luke\"\n\n```\n\n#### compare entities\n\nYou can compare two entities.\n\n`compare` just check props values and id value. `deepEqual` check props values, id, types and history.\n\n```ts\n\nconst isEqual = user1.isEqual(user2);\n\nconsole.log(isEqual);\n\n> false\n\n\n```\n\n#### history\n\nEach operation to change any entity state property generates a history.<br>\nAt any time you can return to a previous state\n\n```ts\n\nconst result = User.create({ name, age });\n\nconst user = result.value();\n\nconsole.log(user.toObject());\n\n> Object\n`{\n\tage: 21,\n\tname: \"James\",\n\tcreatedAt: \"2022-08-13T03:51:25.738Z\",\n\tupdatedAt: \"2022-08-13T03:51:25.738Z\",\n\tid: \"0709220f-7c2f-41e2-b535-151926286893\"\n }`\n\n// first history is initial props on create an instance\nconsole.log(user.history().count());\n\n> 1\n\nuser.set('name').to(newName);\n\nconsole.log(user.toObject());\n\n> Object\n`{\n\tage: 21,\n\tname: \"Luke\",\n\tcreatedAt: \"2022-08-13T03:51:25.738Z\",\n\tupdatedAt: \"2022-08-13T03:52:25.738Z\",\n\tid: \"0709220f-7c2f-41e2-b535-151926286893\"\n }`\n\n// On change name create a new history\nconsole.log(user.history().count());\n\n> 2\n\n// back to history 1\nuser.history().back();\n\nconsole.log(user.toObject());\n\n> Object\n`{\n\tage: 21,\n\tname: \"James\",\n\tcreatedAt: \"2022-08-13T03:51:25.738Z\",\n\tupdatedAt: \"2022-08-13T03:51:25.738Z\",\n\tid: \"0709220f-7c2f-41e2-b535-151926286893\"\n }`\n\n```\n\n---\n\n### Aggregate\n\nWhat is aggregate:\n\n- Encapsulate and are composed of entity classes and value objects that change together in a business transaction\n- Aggregates are a transactional graph of model objects\n- Aggregate root should be an entity, an aggregate can even be a single entity\n- Aggregate can keep a reference to other aggregate roots, but not to other entity classes which are not aggregate roots themselves\n- Aggregate should not keep a reference to other aggregate root entity classes if those other entities do not change together with this aggregate root entity\n- Aggregate can also keep the id of another entity, but keeping too many foreign key ids is a code smell (why?)\n- If deleting an entity has a cascade effect on the other entities referenced by class in the object graph, these entities are part of the same aggregate, if not, they should not be inside this aggregate\n\nThe aggregate has the same methods already mentioned in the entity.\nAnd in addition to the entity methods, there is another one that is responsible for managing the `domain's events`.\n\n#### Simple Aggregate\n\n```ts\n\nexport interface ProductProps {\n\tid?: UID;\n\tname: ProductName;\n\tprice: ProductPrice;\n\tcreatedAt?: Date;\n\tupdatedAt?: Date;\n}\n\n// extends to Aggregate\nexport class Product extends Aggregate<ProductProps>{\n\tprivate constructor(props: ProductProps) {\n\t\tsuper(props);\n\t}\n\n\tpublic static create(props: ProductProps): IResult<Product> {\n\t\treturn Result.Ok(new Product(props));\n\t}\n}\n\nexport default Product;\n\n```\n\n#### Domain Event\n\nLet's create an aggregate instance and see how to add domain event to it.\n\n```ts\n\nexport class ProductCreatedEvent implements IHandle<Product>{\n\tpublic eventName: string;\n\n\tconstructor() { \n\t\tthis.eventName = 'ProductCreated';\n\t}\n\t\n\tdispatch(event: IDomainEvent<Product>): void {\n\t\t// your action here\n\t\tconst { aggregate } = event;\n\t\tconsole.log(`EVENT DISPATCH: ${aggregate.hashCode().value()}`);\n\t}\n}\n\nexport default ProductCreatedEvent;\n\n```\n\nNow let's add the event to a product instance.<br>\nEvents are stored in memory and are deleted after being triggered.\n\n```ts\n\nconst result = Product.create({ name, price });\n\nconst product = result.value();\n\nconst event = new ProductCreatedEvent();\n\nproduct.addEvent(event);\n\n```\n\nNow we can dispatch the event whenever we want.\n\n```ts\n\nproduct.dispatch(\"ProductCreated\");\n\n> \"EVENT DISPATCH: [Aggregate@Product]:6039756f-d3bc-452e-932a-ec89ff536dda\"\n\n```\n---\n### Adapter\n\nHow to adapt the data from persistence to domain or from domain to persistence.\n\n```ts\n\n// from domain to data layer\nclass MyAdapterToInfra implements IAdapter<DomainUser, DataUser>{\n\tbuild(target: DomainUser): Result<DataUser> {\n\t\t// ...\n\t}\n}\n\n// from data layer to domain\nclass MyAdapterToDomain implements IAdapter<DataUser, DomainUser>{\n\tbuild(target: DataUser): Result<DomainUser> {\n\t\t// ...\n\t}\n}\n\n// You can use adapter instance in toObject function\nconst myAdapter = new MyAdapterToInfra();\n\nconst dataUser = domainUser.toObject<DataUser>(myAdapter);\n\n```\n\n---\n\n### Utils\n\nSome util tools available\n\n#### Ready to use\n\n- ✔ EmailValueObject\n- ✔ UserNameValueObject\n- ✔ BirthdayValueObject\n- ✔ CurrencyValueObject\n- ✔ PasswordValueObject\n- ✔ HomePhoneValueObject\n- ✔ MobilePhoneValueObject\n- ✔ TrackingCodeValueObject\n- ✔ RGBColorValueObject\n- ✔ HEXColorValueObject\n- ✔ PostalCodeValueObject\n- ✔ UrlValueObject\n- ✔ OrderStatusValueObject\n- ✔ PinValueObject\n- ✔ CPFValueObject\n- ✔ CNPJValueObject\n- ✔ CustomStringValueObject\n- ✔ CustomNumberValueObject\n- ✔ WeightUnitValueObject\n- ✔ UnitOfMeasureValueObject\n- ✔ DimensionValueObject\n- ✔ WeightValueObject\n- ✔ DateValueObject\n- ✔ getUndefinedKeysAsArray\n- ✔ getUndefinedKeysAsObject\n- ✔ removeUndefinedKeysFromObject\n- ✔ SpecificationComposite\n- ✔ FactoryMethod\n- ✔ TSProxy\n\n---\n\n\n#### Password\n\nJust import and use\n\n```ts\n\nconst passOrError = PasswordValueObject.create('my-strength-pass');\n\nconsole.log(passOrError.isOk());\n\n> true\n\nconst pass = passOrError.value();\n\npass.encrypt();\n\nconsole.log(pass.value());\n\n> \"$2a$12$AdLoTarjC5wnc1tAUc3j1.RczGxxImH0mG6dZkS5zPaGrTi/EmPWG\"\n\nconsole.log(pass.isEncrypted());\n\n> true\n\nconst passMatch = pass.compare('my-strength-pass');\n\nconsole.log(passMatch);\n\n> true\n\nconsole.log(PasswordValueObject.random(12).value());\n\n> \"WtS65$@!A6by\"\n\n```\n\nyou can define a custom range for password length and error message\n\n```ts\n\nReflect.set(PasswordValueObject, \"MIN_LENGTH\", 10);\nReflect.set(PasswordValueObject, \"MAX_LENGTH\", 20);\nReflect.set(PasswordValueObject, \"MESSAGE\", \"Password must be between 10 and 20 characters\");\n\n```\n\n#### Date\n\nJust import and use\n\n```ts\n\nconst currentDate = new Date();\n\nconst myDate = DateValueObject.create(currentDate).value();\n\nconsole.log(myDate.value());\n\n> \"2021-10-11T14:45:04.758Z\"\n\nconsole.log(myDate.format(\"DD-MM-YYYY\"));\n\n> \"11-10-2021\"\n\nmyDate.addDays(3);\n\nconsole.log(myDate.value());\n\n> \"2021-10-14T14:45:04.758Z\"\n\nconst isWeekend = myDate.isWeekend();\n\nconsole.log(isWeekend);\n\n> false\n\nmyDate.addHours(7);\n\nconst isAfter = myDate.isAfter(currentDate);\n\nconsole.log(isAfter);\n\n> true\n\n```\n\n#### Currency\n\nJust import and use\n\n```ts\n\nconst voOrErr = CurrencyValueObject.create({ currency: 'BRL', value: 0.50 });\n\nconst myCurrency = voOrErr.value();\n\nconsole.log(myCurrency.value());\n\n> 0.5\n\nmyCurrency.add(0.50); // 1\nmyCurrency.multiplyBy(50); // 50\nmyCurrency.divideBy(2); // 25\nmyCurrency.subtractBy(5); // 20\nmyCurrency.add(80); // 100\nmyCurrency.addPercent(2); // 102\nmyCurrency.subtractBy(2); // 100\nmyCurrency.subtractPercent(30); // 70\n\nconsole.log(myCurrency.value());\n\n> 70\n\nconsole.log(myCurrency.getCoin());\n\n> \"R$ 70.00\"\n\n// OR chain\n\nconst result = myCurrency.add(10).addPercent(21).multiplyBy(3).subtractBy(50);\n\n```\n\n\n#### Weight units\n\nJust import and use\n\n```ts\n\nconst result = WeightValueObject.create({ value: 1000, unit: \"TON\" });\n\nconsole.log(result.isOk());\n\n> true\n\nconst weight = result.value();\n\nconsole.log(weight.unit);\n\n> \"TON\"\n\nconsole.log(weight.weight.value());\n\n> 1000\n\n// Convert instance value and unit to KG\nweight.toKG();\n\nconsole.log(weight.unit);\n\n> \"KG\"\n\nconsole.log(weight.weight.value());\n> 1\n\n```\n\n#### Email\n\nJust import and use\n\n```ts\n\nconst result = EmailValueObject.create('dany@mailer.com');\n\nconsole.log(result.isOk());\n\n> true\n\nconst email = result.value();\n\nconsole.log(email.value());\n\n> \"dany@mailer.com\"\n\nconsole.log(email.getNick());\n\n> \"dany\"\n\nconsole.log(email.getDomain());\n\n> \"mailer.com\"\n\n\n```\n\nyou can block same domain or define only specific domains\n\n```ts\n\nReflect.set(EmailValueObject, \"BLOCKED_DOMAINS\", [\"microsoft.com\", \"leak.com\"]);\nReflect.set(EmailValueObject, \"VALID_DOMAINS\", [\"gmail.com\", \"hotmail.com\"]);\n\n// now only two domains are accepted gmail and hotmail\n\n```\n\n#### Name\n\nJust import and use\n\n```ts\n\nconst result = UserNameValueObject.create('jannie lan spark');\n\nconsole.log(result.isOk());\n\n> true\n\nconst name = result.value();\n\nconsole.log(name.value());\n\n> \"Jannie Lan Spark\"\n\nconsole.log(name.getLastName());\n\n> \"Spark\"\n\nconsole.log(name.getMiddleName());\n\n> \"Lan\"\n\nconsole.log(name.getFirstName());\n\n> \"Jannie\"\n\nconsole.log(name.getInitials());\n\n> \"J.L.S\"\n\n```\n\n\n#### BirthDay\n\nJust import and use\n\n```ts\n\nconst year2000 = new Date(2000, 1, 1);\n\nconst result = BirthdayValueObject.create(year2000);\n\nconsole.log(result.isOk());\n\n> true\n\nconst birthDay = result.value();\n\nconsole.log(birthDay.value());\n\n> \"2000-02-01T02:00:00.000Z\"\n\nconsole.log(birthDay.isAgeGreaterThan(18));\n\n> true\n\nconsole.log(birthDay.getAgeAsYearsOld());\n\n> 22\n\n\n```\n\n\n#### Custom string\n\n```ts\n// my-custom-string.ts\n\nimport { CustomStringValueObject } from 'types-ddd';\n\n\nReflect.set(CustomStringValueObject, 'VALIDATOR', (value: string) => typeof value === 'string');\nReflect.set(CustomStringValueObject, 'MESSAGE', \"my custom error message\");\n\nconst MyCustomString = CustomStringValueObject;\nexport MyCustomString;\nexport default MyCustomString;\n\n```\n\n#### Custom number\n\n```ts\n// my-custom-number.ts\n\nimport { CustomNumberValueObject } from 'types-ddd';\n\n\nReflect.set(CustomNumberValueObject, 'VALIDATOR', (value: string) => typeof value === 'number');\nReflect.set(CustomNumberValueObject, 'MESSAGE', \"my custom error message\");\n\nconst MyCustomNumber = CustomNumberValueObject;\nexport MyCustomNumber;\nexport default MyCustomNumber;\n\n```\n"
  },
  {
    "path": "global-setup.ts",
    "content": "process.env.TZ = 'UTC';"
  },
  {
    "path": "jest.config.ts",
    "content": "import './global-setup';\n\nmodule.exports = {\n\troots: ['<rootDir>'],\n\tcollectCoverage: false,\n\tcoverageDirectory: 'coverage',\n\ttestEnvironment: 'node',\n\ttransform: {\n\t\t'.+\\\\.ts$': 'ts-jest',\n\t},\n\tmoduleNameMapper: {\n\t\t'@type-ddd': '<rootDir>/lib/index',\n\t},\n};\n"
  },
  {
    "path": "lerna.json",
    "content": "{\n  \"packages\": [\n    \"packages/*\"\n  ],\n  \"version\": \"independent\"\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n\t\"name\": \"type-ddd\",\n\t\"version\": \"4.1.0\",\n\t\"description\": \"This package provide utils file and interfaces to assistant build a complex application with domain driving design\",\n\t\"main\": \"dist/index.js\",\n\t\"types\": \"dist/index.d.ts\",\n\t\"license\": \"ISC\",\n\t\"author\": \"Alessandro Dev\",\n\t\"private\": true,\n\t\"workspaces\": [\n\t\t\"packages/*\"\n\t],\n\t\"engines\": {\n\t\t\"node\": \">=16.x <=22\"\n\t},\n\t\"keywords\": [\n\t\t\"Complexity\",\n\t\t\"NodeJS\",\n\t\t\"Business Logic\",\n\t\t\"DDD\",\n\t\t\"Domain Driving Design\",\n\t\t\"Typescript\",\n\t\t\"DDD-Utils\",\n\t\t\"Base Entity\",\n\t\t\"Base Aggregate\",\n\t\t\"Base Value Object\",\n\t\t\"Use Cases\",\n\t\t\"Domain Events\",\n\t\t\"Clean Architecture\"\n\t],\n\t\"scripts\": {\n\t\t\"prebuild\": \"rimraf ./dist && npm run check:circular-deps\",\n\t\t\"build\": \"tsc -b -v packages\",\n\t\t\"build:lerna\": \"lerna run build\",\n\t\t\"test:prod\": \"NODE_ENV=production jest --silent --runInBand\",\n\t\t\"test:dev\": \"jest --silent --runInBand\",\n\t\t\"test:cov\": \"TYPES_DDD_LOGS=off jest --silent --runInBand --coverage\",\n\t\t\"test\": \"TYPES_DDD_LOGS=off jest --silent --runInBand --coverage\",\n\t\t\"test:verbose\": \"jest --runInBand\",\n\t\t\"check:circular-deps\": \"madge --circular --extensions ts ./packages\",\n\t\t\"prepublish:lib\": \"rimraf ./dist && npm run check:circular-deps\",\n\t\t\"publish:lib\": \"npm publish\",\n\t\t\"format:all\": \"npx prettier --write .\",\n\t\t\"check:types\": \"tsc -v packages --noEmit\"\n\t},\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"git+https://github.com/4lessandrodev/type-ddd.git\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/4lessandrodev/type-ddd/issues\"\n\t},\n\t\"homepage\": \"https://github.com/4lessandrodev/type-ddd/tree/main\",\n\t\"peerDependencies\": {\n\t\t\"rich-domain\": \"^1.25.0\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@types/jest\": \"^27.0.1\",\n\t\t\"@types/node\": \"^22.5.2\",\n\t\t\"@types/pino\": \"^7.0.5\",\n\t\t\"husky\": \"^9.0.6\",\n\t\t\"jest\": \"^27.5.1\",\n\t\t\"lerna\": \"^8.1.3\",\n\t\t\"lint-staged\": \"^15.0.1\",\n\t\t\"madge\": \"^8.0.0\",\n\t\t\"prettier\": \"^3.0.0\",\n\t\t\"rich-domain\": \"1.26.0\",\n\t\t\"rimraf\": \"^5.0.5\",\n\t\t\"ts-jest\": \"^27.1.4\",\n\t\t\"ts-node\": \"^10.7.0\",\n\t\t\"typescript\": \"^5.1.6\"\n\t},\n\t\"files\": [\n\t\t\"dist/*\",\n\t\t\"package.json\",\n\t\t\"packages/*/*.js\",\n\t\t\"packages/*/*.d.ts\",\n\t\t\"README.md\"\n\t],\n\t\"lint-staged\": {\n\t\t\"*\": [\n\t\t\t\"npm run format:all\",\n\t\t\t\"npx prettier --ignore-unknown --check\"\n\t\t],\n\t\t\"*.{ts,js}\": [\n\t\t\t\"npm run check:circular-deps\"\n\t\t]\n\t}\n}\n"
  },
  {
    "path": "packages/cnpj/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.0.4-alpha.0](https://github.com/4lessandrodev/type-ddd/compare/@type-ddd/cnpj@0.0.2...@type-ddd/cnpj@0.0.4-alpha.0) (2024-12-16)\n\n\n\n## 4.0.5 (2024-11-28)\n\n\n### Bug Fixes\n\n* change type create method return null [#194](https://github.com/4lessandrodev/type-ddd/issues/194) ([2cd03bf](https://github.com/4lessandrodev/type-ddd/commit/2cd03bf34387f4889a0a292ba350f2c0cfc753b7))\n\n\n\n## 4.0.3 (2024-07-26)\n\n\n\n\n\n# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n## Unreleased\n\n---\n\n## Released\n\n---\n\n### [0.0.3] - 2024-11-28\n\n### Fix\n\n- update rich-domain lib to check nullish type: now 'create' return a possibly null value in Result instance.\n\n### [0.0.2] - 2024-05-31\n\n### Docs\n\n- Doc: update documentation\n\n---\n\n### [0.0.1] - 2024-05-31\n\n### Base\n\n- Create base value object as single pack\n"
  },
  {
    "path": "packages/cnpj/README.md",
    "content": "# `@type-ddd/cnpj`\n\n> The @type-ddd/cnpj library provides TypeScript type definitions for handling CNPJ (Cadastro Nacional da Pessoa Jurídica) in Domain-Driven Design contexts. It facilitates the validation and manipulation of CNPJ numbers, ensuring they adhere to the Brazilian legal standards.\n\n---\n\n## Installation\n\nInstall `rich-domain` and `@type-ddd/cnpj` with your favorite package manager\n\n```sh\n\nnpm i rich-domain @type-ddd/cnpj\n\n# OR\n\nyarn add rich-domain @type-ddd/cnpj\n\n```\n\n## Usage\n\nDon't worry about removing special characters; they are automatically stripped from all instances.\n\n```ts\n\nimport { CNPJ } from '@type-ddd/cnpj'\n\n// Instance of CNPJ or throws an error if provide an invalid value\nconst cnpj = CNPJ.init('54097792000193');\n\n// OR\n\n// Result of CNPJ (Check Result pattern docs)\nconst result = CNPJ.create('54097792000193');\n\nresult.isOk(); // true\n\n// cnpj instance or null if provide an invalid value\nconst cnpj = result.value();\n\n```\n\n## Compare values or instances\n\nMethod to compare two instances or values.\n\n```ts\n\n// value as string \nconst isEqual = cnpj.compare('54097792000194')\n\n// Output: false\n\n// OR\n\n// value as instance of CNPJ\nconst isEqual = cnpj.compare(cnpj2)\n\n// Output: false\n\n```\n\n## Check string is valid cnpj\n\nDon't worry about removing special characters; they are automatically stripped from all instances.\n\n```ts\n\nconst result = CNPJ.isValid('54097792000193');\n\n// Output: true\n\n```\n\n## Special chars\n\nIf you need the value with the mask, you can use the `toPattern` method:\n\n```ts\n\ncnpj.toPattern();\n\n// Output: 54.097.792/0001-93\n\n```\n\nOr if you need to apply mask from a string value you may use `addMask` method\n\n\n```ts\n\nCNPJ.addMask('54097792000193');\n\n// Output: 54.097.792/0001-93\n\n```\n"
  },
  {
    "path": "packages/cnpj/__tests__/cnpj.value-object.util.spec.ts",
    "content": "import CNPJValueObject from '../index';\n\ndescribe('CNPJ Value Object', () => {\n\tdescribe('Creation and Definition', () => {\n\t\tit('should be able to create a CNPJ value object', () => {\n\t\t\tconst valueObject = CNPJValueObject.create;\n\t\t\texpect(valueObject).toBeDefined();\n\t\t});\n\n\t\tit('should create a valid CNPJ with special characters removed', () => {\n\t\t\tconst valueObject = CNPJValueObject.create('43.909.299/0001-04');\n\t\t\texpect(valueObject.isOk()).toBeTruthy();\n\t\t\texpect(valueObject.value()?.value()).toBe('43909299000104');\n\t\t});\n\n\t\tit('should create a valid CNPJ with numbers only', () => {\n\t\t\tconst valueObject = CNPJValueObject.create('60105617000101');\n\t\t\texpect(valueObject.isOk()).toBeTruthy();\n\t\t\texpect(valueObject.value()?.value()).toBe('60105617000101');\n\t\t});\n\n\t\tit('should initialize an instance without error', () => {\n\t\t\tconst init = () => CNPJValueObject.init('27729251000168');\n\t\t\texpect(init).not.toThrowError();\n\t\t});\n\n\t\tit('should throw an error when initializing with an invalid value', () => {\n\t\t\tconst init = () => CNPJValueObject.init('invalid');\n\t\t\texpect(init).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('Validation', () => {\n\t\tit('should return true for a valid CNPJ', () => {\n\t\t\tconst isValid = CNPJValueObject.isValid('43.909.299/0001-04');\n\t\t\texpect(isValid).toBeTruthy();\n\t\t});\n\n\t\tit('should return false for an invalid CNPJ', () => {\n\t\t\tconst isValid = CNPJValueObject.isValid('invalid');\n\t\t\texpect(isValid).toBeFalsy();\n\t\t});\n\n\t\tit('should fail for an invalid CNPJ', () => {\n\t\t\tconst valueObject = CNPJValueObject.create('53.462.048/0000-99');\n\t\t\texpect(valueObject.isFail()).toBeTruthy();\n\t\t});\n\n\t\tit('should fail for an invalid CNPJ (digit sum)', () => {\n\t\t\tconst valueObject = CNPJValueObject.create('93.118.559/0001-1');\n\t\t\texpect(valueObject.isFail()).toBeTruthy();\n\t\t});\n\n\t\tit('should fail for an invalid CNPJ (digit sum)', () => {\n\t\t\tconst valueObject = CNPJValueObject.create('93.118.559/0001-100');\n\t\t\texpect(valueObject.isFail()).toBeTruthy();\n\t\t});\n\t});\n\n\tdescribe('Formatting', () => {\n\t\tit('should format a CNPJ with special characters', () => {\n\t\t\tconst valueObject =\n\t\t\t\tCNPJValueObject.create('20.798.751/0001-02').value();\n\t\t\texpect(valueObject?.toPattern()).toBe('20.798.751/0001-02');\n\t\t});\n\n\t\tit('should format a CNPJ with special characters', () => {\n\t\t\tconst valueObject =\n\t\t\t\tCNPJValueObject.create('65.389.009/0001-81').value();\n\t\t\texpect(valueObject?.toPattern()).toBe('65.389.009/0001-81');\n\t\t});\n\n\t\tit('should format a CNPJ with special characters', () => {\n\t\t\tconst valueObject =\n\t\t\t\tCNPJValueObject.create('02.470.431/0001-47').value();\n\t\t\texpect(valueObject?.toPattern()).toBe('02.470.431/0001-47');\n\t\t});\n\n\t\tit('should format a CNPJ with special characters and remove them later', () => {\n\t\t\tconst valueObject =\n\t\t\t\tCNPJValueObject.create('62.412.404/0001-40').value();\n\t\t\texpect(valueObject?.toPattern()).toBe('62.412.404/0001-40');\n\t\t});\n\t});\n\n\tdescribe('Comparison', () => {\n\t\tit('should correctly compare the value in the instance with the provided value', () => {\n\t\t\tconst validCNPJ = '22.606.062/0001-84';\n\t\t\tconst valueObject = CNPJValueObject.create(validCNPJ).value();\n\t\t\n\t\t\t// Compare with invalid CNPJ\n\t\t\tlet isEqual = valueObject?.compare('invalid');\n\t\t\texpect(isEqual).toBeFalsy();\n\t\t\n\t\t\t// Compare with different valid CNPJ\n\t\t\tisEqual = valueObject?.compare('22.606.062/0001-20');\n\t\t\texpect(isEqual).toBeFalsy();\n\t\t\n\t\t\t// Compare with the same valid CNPJ\n\t\t\tisEqual = valueObject?.compare(validCNPJ);\n\t\t\texpect(isEqual).toBeTruthy();\n\t\t\n\t\t\t// Compare with a valid CNPJ with different format\n\t\t\tisEqual = valueObject?.compare('22606062000155');\n\t\t\texpect(isEqual).toBeFalsy();\n\t\t\n\t\t\t// Compare with a valid CNPJ with the same value but different format\n\t\t\tisEqual = valueObject?.compare('22606062000184');\n\t\t\texpect(isEqual).toBeTruthy();\n\t\t\n\t\t\t// Compare with the same valid CNPJ\n\t\t\tisEqual = valueObject?.compare('22.606.062/0001-84');\n\t\t\texpect(isEqual).toBeTruthy();\n\t\t});\n\n\t\tit('should compare two instances', () => {\n\n\t\t\tconst instanceA = CNPJValueObject.init('22.606.062/0001-84');\n\t\t\tconst instanceB = CNPJValueObject.init('22.606.062/0001-84');\n\n\t\t\texpect(instanceA.compare(instanceB)).toBeTruthy();\n\t\t});\n\n\t\tit('should return false when comparing with null', () => {\n\t\t\tconst instanceA = CNPJValueObject.init('22.606.062/0001-84');\n\t\t\texpect(instanceA.compare(null as any)).toBeFalsy();\n\t\t});\n\t});\n\n\tdescribe('Special Character Removal', () => {\n\t\tit('should remove special characters from a string', () => {\n\t\t\tconst value = CNPJValueObject.removeSpecialChars('93.118.559/0001-10');\n\t\t\texpect(value).toBe('93118559000110');\n\t\t});\n\n\t\tit('should remove special characters from a string', () => {\n\t\t\tconst value = CNPJValueObject.addMask('93118559000110');\n\t\t\texpect(value).toBe('93.118.559/0001-10');\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/cnpj/__tests__/is-valid-cpf-digit.util.spec.ts",
    "content": "import { formatValueToCnpjPattern, isValidCnpjDigit, removeSpecialCharsFromCnpj } from '../util';\n\ndescribe('is-valid-cnpj-digits', () => {\n\tit('should be defined', () => {\n\t\tconst isValidCnpjDigitFn = isValidCnpjDigit;\n\t\texpect(isValidCnpjDigitFn).toBeDefined();\n\t});\n\n\tit('should return false if provide a value less than 11 char', () => {\n\t\tconst isValidCnpjDigitFn = isValidCnpjDigit('506595900001');\n\t\texpect(isValidCnpjDigitFn).toBe(false);\n\t});\n\n\tit('should return false if provide word instead numbers', () => {\n\t\tconst isValidCnpjDigitFn = isValidCnpjDigit('invalid_val');\n\t\texpect(isValidCnpjDigitFn).toBe(false);\n\t});\n\n\tit('should return false if provide a value with invalid sum', () => {\n\t\tconst isValidCnpjDigitFn = isValidCnpjDigit('39.060.118/0001-41');\n\t\texpect(isValidCnpjDigitFn).toBe(false);\n\t});\n\n\tit('should return false if provide a value with invalid sum', () => {\n\t\tconst isValidCnpjDigitFn = isValidCnpjDigit('50659590000140');\n\t\texpect(isValidCnpjDigitFn).toBe(false);\n\t});\n\n\tit('should return true and validate with success', () => {\n\t\tconst isValidCnpjDigitFn = isValidCnpjDigit('50659590000137');\n\t\texpect(isValidCnpjDigitFn).toBe(true);\n\t});\n\n\tit('should return true and validate with success', () => {\n\t\tconst isValidCnpjDigitFn = isValidCnpjDigit('05.718.081/0001-83');\n\t\texpect(isValidCnpjDigitFn).toBe(true);\n\t});\n\n\tit('should return true and validate with success', () => {\n\t\tconst isValidCnpjDigitFn = isValidCnpjDigit('39.434.735/0001-69');\n\t\texpect(isValidCnpjDigitFn).toBe(true);\n\t});\n\n\tit('should return true and validate with success', () => {\n\t\tconst isValidCnpjDigitFn = isValidCnpjDigit('47.091.193/0001-05');\n\t\texpect(isValidCnpjDigitFn).toBe(true);\n\t});\n\n\tit('should format cnpj from pattern to only numbers', () => {\n\t\tconst isValidCnpjDigitFn =\n\t\t\tremoveSpecialCharsFromCnpj('39.604.284/0001-60');\n\t\texpect(isValidCnpjDigitFn).toBe('39604284000160');\n\t});\n\n\tit('should format cnpj from pattern to only numbers', () => {\n\t\tconst isValidCnpjDigitFn = removeSpecialCharsFromCnpj('39604284000160');\n\t\texpect(isValidCnpjDigitFn).toBe('39604284000160');\n\t});\n\n\tit('should format cnpj from pattern to only numbers', () => {\n\t\tconst isValidCnpjDigitFn =\n\t\t\tremoveSpecialCharsFromCnpj('val.cnpj.str-d0');\n\t\texpect(isValidCnpjDigitFn).toBe('valcnpjstrd0');\n\t});\n\n\tit('should format cnpj from only numbers to pattern', () => {\n\t\tconst isValidCnpjDigitFn = formatValueToCnpjPattern('39604284000160');\n\t\texpect(isValidCnpjDigitFn).toBe('39.604.284/0001-60');\n\t});\n\n\tit('should format cnpj from only numbers to pattern', () => {\n\t\tconst isValidCnpjDigitFn = formatValueToCnpjPattern('39604284000160');\n\t\texpect(isValidCnpjDigitFn).toBe('39.604.284/0001-60');\n\t});\n\n\tit('should format cnpj from only numbers to pattern', () => {\n\t\tconst isValidCnpjDigitFn = formatValueToCnpjPattern('vacnppj00strd0');\n\t\texpect(isValidCnpjDigitFn).toBe('va.cnp.pj0/0str-d0');\n\t});\n});\n"
  },
  {
    "path": "packages/cnpj/index.ts",
    "content": "import { Result, ValueObject } from 'rich-domain';\nimport isValidCnpjDigit, { formatValueToCnpjPattern, removeSpecialCharsFromCnpj } from './util';\n\nconst regexCnpj =\n\t/^([0-9]{2})[\\.]([0-9]{3})[\\.]((?!\\2)[0-9]{3})[\\/]([0-9]{4})[-]([0-9]{2})$|^[0-9]{14}$/;\n\n\nexport class CNPJ extends ValueObject<string> {\n\tprotected static readonly REGEX = regexCnpj;\n\tprotected static readonly MESSAGE: string = 'Invalid value for cnpj';\n\n\tprivate constructor(props: string) {\n\t\tsuper(props);\n\t}\n\n\t/**\n\t * @description return a cnpj value (only numbers).\n\t * @example example \"22398345000188\".\n\t * @summary If you want cnpj as pattern use `formatToCnpjPattern` before get value.\n\t */\n\tvalue(): string {\n\t\treturn this.props;\n\t}\n\n\t/**\n\t * @description add hyphen and dot to cnpj value.\n\t * @example before \"22398345000188\"\n\t * @example after \"22.398.345/0001-88\"\n\t */\n\ttoPattern(): string {\n\t\treturn formatValueToCnpjPattern(this.props);\n\t}\n\n\t/**\n\t * @description add hyphen and dot to cnpj value.\n\t * @example before \"22398345000188\"\n\t * @example after \"22.398.345/0001-88\"\n\t */\n\tpublic static addMask(cnpj: string): string {\n\t\treturn formatValueToCnpjPattern(cnpj);\n\t}\n\n\t/**\n\t * @description remove hyphen and dot from cnpj value.\n\t * @example before \"22.398.345/0001-88\"\n\t * @example after \"22398345000188\"\n\t */\n\tpublic static removeSpecialChars(cnpj: string): string {\n\t\treturn removeSpecialCharsFromCnpj(cnpj);\n\t}\n\n\t/**\n\t *\n\t * @param cnpj value as string only number or pattern.\n\t * @returns true if cnpj match with instance value and false if not.\n\t * @example param \"22398345000188\"\n\t * @example param \"22.398.345/0001-88\"\n\t */\n\tcompare(cnpj: string | CNPJ): boolean {\n\t\tif (typeof cnpj === 'string') {\n\t\t\tconst formattedCnpj = removeSpecialCharsFromCnpj(cnpj);\n\t\t\tconst instanceValue = this.props;\n\t\t\treturn instanceValue === formattedCnpj;\n\t\t}\n\t\tif (cnpj instanceof CNPJ) {\n\t\t\treturn cnpj.isEqual(this);\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * @description check if cnpj value is a valid pattern and has a valid digit sum.\n\t * @param value cnpj as string\n\t * @returns true if value is valid and false if not.\n\t * @example \"22.398.345/0001-88\"\n\t * @example \"22398345000188\"\n\t */\n\tpublic static isValidProps(value: string): boolean {\n\t\tconst isValidPattern = CNPJ.REGEX.test(value);\n\t\tconst isValidDigits = isValidCnpjDigit(value);\n\t\treturn isValidDigits && isValidPattern;\n\t}\n\n\t/**\n\t * @description check if cnpj value is a valid pattern and has a valid digit sum.\n\t * @param value cnpj as string\n\t * @returns true if value is valid and false if not.\n\t * @example \"22.398.345/0001-88\"\n\t * @example \"22398345000188\"\n\t */\n\tpublic static isValid(value: string): boolean {\n\t\treturn this.isValidProps(value);\n\t}\n\n\t/**\n\t * \n\t * @param value value as string\n\t * @returns instance of CNPJ or throw an error\n\t */\n\tpublic static init(value: string): CNPJ {\n\t\tconst isValidValue = CNPJ.isValidProps(value);\n\t\tif (!isValidValue) throw new Error(CNPJ.MESSAGE);\n\t\treturn new CNPJ(value);\n\t}\n\n\t/**\n\t * @description create a cnpj value object\n\t * @param value cnpj numbers as string\n\t * @returns instance of Result with cnpj value\n\t * @example \"22.398.345/0001-88\"\n\t * @example \"22398345000188\"\n\t * @summary fails if provide an invalid pattern or a cnpj with invalid digit sum\n\t */\n\tpublic static create(value: string): Result<CNPJ | null> {\n\t\tconst isValidValue = CNPJ.isValidProps(value);\n\n\t\tif (!isValidValue) {\n\t\t\treturn Result.fail(CNPJ.MESSAGE);\n\t\t}\n\n\t\treturn Result.Ok(new CNPJ(removeSpecialCharsFromCnpj(value)));\n\t}\n}\n\nexport default CNPJ;\n"
  },
  {
    "path": "packages/cnpj/package.json",
    "content": "{\n  \"name\": \"@type-ddd/cnpj\",\n  \"description\": \"Library that provides TypeScript type definitions for handling CNPJ (Cadastro Nacional da Pessoa Jurídica) in Domain-Driven Design contexts. It facilitates the validation and manipulation of CNPJ numbers, ensuring they adhere to the Brazilian legal standards.\",\n  \"version\": \"0.1.0\",\n  \"main\": \"index.js\",\n  \"types\": \"index.d.ts\",\n  \"author\": \"Alessandro Dev\",\n  \"license\": \"MIT\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"keywords\": [\n    \"Complexity\",\n    \"Business Logic\",\n    \"DDD\",\n    \"Domain Driving Design\",\n    \"DDD-Utils\",\n    \"Base Value Object\",\n    \"Domain Events\",\n    \"Clean Architecture\",\n    \"Validation\",\n    \"Formatting\",\n    \"Value Object\",\n    \"Utility\",\n    \"Security\",\n    \"Standards\",\n    \"Brazil\",\n    \"CNPJ\",\n    \"Cadastro Nacional Pessoa Jurídica\",\n    \"Pessoa Jurídica\"\n  ],\n  \"scripts\": {\n    \"build\": \"tsc\"\n  },\n  \"peerDependencies\": {\n    \"rich-domain\": \"^1.25.0\"\n  },\n  \"files\": [\n    \"index.js\",\n    \"index.d.ts\",\n    \"util.d.ts\",\n    \"util.js\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/4lessandrodev/type-ddd.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/4lessandrodev/type-ddd/issues\"\n  },\n  \"homepage\": \"https://github.com/4lessandrodev/type-ddd/tree/main/packages/cnpj\",\n  \"gitHead\": \"4cb9159bde8d6fc951e9d902feed2ad25da49fa4\"\n}\n"
  },
  {
    "path": "packages/cnpj/tsconfig.build.json",
    "content": "{\n    \"extends\": \"../tsconfig.build.json\",\n    \"compilerOptions\": {\n        \"outDir\": \".\",\n        \"rootDir\": \".\",\n        \"paths\": {}\n    },\n    \"exclude\": [\n        \"node_modules\",\n        \"dist\",\n        \"__tests__/**/*\",\n        \"*.spec.ts\"\n    ],\n    \"references\": []\n}"
  },
  {
    "path": "packages/cnpj/tsconfig.json",
    "content": "{\n\t\"extends\": \"../tsconfig.build.json\",\n\t\"compilerOptions\": {\n\t\t\"types\": [\n\t\t\t\"node\"\n\t\t]\n\t},\n\t\"files\": [],\n\t\"include\": [],\n\t\"references\": [\n\t\t{\n\t\t\t\"path\": \"./tsconfig.build.json\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "packages/cnpj/util.ts",
    "content": "interface CnpjDigits {\n\tpenultimateDigit: number;\n\tultimateDigit: number;\n}\n\nconst removeSpecialCharsFromCnpjRegex = /[\\.]|[-]|[\\/]/g;\n\nexport const formatValueToCnpjPattern = (cnpj: string): string => {\n\tconst cnpjValue = removeSpecialCharsFromCnpj(cnpj);\n\tlet formattedValue: string = '';\n\tlet index: number = 0;\n\n\twhile (formattedValue.length < 18 && index < 17) {\n\t\tif (index === 2 || index === 5) {\n\t\t\tformattedValue += '.';\n\t\t} else if (index === 8) {\n\t\t\tformattedValue += '/';\n\t\t} else if (index === 12) {\n\t\t\tformattedValue += '-';\n\t\t}\n\t\tformattedValue += cnpjValue[index];\n\t\tindex++;\n\t}\n\n\treturn formattedValue;\n};\n\nexport const removeSpecialCharsFromCnpj = (cnpj: string): string => {\n\treturn cnpj.replace(removeSpecialCharsFromCnpjRegex, '');\n};\n\nconst getCnpjDigitsNumbers = (cnpj: string): CnpjDigits => {\n\tconst lastTwoNumbers = cnpj.slice(cnpj.length - 2);\n\tconst penultimateDigit = parseInt(lastTwoNumbers[0]);\n\tconst ultimateDigit = parseInt(lastTwoNumbers[1]);\n\n\treturn {\n\t\tpenultimateDigit,\n\t\tultimateDigit,\n\t};\n};\n\nconst transformCnpjInArrNumber = (cnpj: string): number[] => {\n\tvar arr: number[] = [];\n\n\tlet index = 0;\n\twhile (index < 12) {\n\t\tarr.push(parseInt(cnpj[index]));\n\t\tindex++;\n\t}\n\n\treturn arr;\n};\n\nconst calculateCnpjDigits = (cnpjNumbers: number[]): CnpjDigits => {\n\tconst factor = 11;\n\tlet index = cnpjNumbers.length - 1;\n\tlet startAuxValue = 2;\n\tlet totalForDigit = 0;\n\n\twhile (index >= 0) {\n\t\ttotalForDigit = totalForDigit + cnpjNumbers[index] * startAuxValue;\n\t\tstartAuxValue = startAuxValue === 9 ? 2 : startAuxValue + 1;\n\t\tindex--;\n\t}\n\n\tconst calcPDigit = totalForDigit % factor;\n\tconst resultPDigit = factor - calcPDigit;\n\tconst zeroIfPGreaterThanNine = resultPDigit >= 9 ? 0 : resultPDigit;\n\tconst penultimateDigit = zeroIfPGreaterThanNine;\n\n\tcnpjNumbers.push(penultimateDigit);\n\n\tindex = cnpjNumbers.length - 1;\n\tstartAuxValue = 2;\n\ttotalForDigit = 0;\n\n\twhile (index >= 0) {\n\t\ttotalForDigit = totalForDigit + cnpjNumbers[index] * startAuxValue;\n\t\tstartAuxValue = startAuxValue === 9 ? 2 : startAuxValue + 1;\n\t\tindex--;\n\t}\n\n\tconst calcUDigit = totalForDigit % factor;\n\tconst resultUDigit = factor - calcUDigit;\n\tconst zeroIfGreaterThanNine = resultUDigit > 9 ? 0 : resultUDigit;\n\tconst ultimateDigit = zeroIfGreaterThanNine;\n\n\treturn {\n\t\tpenultimateDigit,\n\t\tultimateDigit,\n\t};\n};\n\nexport const isValidCnpjDigit = (cnpj: string): boolean => {\n\tconst onlyNumbers = removeSpecialCharsFromCnpj(cnpj);\n\n\tif (onlyNumbers.length !== 14) {\n\t\treturn false;\n\t}\n\n\tconst digits = getCnpjDigitsNumbers(onlyNumbers);\n\tconst arrNumbers = transformCnpjInArrNumber(onlyNumbers);\n\tconst validDigits = calculateCnpjDigits(arrNumbers);\n\n\treturn (\n\t\tdigits.penultimateDigit === validDigits.penultimateDigit &&\n\t\tdigits.ultimateDigit === validDigits.ultimateDigit\n\t);\n};\n\nexport default isValidCnpjDigit;\n"
  },
  {
    "path": "packages/cpf/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.0.4-alpha.0](https://github.com/4lessandrodev/type-ddd/compare/@type-ddd/cpf@0.0.2...@type-ddd/cpf@0.0.4-alpha.0) (2024-12-16)\n\n\n\n## 4.0.5 (2024-11-28)\n\n\n### Bug Fixes\n\n* change type create method return null [#194](https://github.com/4lessandrodev/type-ddd/issues/194) ([2cd03bf](https://github.com/4lessandrodev/type-ddd/commit/2cd03bf34387f4889a0a292ba350f2c0cfc753b7))\n\n\n\n## 4.0.3 (2024-07-26)\n\n\n\n\n\n# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n## Unreleased\n\n---\n\n## Released\n\n---\n\n### [0.0.3] - 2024-11-28\n\n### Fix\n\n- update rich-domain lib to check nullish type: now 'create' return a possibly null value in Result instance.\n\n### [0.0.2] - 2024-05-31\n\n### Docs\n\n- Doc: update documentation\n\n---\n\n### [0.0.1] - 2024-05-14\n\n### Base\n\n- Create base value object as single pack\n"
  },
  {
    "path": "packages/cpf/README.md",
    "content": "# `@type-ddd/cpf`\n\n> The @type-ddd/cpf library provides TypeScript type definitions for handling CPF (Cadastro de Pessoa Física) in Domain-Driven Design contexts. It facilitates the validation and manipulation of CPF numbers, ensuring they adhere to the Brazilian legal standards.\n\n---\n\n## Installation\n\nInstall `rich-domain` and `@type-ddd/cpf` with your favorite package manager\n\n```sh\n\nnpm i rich-domain @type-ddd/cpf\n\n# OR\n\nyarn add rich-domain @type-ddd/cpf\n\n```\n\n## Usage\n\nDon't worry about removing special characters; they are automatically stripped from all instances.\n\n```ts\n\nimport { CPF } from '@type-ddd/cpf'\n\n// Instance of cpf or throws an error if provide an invalid value\nconst cpf = CPF.init('54097792000193');\n\n// OR\n\n// Result of cpf (Check Result pattern docs)\nconst result = CPF.create('54097792000193');\n\nresult.isOk(); // true\n\n// cpf instance or null if provide an invalid value\nconst cpf = result.value();\n\n```\n\n## Compare values or instances\n\nMethod to compare two instances or values.\n\n```ts\n\n// value as string \nconst isEqual = cpf.compare('54097792000194')\n\n// Output: false\n\n// OR\n\n// value as instance of cpf\nconst isEqual = cpf.compare(cpf2)\n\n// Output: false\n\n```\n\n## Check string is valid cpf\n\nDon't worry about removing special characters; they are automatically stripped from all instances.\n\n```ts\n\nconst result = CPF.isValid('54097792000193');\n\n// Output: true\n\n```\n\n## Special chars\n\nIf you need the value with the mask, you can use the `toPattern` method:\n\n```ts\n\ncpf.toPattern();\n\n// Output: 54.097.792/0001-93\n\n```\n\nOr if you need to apply mask from a string value you may use `addMask` method\n\n\n```ts\n\nCPF.addMask('54097792000193');\n\n// Output: 54.097.792/0001-93\n\n```\n"
  },
  {
    "path": "packages/cpf/__tests__/cpf.value-object.util.spec.ts",
    "content": "import CPFValueObject from \"../index\";\n\ndescribe('cpf.value-object', () => {\n\tit('should be defined', () => {\n\t\tconst valueObject = CPFValueObject.create;\n\t\texpect(valueObject).toBeDefined();\n\t});\n\n\tit('should create a valid cpf with special chars and remove special chars on get value', () => {\n\t\tconst valueObject = CPFValueObject.create('667.324.914-58');\n\t\texpect(valueObject.isOk()).toBeTruthy();\n\t\texpect(valueObject.value()?.value()).toBe('66732491458');\n\t});\n\n\tit('should create a valid cpf with special chars and remove special chars on get value', () => {\n\t\tconst valueObject = CPFValueObject.create('934.665.143-12');\n\t\texpect(valueObject.isOk()).toBeTruthy();\n\t\texpect(valueObject.value()?.value()).toBe('93466514312');\n\t});\n\n\tit('should create a valid cpf with special chars and remove special chars on get value', () => {\n\t\tconst valueObject = CPFValueObject.create('690.574.738-60');\n\t\texpect(valueObject.isOk()).toBeTruthy();\n\t\texpect(valueObject.value()?.value()).toBe('69057473860');\n\t});\n\n\tit('should create a valid cpf with special chars and remove special chars on get value', () => {\n\t\tconst valueObject = CPFValueObject.create('324.123.359-66');\n\t\texpect(valueObject.isOk()).toBeTruthy();\n\t\texpect(valueObject.value()?.value()).toBe('32412335966');\n\t});\n\n\tit('should create a valid cpf with special chars and remove special chars on get value', () => {\n\t\tconst valueObject = CPFValueObject.create('673.761.543-02');\n\t\texpect(valueObject.isOk()).toBeTruthy();\n\t\texpect(valueObject.value()?.value()).toBe('67376154302');\n\t});\n\n\tit('should create a valid cpf with special chars and remove special chars on get value', () => {\n\t\tconst valueObject = CPFValueObject.create('024.815.901-12');\n\t\texpect(valueObject.isOk()).toBeTruthy();\n\t\texpect(valueObject.value()?.value()).toBe('02481590112');\n\t});\n\n\tit('should create a valid cpf with special chars and remove special chars on get value', () => {\n\t\tconst valueObject = CPFValueObject.create('754.179.880-06');\n\t\texpect(valueObject.isOk()).toBeTruthy();\n\t\texpect(valueObject.value()?.value()).toBe('75417988006');\n\t});\n\n\tit('should format a cpf to add special chars', () => {\n\t\tconst valueObject = CPFValueObject.create('667.324.914-58').value();\n\t\texpect(valueObject?.toPattern()).toBe('667.324.914-58');\n\t});\n\n\tit('should format a cpf to add special chars', () => {\n\t\tconst valueObject = CPFValueObject.create('578.363.883-87').value();\n\t\texpect(valueObject?.toPattern()).toBe('578.363.883-87');\n\t});\n\n\tit('should format a cpf to add special chars', () => {\n\t\tconst valueObject = CPFValueObject.create('844.676.543-80').value();\n\t\texpect(valueObject?.toPattern()).toBe('844.676.543-80');\n\t});\n\n\tit('should format a cpf to add special chars and remove it later', () => {\n\t\tconst valueObject = CPFValueObject.create('667.324.914-58').value();\n\t\texpect(valueObject?.toPattern()).toBe('667.324.914-58');\n\t\texpect(valueObject?.value()).toBe('66732491458');\n\t});\n\n\tit('should compare value on instance and provided value', () => {\n\t\tconst valueObject = CPFValueObject.create('549.777.281-14').value();\n\t\tlet isEqual = valueObject?.compare('invalid');\n\t\texpect(isEqual).toBeFalsy();\n\n\t\tisEqual = valueObject?.compare('549.777.281-15');\n\t\texpect(isEqual).toBeFalsy();\n\n\t\tisEqual = valueObject?.compare('549.777.281-14');\n\t\texpect(isEqual).toBeTruthy();\n\n\t\tisEqual = valueObject?.compare('54977728314');\n\t\texpect(isEqual).toBeFalsy();\n\n\t\tisEqual = valueObject?.compare('54977728114');\n\t\texpect(isEqual).toBeTruthy();\n\n\t\tisEqual = valueObject?.compare('54977728114');\n\t\texpect(isEqual).toBeTruthy();\n\n\t\tisEqual = valueObject?.compare('549.777.281-14');\n\t\texpect(isEqual).toBeTruthy();\n\t});\n\n\tit('should create a valid cpf only numbers', () => {\n\t\tconst valueObject = CPFValueObject.create('53534317661');\n\t\texpect(valueObject.isOk()).toBeTruthy();\n\t\texpect(valueObject.value()?.value()).toBe('53534317661');\n\t\texpect(CPFValueObject.isValid('53534317661')).toBeTruthy();\n\t});\n\n\tit('should fail if provide an invalid value', () => {\n\t\tconst valueObject = CPFValueObject.create('754.466.282-920');\n\t\texpect(valueObject.isFail()).toBeTruthy();\n\t});\n\n\tit('should fail if provide an invalid value (digit sum)', () => {\n\t\tconst valueObject = CPFValueObject.create('754.466.282-01');\n\t\texpect(valueObject.isFail()).toBeTruthy();\n\t});\n\n\tit('should fail if provide an invalid value (digit sum)', () => {\n\t\tconst valueObject = CPFValueObject.create('75446628201');\n\t\texpect(valueObject.isFail()).toBeTruthy();\n\t});\n\n\tit('should create a valid cpf only numbers', () => {\n\t\tconst valueObject = CPFValueObject.create('53534317661');\n\t\texpect(valueObject.isOk()).toBeTruthy();\n\t\texpect(valueObject.value()?.value()).toBe('53534317661');\n\t});\n\n\tit('should create a valid cpf only numbers', () => {\n\t\tconst valueObject = CPFValueObject.create('98614591039');\n\t\texpect(valueObject.isOk()).toBeTruthy();\n\t\texpect(valueObject.value()?.value()).toBe('98614591039');\n\t});\n\n\tit('should init an instance with success', () => {\n\t\tconst init = () => CPFValueObject.init('53534317661');\n\t\texpect(init).not.toThrowError();\n\t});\n\n\tit('should throw an error on init an instance with invalid value', () => {\n\t\tconst init = () => CPFValueObject.init('invalid');\n\t\texpect(init).toThrowError();\n\t});\n\n\tit('should add mask with success', () => {\n\t\tconst result = CPFValueObject.addMask('53534317661');\n\t\texpect(result).toBe('535.343.176-61');\n\t});\n\n\tit('should remove mask with success', () => {\n\t\tconst result = CPFValueObject.removeSpecialChars('535.343.176-61');\n\t\texpect(result).toBe('53534317661');\n\t});\n\n\tit('should compare cpf instances with success', () => {\n\t\tconst cpfA = CPFValueObject.init('535.343.176-61');\n\t\tconst cpfB = CPFValueObject.init('53534317661');\n\t\tconst cpfC = CPFValueObject.init('89926097014');\n\n\t\texpect(cpfA.compare(cpfB)).toBeTruthy();\n\t\texpect(cpfA.compare(cpfC)).toBeFalsy();\n\t\texpect(cpfC.compare(123 as any)).toBeFalsy();\n\t});\n});\n"
  },
  {
    "path": "packages/cpf/__tests__/is-valid-cpf-digit.util.spec.ts",
    "content": "import isValidCpfDigit, { formatValueToCpfPattern, removeSpecialCharsFromCpf } from \"../util\";\n\ndescribe('is-valid-cpf-digits', () => {\n\tit('should be defined', () => {\n\t\tconst isValidCpfDigitFn = isValidCpfDigit;\n\t\texpect(isValidCpfDigitFn).toBeDefined();\n\t});\n\n\tit('should return false if provide a value less than 11 char', () => {\n\t\tconst isValidCpfDigitFn = isValidCpfDigit('727254778');\n\t\texpect(isValidCpfDigitFn).toBe(false);\n\t});\n\n\tit('should return false if provide word instead numbers', () => {\n\t\tconst isValidCpfDigitFn = isValidCpfDigit('invalid_val');\n\t\texpect(isValidCpfDigitFn).toBe(false);\n\t});\n\n\tit('should return false if provide a value with invalid sum', () => {\n\t\tconst isValidCpfDigitFn = isValidCpfDigit('766.682.694-01');\n\t\texpect(isValidCpfDigitFn).toBe(false);\n\t});\n\n\tit('should return false if provide a value with invalid sum', () => {\n\t\tconst isValidCpfDigitFn = isValidCpfDigit('76668269401');\n\t\texpect(isValidCpfDigitFn).toBe(false);\n\t});\n\n\tit('should return true and validate with success', () => {\n\t\tconst isValidCpfDigitFn = isValidCpfDigit('76668269400');\n\t\texpect(isValidCpfDigitFn).toBe(true);\n\t});\n\n\tit('should return true and validate with success', () => {\n\t\tconst isValidCpfDigitFn = isValidCpfDigit('730.208.487-41');\n\t\texpect(isValidCpfDigitFn).toBe(true);\n\t});\n\n\tit('should return true and validate with success', () => {\n\t\tconst isValidCpfDigitFn = isValidCpfDigit('641.482.734-79');\n\t\texpect(isValidCpfDigitFn).toBe(true);\n\t});\n\n\tit('should return true and validate with success', () => {\n\t\tconst isValidCpfDigitFn = isValidCpfDigit('48153676474');\n\t\texpect(isValidCpfDigitFn).toBe(true);\n\t});\n\n\tit('should format cpf from pattern to only numbers', () => {\n\t\tconst isValidCpfDigitFn = removeSpecialCharsFromCpf('641.482.734-79');\n\t\texpect(isValidCpfDigitFn).toBe('64148273479');\n\t});\n\n\tit('should format cpf from pattern to only numbers', () => {\n\t\tconst isValidCpfDigitFn = removeSpecialCharsFromCpf('64148273479');\n\t\texpect(isValidCpfDigitFn).toBe('64148273479');\n\t});\n\n\tit('should format cpf from pattern to only numbers', () => {\n\t\tconst isValidCpfDigitFn = removeSpecialCharsFromCpf('val.cpf.str-d0');\n\t\texpect(isValidCpfDigitFn).toBe('valcpfstrd0');\n\t});\n\n\tit('should format cpf from only numbers to pattern', () => {\n\t\tconst isValidCpfDigitFn = formatValueToCpfPattern('64148273479');\n\t\texpect(isValidCpfDigitFn).toBe('641.482.734-79');\n\t});\n\n\tit('should format cpf from only numbers to pattern', () => {\n\t\tconst isValidCpfDigitFn = formatValueToCpfPattern('64148273479');\n\t\texpect(isValidCpfDigitFn).toBe('641.482.734-79');\n\t});\n\n\tit('should format cpf from only numbers to pattern', () => {\n\t\tconst isValidCpfDigitFn = formatValueToCpfPattern('valcpfstrd0');\n\t\texpect(isValidCpfDigitFn).toBe('val.cpf.str-d0');\n\t});\n\n\tit('should to be valid cpf', () => {\n\t\tconst isValid = isValidCpfDigit('15173713097');\n\t\texpect(isValid).toBeTruthy();\n\t});\n});\n"
  },
  {
    "path": "packages/cpf/index.ts",
    "content": "import { Result, ValueObject } from \"rich-domain\";\nimport isValidCpfDigit, { formatValueToCpfPattern } from \"./util\";\n\nexport class CPF extends ValueObject<string> {\n\tprotected static readonly REGEX = /^([0-9]{3})[\\.]((?!\\1)[0-9]{3})[\\.]([0-9]{3})[-]([0-9]{2})$|^[0-9]{11}$/;\n\tprotected static readonly MESSAGE: string = 'Invalid value for cpf';\n\n\tprivate constructor(value: string) {\n\t\tsuper(value);\n\t}\n\n\t/**\n\t * @description return a cpf value (only numbers).\n\t * @example example \"52734865211\".\n\t * @summary If you want cpf as pattern use `formatToCpfPattern` before get value.\n\t */\n\tvalue(): string {\n\t\treturn this.props;\n\t}\n\n\t/**\n\t * @description add hyphen and dot to cpf value.\n\t * @example before \"52734865211\"\n\t * @example after \"527.348.652-11\"\n\t */\n\ttoPattern(): string {\n\t\treturn formatValueToCpfPattern(this.props);\n\t}\n\n\t/**\n\t * @description add hyphen and dot to cpf value.\n\t * @example before \"52734865211\"\n\t * @example after \"527.348.652-11\"\n\t */\n\tpublic static addMask(cpf: string): string {\n\t\treturn formatValueToCpfPattern(cpf);\n\t}\n\n\t/**\n\t * @description remove hyphen and dot from cpf value.\n\t * @example before \"527.348.652-11\"\n\t * @example after \"52734865211\"\n\t */\n\tpublic static removeSpecialChars(cpf: string): string {\n\t\treturn this.util.string(cpf).removeSpecialChars();\n\t}\n\n\t/**\n\t *\n\t * @param cpf value as string only number or pattern Or instance of CPF.\n\t * @returns true if cpf match with instance value and false if not.\n\t * @example param \"52734865211\"\n\t * @example param \"527.348.652-11\"\n\t */\n\tcompare(cpf: string | CPF): boolean {\n\t\tif (typeof cpf === 'string') {\n\t\t\tconst valueA = this.util.string(cpf).removeSpecialChars();\n\t\t\tconst valueB = this.util\n\t\t\t\t.string(this.props)\n\t\t\t\t.removeSpecialChars();\n\t\t\treturn valueA === valueB;\n\t\t}\n\t\tif (cpf instanceof CPF) return cpf.isEqual(this);\n\t\treturn false;\n\t}\n\n\t/**\n\t * @description check if cpf value is a valid pattern and has a valid digit sum.\n\t * @param value cpf as string\n\t * @returns true if value is valid and false if not.\n\t * @example \"527.348.652-11\"\n\t * @example \"72725477824\"\n\t */\n\tpublic static isValidProps(value: string): boolean {\n\t\tconst isValidPattern = CPF.REGEX.test(value);\n\t\tconst isValidDigits = isValidCpfDigit(value);\n\t\treturn isValidDigits && isValidPattern;\n\t}\n\n\t/**\n\t * @description check if cpf value is a valid pattern and has a valid digit sum.\n\t * @param value cpf as string\n\t * @returns true if value is valid and false if not.\n\t * @example \"527.348.652-11\"\n\t * @example \"72725477824\"\n\t */\n\tpublic static isValid(value: string): boolean {\n\t\treturn this.isValidProps(value);\n\t}\n\n\t/**\n\t * \n\t * @param value value as string\n\t * @returns instance of CPF or throw an error\n\t */\n\tpublic static init(value: string): CPF {\n\t\tconst isValidValue = CPF.isValidProps(value);\n\t\tif (!isValidValue) throw new Error(CPF.MESSAGE);\n\t\treturn new CPF(this.util.string(value).removeSpecialChars());\n\t}\n\n\t/**\n\t * @description create a cpf value object\n\t * @param value cpf numbers as string\n\t * @returns instance of Result with cpf value\n\t * @example \"527.348.652-11\"\n\t * @example \"72725477824\"\n\t * @summary fails if provide an invalid pattern or a cpf with invalid digit sum\n\t */\n\tpublic static create(value: string): Result<CPF | null> {\n\t\tconst isValidValue = CPF.isValidProps(value);\n\n\t\tif (!isValidValue) {\n\t\t\treturn Result.fail(CPF.MESSAGE);\n\t\t}\n\n\t\treturn Result.Ok(new CPF(this.util.string(value).removeSpecialChars()));\n\t}\n}\n\nexport default CPF;\n"
  },
  {
    "path": "packages/cpf/package.json",
    "content": "{\n  \"name\": \"@type-ddd/cpf\",\n  \"description\": \"This package provides TypeScript type definitions for handling CPF (Cadastro de Pessoa Física) in Domain-Driven Design contexts\",\n  \"version\": \"0.1.0\",\n  \"main\": \"index.js\",\n  \"types\": \"index.d.ts\",\n  \"author\": \"Alessandro Dev\",\n  \"license\": \"MIT\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"keywords\": [\n    \"Complexity\",\n    \"Business Logic\",\n    \"DDD\",\n    \"Domain Driving Design\",\n    \"DDD-Utils\",\n    \"Base Value Object\",\n    \"Domain Events\",\n    \"CPF\",\n    \"Validation\",\n    \"Formatting\",\n    \"Value Object\",\n    \"Utility\",\n    \"Standards\",\n    \"Brazil\",\n    \"Cadastro de Pessoa Física\"\n  ],\n  \"scripts\": {\n    \"build\": \"tsc\"\n  },\n  \"peerDependencies\": {\n    \"rich-domain\": \"^1.25.0\"\n  },\n  \"files\": [\n    \"index.js\",\n    \"index.d.ts\",\n    \"util.d.ts\",\n    \"util.js\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/4lessandrodev/type-ddd.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/4lessandrodev/type-ddd/issues\"\n  },\n  \"homepage\": \"https://github.com/4lessandrodev/type-ddd/tree/main/packages/cpf\",\n  \"gitHead\": \"4cb9159bde8d6fc951e9d902feed2ad25da49fa4\"\n}\n"
  },
  {
    "path": "packages/cpf/tsconfig.build.json",
    "content": "{\n    \"extends\": \"../tsconfig.build.json\",\n    \"compilerOptions\": {\n        \"outDir\": \".\",\n        \"rootDir\": \".\",\n        \"paths\": {}\n    },\n    \"exclude\": [\n        \"node_modules\",\n        \"dist\",\n        \"__tests__/**/*\",\n        \"*.spec.ts\"\n    ],\n    \"references\": []\n}"
  },
  {
    "path": "packages/cpf/tsconfig.json",
    "content": "{\n\t\"extends\": \"../tsconfig.build.json\",\n\t\"compilerOptions\": {\n\t\t\"types\": [\n\t\t\t\"node\"\n\t\t]\n\t},\n\t\"files\": [],\n\t\"include\": [],\n\t\"references\": [\n\t\t{\n\t\t\t\"path\": \"./tsconfig.build.json\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "packages/cpf/util.ts",
    "content": "interface CpfDigits {\n\tpenultimateDigit: number;\n\tultimateDigit: number;\n}\n\nconst removeSpecialCharsFromCpfRegex = /[\\.]|[-]/g;\n\nexport const formatValueToCpfPattern = (cpf: string): string => {\n\tconst cpfValue = removeSpecialCharsFromCpf(cpf);\n\tlet formattedValue: string = '';\n\tlet index: number = 0;\n\n\twhile (formattedValue.length < 14 && index < 11) {\n\t\tif (index === 3 || index === 6) {\n\t\t\tformattedValue += '.';\n\t\t} else if (index === 9) {\n\t\t\tformattedValue += '-';\n\t\t}\n\t\tformattedValue += cpfValue[index];\n\t\tindex++;\n\t}\n\n\treturn formattedValue;\n};\n\nexport const removeSpecialCharsFromCpf = (cpf: string): string => {\n\treturn cpf.replace(removeSpecialCharsFromCpfRegex, '');\n};\n\nconst getCpfDigitsNumbers = (cpf: string): CpfDigits => {\n\tconst lastTwoNumbers = cpf.slice(cpf.length - 2);\n\tconst penultimateDigit = parseInt(lastTwoNumbers[0]);\n\tconst ultimateDigit = parseInt(lastTwoNumbers[1]);\n\n\treturn {\n\t\tpenultimateDigit,\n\t\tultimateDigit,\n\t};\n};\n\nconst transformCpfInArrNumber = (cpf: string): number[] => {\n\tvar arr: number[] = [];\n\n\tlet index = 0;\n\twhile (index < 9) {\n\t\tarr.push(parseInt(cpf[index]));\n\t\tindex++;\n\t}\n\n\treturn arr;\n};\n\nexport const calculateCpfDigits = (cpfNumbers: number[]): CpfDigits => {\n\tconst factor = 11;\n\tlet index = 0;\n\tlet startAuxValue = 10;\n\tlet totalForDigit = 0;\n\n\twhile (index < 9) {\n\t\ttotalForDigit = totalForDigit + cpfNumbers[index] * startAuxValue;\n\t\tstartAuxValue--;\n\t\tindex++;\n\t}\n\n\tconst calcPDigit = totalForDigit % factor;\n\tconst resultPDigit = factor - calcPDigit;\n\tconst zeroIfPGreaterThanNine = resultPDigit > 9 ? 0 : resultPDigit;\n\tconst penultimateDigit = zeroIfPGreaterThanNine;\n\n\tindex = 0;\n\tstartAuxValue = 11;\n\ttotalForDigit = 0;\n\n\tcpfNumbers.push(penultimateDigit);\n\n\twhile (index < 10) {\n\t\ttotalForDigit = totalForDigit + cpfNumbers[index] * startAuxValue;\n\t\tstartAuxValue--;\n\t\tindex++;\n\t}\n\n\tconst calcUDigit = totalForDigit % factor;\n\tconst resultUDigit = factor - calcUDigit;\n\tconst zeroIfGreaterThanNine = resultUDigit > 9 ? 0 : resultUDigit;\n\tconst ultimateDigit = zeroIfGreaterThanNine;\n\n\treturn {\n\t\tpenultimateDigit,\n\t\tultimateDigit,\n\t};\n};\n\nexport const isValidCpfDigit = (cpf: string): boolean => {\n\tconst onlyNumbers = removeSpecialCharsFromCpf(cpf);\n\n\tif (onlyNumbers.length !== 11) {\n\t\treturn false;\n\t}\n\n\tconst digits = getCpfDigitsNumbers(onlyNumbers);\n\tconst arrNumbers = transformCpfInArrNumber(onlyNumbers);\n\tconst validDigits = calculateCpfDigits(arrNumbers);\n\n\treturn (\n\t\tdigits.penultimateDigit === validDigits.penultimateDigit &&\n\t\tdigits.ultimateDigit === validDigits.ultimateDigit\n\t);\n};\n\nexport default isValidCpfDigit;\n"
  },
  {
    "path": "packages/date/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.0.4-alpha.0](https://github.com/4lessandrodev/type-ddd/compare/@type-ddd/date@0.0.2...@type-ddd/date@0.0.4-alpha.0) (2024-12-16)\n\n\n\n## 4.0.5 (2024-11-28)\n\n\n### Bug Fixes\n\n* change type create method return null [#194](https://github.com/4lessandrodev/type-ddd/issues/194) ([2cd03bf](https://github.com/4lessandrodev/type-ddd/commit/2cd03bf34387f4889a0a292ba350f2c0cfc753b7))\n\n\n\n## 4.0.3 (2024-07-26)\n\n\n\n\n\n# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n## Unreleased\n\n---\n\n## Released\n\n---\n\n### [0.0.3] - 2024-11-28\n\n### Fix\n\n- update rich-domain lib to check nullish type: now 'create' return a possibly null value in Result instance.\n\n### [0.0.2] - 2024-05-31\n\n### Docs\n\n- Doc: update documentation\n\n---\n\n### [0.0.1] - 2024-05-31\n\n### Base\n\n- Create base value object as single pack\n"
  },
  {
    "path": "packages/date/README.md",
    "content": "# `@type-ddd/date`\n\n> The @type-ddd/date library provides a class Dates for handling date and time operations in TypeScript. It offers various methods for manipulating dates, calculating differences, formatting dates, and checking validity. This library aims to simplify date and time management in Domain-Driven Design contexts.\n\n---\n\n## Installation\n\nInstall `rich-domain` and `@type-ddd/date` with your favorite package manager:\n\n```sh\n\nnpm i rich-domain @type-ddd/date\n\n# OR\n\nyarn add rich-domain @type-ddd/date\n\n```\n ## Usage\n\n ```ts\n\n\nimport { Dates } from '@type-ddd/dates';\n\n// Check if is valid value\nconst isValid = Dates.isValid('2020-02-31');\n// false\n\n// Initialize Dates instance with current date and time\nconst date = Dates.init();\n\n// OR\n\n// Create Dates instance from provided date or timestamp\nconst result = Dates.create('2024-05-24');\n\n// Add days, months, hours, minutes, weeks, or years\nconst newDate = date.addDays(5).addMonths(2);\n\n// Format date according to various patterns\nconst formattedDate = date.format('DD/MM/YYYY hh:mm:ss');\n\n// Check if date is weekday or weekend\nconst isWeekday = date.isWeekday();\nconst isWeekend = date.isWeekend();\n\n ```\n"
  },
  {
    "path": "packages/date/__tests__/date.value-object.spec.ts",
    "content": "import Dates from '../index';\n\ndescribe('Date', () => {\n\n\tdescribe('create', () => {\n\t\tit('should create an instance with success', () => {\n\t\t\tconst instance = Dates.create();\n\t\t\texpect(instance.value()).toBeInstanceOf(Dates);\n\t\t});\n\n\t\tit('should create an instance with success', () => {\n\t\t\tconst instance = Dates.create('2020-12-25');\n\t\t\texpect(instance.value()).toBeInstanceOf(Dates);\n\t\t});\n\n\t\tit('should create an instance with success', () => {\n\t\t\tconst instance = Dates.create(Date.now());\n\t\t\texpect(instance.value()).toBeInstanceOf(Dates);\n\t\t});\n\n\t\tit('should create an instance with success', () => {\n\t\t\tconst instance = Dates.create(new Date(2020, 1, 1, 1, 1, 1));\n\t\t\texpect(instance.value()?.value().toISOString()).toBe('2020-02-01T01:01:01.000Z');\n\t\t});\n\n\t\tit('should return result fail if provide an invalid value', () => {\n\t\t\tconst instance = Dates.create({} as any);\n\t\t\texpect(instance.isFail()).toBeTruthy();\n\t\t});\n\n\t\tit('should return result fail if provide an invalid date string', () => {\n\t\t\tconst instance = Dates.create('invalid');\n\t\t\texpect(instance.isFail()).toBeTruthy();\n\t\t});\n\n\t\tit('should init a valid v.o', () => {\n\t\t\tconst instance = Dates.init();\n\t\t\texpect(instance).toBeInstanceOf(Dates);\n\t\t});\n\n\t\tit('should init a date with provided value', () => {\n\t\t\tconst instance = Dates.init(new Date(2020, 1, 1, 1, 1, 1));\n\t\t\texpect(instance.value().toISOString()).toBe('2020-02-01T01:01:01.000Z');\n\t\t});\n\n\t\tit('should throw an error if provide an invalid value', () => {\n\t\t\tconst build = () => Dates.init({} as any);\n\t\t\texpect(build).toThrowError();\n\t\t});\n\n\t\tit('should throw if provide an invalid date string', () => {\n\t\t\tconst build = () => Dates.init('invalid');\n\t\t\texpect(build).toThrowError();\t\n\t\t});\n\n\t\tit('should throw if provide an invalid date string', () => {\n\t\t\tconst build = () => Dates.init('2020-12-25');\n\t\t\texpect(build).not.toThrowError();\t\n\t\t});\n\n\t\tit('should throw if provide an invalid date string', () => {\n\t\t\tconst build = () => Dates.init(Date.now());\n\t\t\texpect(build).not.toThrowError();\t\n\t\t});\n\t});\n\n\tdescribe('addDays', () => {\n\t\tit('should add 1 day with success', () => {\n\t\t\tconst date = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\texpect(date.addDays(1).value().toISOString()).toBe('2020-01-02T08:00:00.000Z');\n\t\t});\n\n\t\tit('should add 7 days with success', () => {\n\t\t\tconst date = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\texpect(date.addDays(7).value().toISOString()).toBe('2020-01-08T08:00:00.000Z');\n\t\t});\n\t});\n\n\tdescribe('addMonths', () => {\n\t\tit('should add 1 month with success', () => {\n\t\t\tconst date = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\texpect(date.addMonths(1).value().toISOString()).toBe('2020-01-31T08:00:00.000Z');\n\t\t});\n\n\t\tit('should add 7 months with success', () => {\n\t\t\tconst date = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\texpect(date.addMonths(7).value().toISOString()).toBe('2020-07-29T08:00:00.000Z');\n\t\t});\n\t});\n\n\tdescribe('addHours', () => {\n\t\tit('should add 1 hour with success', () => {\n\t\t\tconst date = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\texpect(date.addHours(1).value().toISOString()).toBe('2020-01-01T09:00:00.000Z');\n\t\t});\n\n\t\tit('should add 7 hours with success', () => {\n\t\t\tconst date = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\texpect(date.addHours(7).value().toISOString()).toBe('2020-01-01T15:00:00.000Z');\n\t\t});\n\t});\n\n\tdescribe('addMinutes', () => {\n\t\tit('should add 1 minute with success', () => {\n\t\t\tconst date = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\texpect(date.addMinutes(1).value().toISOString()).toBe('2020-01-01T08:01:00.000Z');\n\t\t});\n\n\t\tit('should add 7 minutes with success', () => {\n\t\t\tconst date = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\texpect(date.addMinutes(7).value().toISOString()).toBe('2020-01-01T08:07:00.000Z');\n\t\t});\n\t});\n\n\tdescribe('addWeeks', () => {\n\t\tit('should add 1 week with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.addWeeks(1);\n\t\t\texpect(date2.value().toISOString()).toBe('2020-01-08T08:00:00.000Z');\n\t\t\texpect(date2.differenceInDays(date1)).toBe(7);\n\t\t});\n\n\t\tit('should add 7 weeks with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.addWeeks(7);\n\t\t\texpect(date2.value().toISOString()).toBe('2020-02-19T08:00:00.000Z');\n\t\t\texpect(date2.differenceInDays(date1)).toBe(49);\n\t\t});\n\t});\n\n\tdescribe('addYears', () => {\n\t\tit('should add 1 year with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.addYears(1);\n\t\t\texpect(date2.value().toISOString()).toBe('2020-12-31T08:00:00.000Z');\n\t\t\texpect(date2.differenceInDays(date1)).toBe(365);\n\t\t});\n\n\t\tit('should add 7 years with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.addYears(7);\n\t\t\texpect(date2.value().toISOString()).toBe('2026-12-30T08:00:00.000Z');\n\t\t\texpect(date2.differenceInDays(date1)).toBe(2555);\n\t\t});\n\t});\n\n\tdescribe('subtractDays', () => {\n\t\tit('should subtract 1 day with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractDays(1);\n\t\t\texpect(date2.value().toISOString()).toBe('2019-12-31T08:00:00.000Z');\n\t\t\texpect(date1.differenceInDays(date2)).toBe(1);\n\t\t});\n\n\t\tit('should subtract 7 days with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractDays(7);\n\t\t\texpect(date2.value().toISOString()).toBe('2019-12-25T08:00:00.000Z');\n\t\t\texpect(date1.differenceInDays(date2)).toBe(7);\n\t\t});\n\t});\n\n\tdescribe('subtractMonths', () => {\n\t\tit('should subtract 1 month with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractMonths(1);\n\t\t\texpect(date2.value().toISOString()).toBe('2019-12-02T08:00:00.000Z');\n\t\t\texpect(date1.differenceInDays(date2)).toBe(30);\n\t\t});\n\n\t\tit('should subtract 7 months with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractMonths(7);\n\t\t\texpect(date2.value().toISOString()).toBe('2019-06-05T08:00:00.000Z');\n\t\t\texpect(date1.differenceInDays(date2)).toBe(210);\n\t\t});\n\t});\n\n\tdescribe('subtractHours', () => {\n\t\tit('should subtract 1 hour with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractHours(1);\n\t\t\texpect(date2.value().toISOString()).toBe('2020-01-01T07:00:00.000Z');\n\t\t\texpect(date1.differenceInHours(date2)).toBe(1);\n\t\t});\n\n\t\tit('should subtract 7 hours with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractHours(7);\n\t\t\texpect(date2.value().toISOString()).toBe('2020-01-01T01:00:00.000Z');\n\t\t\texpect(date1.differenceInHours(date2)).toBe(7);\n\t\t});\n\t});\n\n\tdescribe('subtractMinutes', () => {\n\t\tit('should subtract 1 minute with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractMinutes(1);\n\t\t\texpect(date2.value().toISOString()).toBe('2020-01-01T07:59:00.000Z');\n\t\t\texpect(date1.differenceInMinutes(date2)).toBe(1);\n\t\t});\n\n\t\tit('should subtract 7 minutes with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractMinutes(7);\n\t\t\texpect(date2.value().toISOString()).toBe('2020-01-01T07:53:00.000Z');\n\t\t\texpect(date1.differenceInMinutes(date2)).toBe(7);\n\t\t});\n\t});\n\n\tdescribe('subtractWeeks', () => {\n\t\tit('should subtract 1 week with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractWeeks(1);\n\t\t\texpect(date2.value().toISOString()).toBe('2019-12-25T08:00:00.000Z');\n\t\t\texpect(date1.differenceInDays(date2)).toBe(7);\n\t\t});\n\n\t\tit('should subtract 7 weeks with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractWeeks(7);\n\t\t\texpect(date2.value().toISOString()).toBe('2019-11-13T08:00:00.000Z');\n\t\t\texpect(date1.differenceInDays(date2)).toBe(49);\n\t\t});\n\t});\n\n\tdescribe('subtractYears', () => {\n\t\tit('should subtract 1 year with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractYears(1);\n\t\t\texpect(date2.value().toISOString()).toBe('2019-01-01T08:00:00.000Z');\n\t\t\texpect(date1.differenceInDays(date2)).toBe(365);\n\t\t});\n\n\t\tit('should subtract 7 years with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractYears(7);\n\t\t\texpect(date2.value().toISOString()).toBe('2013-01-02T08:00:00.000Z');\n\t\t\texpect(date1.differenceInDays(date2)).toBe(2555);\n\t\t});\n\t});\n\n\tdescribe('differenceInHours', () => {\n\t\tit('should subtract 1 hour with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractHours(1);\n\t\t\texpect(date2.value().toISOString()).toBe('2020-01-01T07:00:00.000Z');\n\t\t\texpect(date1.differenceInHours(date2)).toBe(1);\n\t\t});\n\n\t\tit('should subtract 7 hours with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractHours(7);\n\t\t\texpect(date2.value().toISOString()).toBe('2020-01-01T01:00:00.000Z');\n\t\t\texpect(date1.differenceInHours(date2)).toBe(7);\n\t\t});\n\n\t\tit('should return 0 if provide null', () => {\n\t\t\tconst date = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\texpect(date.differenceInHours(null as any)).toBe(0);\n\t\t})\n\t});\n\n\tdescribe('differenceInMinutes', () => {\n\t\tit('should subtract 1 minute with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractMinutes(1);\n\t\t\texpect(date2.value().toISOString()).toBe('2020-01-01T07:59:00.000Z');\n\t\t\texpect(date1.differenceInMinutes(date2)).toBe(1);\n\t\t});\n\n\t\tit('should subtract 7 minutes with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractMinutes(7);\n\t\t\texpect(date2.value().toISOString()).toBe('2020-01-01T07:53:00.000Z');\n\t\t\texpect(date1.differenceInMinutes(date2)).toBe(7);\n\t\t});\n\n\t\tit('should return 0 if provide null value', () => {\n\t\t\tconst date = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\texpect(date.differenceInMinutes(null as any)).toBe(0);\n\t\t});\n\t});\n\n\tdescribe('differenceInMonths', () => {\n\t\tit('should subtract 1 month with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractMonths(1);\n\t\t\texpect(date2.value().toISOString()).toBe('2019-12-02T08:00:00.000Z');\n\t\t\texpect(date1.differenceInMonths(date2)).toBe(0.97);\n\t\t});\n\n\t\tit('should subtract 7 months with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractMonths(7);\n\t\t\texpect(date2.value().toISOString()).toBe('2019-06-05T08:00:00.000Z');\n\t\t\texpect(date1.differenceInMonths(date2)).toBe(6.77);\n\t\t});\n\n\t\tit('should return 0 if provide null value', () => {\n\t\t\tconst date = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\texpect(date.differenceInMonths(null as any)).toBe(0);\n\t\t});\n\t});\n\n\tdescribe('differenceInYears', () => {\n\t\tit('should subtract 1 year with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractYears(1);\n\t\t\texpect(date2.value().toISOString()).toBe('2019-01-01T08:00:00.000Z');\n\t\t\texpect(date1.differenceInYears(date2)).toBe(1);\n\t\t});\n\n\t\tit('should subtract 7 years with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractYears(7);\n\t\t\texpect(date2.value().toISOString()).toBe('2013-01-02T08:00:00.000Z');\n\t\t\texpect(date1.differenceInYears(date2)).toBe(6.98);\n\t\t});\n\n\t\tit('should return 0 if provide null value', () => {\n\t\t\tconst date = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\texpect(date.differenceInYears(null as any)).toBe(0);\n\t\t});\n\t});\n\n\tdescribe('differenceInWeeks', () => {\n\t\tit('should subtract 1 week with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractWeeks(1);\n\t\t\texpect(date2.value().toISOString()).toBe('2019-12-25T08:00:00.000Z');\n\t\t\texpect(date1.differenceInWeeks(date2)).toBe(1);\n\t\t});\n\n\t\tit('should subtract 7 weeks with success', () => {\n\t\t\tconst date1 = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\tconst date2 = date1.subtractWeeks(7);\n\t\t\texpect(date2.value().toISOString()).toBe('2019-11-13T08:00:00.000Z');\n\t\t\texpect(date1.differenceInWeeks(date2)).toBe(7);\n\t\t});\n\n\t\tit('should return 0 if provide null value', () => {\n\t\t\tconst date = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\texpect(date.differenceInWeeks(null as any)).toBe(0);\n\t\t});\n\t});\n\n\tdescribe('differenceInDays', () => {\n\t\tit('should return 0 if provide null value', () => {\n\t\t\tconst date = Dates.init(new Date('2020-01-01T08:00:00'));\n\t\t\texpect(date.differenceInDays(null as any)).toBe(0);\n\t\t});\n\t});\n\n\tdescribe('validation', () => {\n\t\tit('should return true if is valid date', () => {\n\t\t\tconst isValid = Dates.isValidProps(new Date());\n\t\t\texpect(isValid).toBeTruthy();\n\t\t});\n\n\t\tit('should return false if is valid date', () => {\n\t\t\tconst isValid = Dates.isValid(new Date());\n\t\t\texpect(isValid).toBeTruthy();\n\t\t});\n\n\t\tit('should return false if is not valid date', () => {\n\t\t\tconst isValid = Dates.isValid({} as any);\n\t\t\texpect(isValid).toBeFalsy();\n\t\t});\n\n\t\tit('should return false if is not valid date', () => {\n\t\t\tconst isValid = Dates.isValidProps({} as any);\n\t\t\texpect(isValid).toBeFalsy();\n\t\t});\n\t});\n\n\tdescribe('weekend', () => {\n\t\tit('should return true if is weekend', () => {\n\t\t\tconst date = new Date('2024-05-18T00:00:00.000Z');\n\t\t\tconst isWeekend = Dates.init(date).isWeekend();\n\t\t\texpect(isWeekend).toBeTruthy();\n\t\t\texpect(Dates.isWeekend(date));\n\t\t});\n\n\t\tit('should return true if is weekend', () => {\n\t\t\tconst date = new Date('2024-05-19T00:00:00.000Z');\n\t\t\tconst isWeekend = Dates.init(date).isWeekend();\n\t\t\texpect(isWeekend).toBeTruthy();\n\t\t\texpect(Dates.isWeekend(date)).toBeTruthy();\n\t\t});\n\n\t\tit('should return false if is not weekend', () => {\n\t\t\tconst date = new Date('2024-05-20T00:00:00.000Z');\n\t\t\tconst isWeekend = Dates.init(date).isWeekend();\n\t\t\texpect(isWeekend).toBeFalsy();\n\t\t\texpect(Dates.isWeekend(date)).toBeFalsy();\n\t\t});\n\t});\n\n\tdescribe('weekDay', () => {\n\t\tit('should return false if is weekend', () => {\n\t\t\tconst date = new Date('2024-05-18T00:00:00.000Z');\n\t\t\tconst isWeekend = Dates.init(date).isWeekday();\n\t\t\texpect(isWeekend).toBeFalsy();\n\t\t\texpect(Dates.isWeekday(date)).toBeFalsy();\n\t\t});\n\n\t\tit('should return false if is weekend', () => {\n\t\t\tconst date = new Date('2024-05-19T00:00:00.000Z');\n\t\t\tconst isWeekend = Dates.init(date).isWeekday();\n\t\t\texpect(isWeekend).toBeFalsy();\n\t\t\texpect(Dates.isWeekday(date)).toBeFalsy();\n\t\t});\n\n\t\tit('should return true if is not weekend', () => {\n\t\t\tconst date = new Date('2024-05-20T00:00:00.000Z');\n\t\t\tconst isWeekend = Dates.init(date).isWeekday();\n\t\t\texpect(isWeekend).toBeTruthy();\n\t\t\texpect(Dates.isWeekday(date)).toBeTruthy();\n\t\t});\n\t});\n\n\tdescribe('isAfter', () => {\n\t\tit('should return true if date2 is after date1', () => {\n\t\t\tconst date1 = Dates.init(new Date('2024-05-18T00:00:00.000Z'));\n\t\t\tconst date2 = date1.addDays(1);\n\t\t\texpect(date2.isAfter(date1)).toBeTruthy();\n\t\t});\n\n\t\tit('should return false if date2 is not after date1', () => {\n\t\t\tconst date1 = Dates.init(new Date('2024-05-18T00:00:00.000Z'));\n\t\t\tconst date2 = date1.subtractDays(1);\n\t\t\texpect(date2.isAfter(date1)).toBeFalsy();\n\t\t});\n\n\t\tit('should return false if provide an invalid value', () => {\n\t\t\tconst date = Dates.init(new Date('2024-05-18T00:00:00.000Z'));\n\t\t\texpect(date.isAfter(null as any)).toBeFalsy();\n\t\t});\n\t});\n\n\tdescribe('isBefore', () => {\n\t\tit('should return true if date2 is before date1', () => {\n\t\t\tconst date1 = Dates.init(new Date('2024-05-18T00:00:00.000Z'));\n\t\t\tconst date2 = date1.addDays(1);\n\t\t\texpect(date2.isBefore(date1)).toBeFalsy();\n\t\t});\n\n\t\tit('should return false if date2 is not before date1', () => {\n\t\t\tconst date1 = Dates.init(new Date('2024-05-18T00:00:00.000Z'));\n\t\t\tconst date2 = date1.subtractDays(1);\n\t\t\texpect(date2.isBefore(date1)).toBeTruthy();\n\t\t});\n\n\t\tit('should return false if provide an invalid value', () => {\n\t\t\tconst date = Dates.init(new Date('2024-05-18T00:00:00.000Z'));\n\t\t\texpect(date.isBefore(null as any)).toBeFalsy();\n\t\t});\n\t});\n\n\tdescribe('isEqualDate', () => {\n\t\tit('should return true if date2 is equal date1', () => {\n\t\t\tconst date1 = Dates.init(new Date('2024-05-18T00:00:00.000Z'));\n\t\t\texpect(date1.isEqualDate(date1)).toBeTruthy();\n\t\t});\n\n\t\tit('should return false if date2 is not equal date1', () => {\n\t\t\tconst date1 = Dates.init(new Date('2024-05-18T00:00:00.000Z'));\n\t\t\tconst date2 = date1.subtractDays(1);\n\t\t\texpect(date2.isEqualDate(date1)).toBeFalsy();\n\t\t});\n\n\t\tit('should return false if provide an invalid value', () => {\n\t\t\tconst date = Dates.init(new Date('2024-05-18T00:00:00.000Z'));\n\t\t\texpect(date.isEqualDate(null as any)).toBeFalsy();\n\t\t});\n\t});\n\n\tdescribe('format', () => {\n\t\tit('should format to DD-MM-YY', () => {\n\t\t\tconst date = new Date('2024-12-25T00:00:00.000Z');\n\t\t\tconst format = Dates.init(date).format('DD-MM-YY');\n\t\t\texpect(format).toBe('25-12-24');\n\t\t});\n\n\t\tit('should format to DD-MM-YY HH:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T08:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('DD-MM-YY HH:mm:ss');\n\t\t\texpect(format).toBe('25-12-24 08:10:00');\n\t\t});\n\n\t\tit('should format to DD-MM-YY hh:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('DD-MM-YY hh:mm:ss');\n\t\t\texpect(format).toBe('25-12-24 04:10:00 PM');\n\t\t});\n\n\t\tit('should format to DD-MM-YYYY', () => {\n\t\t\tconst date = new Date('2024-12-25T00:00:00.000Z');\n\t\t\tconst format = Dates.init(date).format('DD-MM-YYYY');\n\t\t\texpect(format).toBe('25-12-2024');\n\t\t});\n\n\t\tit('should format to DD-MM-YYYY HH:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('DD-MM-YYYY HH:mm:ss');\n\t\t\texpect(format).toBe('25-12-2024 16:10:00');\n\t\t});\n\n\t\tit('should format to DD-MM-YYYY HH:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('DD-MM-YYYY hh:mm:ss');\n\t\t\texpect(format).toBe('25-12-2024 04:10:00 PM');\n\t\t});\n\n\t\tit('should format to DD/MM/YY', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('DD/MM/YY');\n\t\t\texpect(format).toBe('25/12/24');\n\t\t});\n\n\t\tit('should format to DD/MM/YY', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('DD/MM/YY');\n\t\t\texpect(format).toBe('25/12/24');\n\t\t});\n\n\t\tit('should format to DD/MM/YY HH:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('DD/MM/YY HH:mm:ss');\n\t\t\texpect(format).toBe('25/12/24 16:10:00');\n\t\t});\n\n\t\tit('should format to DD/MM/YY hh:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('DD/MM/YY hh:mm:ss');\n\t\t\texpect(format).toBe('25/12/24 04:10:00 PM');\n\t\t});\n\n\t\tit('should format to DD/MM/YYYY', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('DD/MM/YYYY');\n\t\t\texpect(format).toBe('25/12/2024');\n\t\t});\n\n\t\tit('should format to DD/MM/YYYY HH:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('DD/MM/YYYY HH:mm:ss');\n\t\t\texpect(format).toBe('25/12/2024 16:10:00');\n\t\t});\n\n\t\tit('should format to DD/MM/YYYY hh:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('DD/MM/YYYY hh:mm:ss');\n\t\t\texpect(format).toBe('25/12/2024 04:10:00 PM');\n\t\t});\n\n\t\tit('should format to MM-DD-YY', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('MM-DD-YY');\n\t\t\texpect(format).toBe('12-25-24');\n\t\t});\n\n\t\tit('should format to MM-DD-YY HH:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('MM-DD-YY HH:mm:ss');\n\t\t\texpect(format).toBe('12-25-24 16:10:00');\n\t\t});\n\n\t\tit('should format to MM-DD-YY hh:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('MM-DD-YY hh:mm:ss');\n\t\t\texpect(format).toBe('12-25-24 04:10:00 PM');\n\t\t});\n\n\t\tit('should format to MM-DD-YYYY', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('MM-DD-YYYY');\n\t\t\texpect(format).toBe('12-25-2024');\n\t\t});\n\n\t\tit('should format to MM-DD-YYYY HH:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('MM-DD-YYYY HH:mm:ss');\n\t\t\texpect(format).toBe('12-25-2024 16:10:00');\n\t\t});\n\n\t\tit('should format to MM-DD-YYYY hh:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('MM-DD-YYYY hh:mm:ss');\n\t\t\texpect(format).toBe('12-25-2024 04:10:00 PM');\n\t\t});\n\n\t\tit('should format to MM/DD/YY', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('MM/DD/YY');\n\t\t\texpect(format).toBe('12/25/24');\n\t\t});\n\n\t\tit('should format to MM/DD/YY HH:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('MM/DD/YY HH:mm:ss');\n\t\t\texpect(format).toBe('12/25/24 16:10:00');\n\t\t});\n\n\t\tit('should format to MM/DD/YY hh:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('MM/DD/YY hh:mm:ss');\n\t\t\texpect(format).toBe('12/25/24 04:10:00 PM');\n\t\t});\n\n\t\tit('should format to MM/DD/YYYY', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('MM/DD/YYYY');\n\t\t\texpect(format).toBe('12/25/2024');\n\t\t});\n\n\t\tit('should format to MM/DD/YYYY HH:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('MM/DD/YYYY HH:mm:ss');\n\t\t\texpect(format).toBe('12/25/2024 16:10:00');\n\t\t});\n\n\t\tit('should format to MM/DD/YYYY hh:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('MM/DD/YYYY hh:mm:ss');\n\t\t\texpect(format).toBe('12/25/2024 04:10:00 PM');\n\t\t});\n\n\t\tit('should format to YYYY-MM-DD', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('YYYY-MM-DD');\n\t\t\texpect(format).toBe('2024-12-25');\n\t\t});\n\n\t\tit('should format to YYYY-MM-DD HH:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('YYYY-MM-DD HH:mm:ss');\n\t\t\texpect(format).toBe('2024-12-25 16:10:00');\n\t\t});\n\n\t\tit('should format to YYYY-MM-DD hh:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('YYYY-MM-DD hh:mm:ss');\n\t\t\texpect(format).toBe('2024-12-25 04:10:00 PM');\n\t\t});\n\n\t\tit('should format to DD.MM.YYYY', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('DD.MM.YY');\n\t\t\texpect(format).toBe('25.12.24');\n\t\t});\n\n\t\tit('should format to MM.DD.YYYY', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('MM.DD.YYYY');\n\t\t\texpect(format).toBe('12.25.2024');\n\t\t});\n\n\t\tit('should format to DD.MM.YY', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('DD.MM.YY');\n\t\t\texpect(format).toBe('25.12.24');\n\t\t});\n\n\t\tit('should format to MM.DD.YY', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('MM.DD.YY');\n\t\t\texpect(format).toBe('12.25.24');\n\t\t});\n\n\t\tit('should format to YYYY.MM.DD', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('YYYY.MM.DD');\n\t\t\texpect(format).toBe('2024.12.25');\n\t\t});\n\n\t\tit('should format to DD.MM.YYYY hh:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('DD.MM.YYYY hh:mm:ss');\n\t\t\texpect(format).toBe('25.12.2024 04:10:00 PM');\n\t\t});\n\n\t\tit('should format to DD.MM.YYYY HH:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('DD.MM.YYYY HH:mm:ss');\n\t\t\texpect(format).toBe('25.12.2024 16:10:00');\n\t\t});\n\n\t\tit('should format to DD.MM.YY hh:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('DD.MM.YY hh:mm:ss');\n\t\t\texpect(format).toBe('25.12.24 04:10:00 PM');\n\t\t});\n\n\t\tit('should format to DD.MM.YY HH:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('DD.MM.YY HH:mm:ss');\n\t\t\texpect(format).toBe('25.12.24 16:10:00');\n\t\t});\n\n\t\tit('should format to MM.DD.YYYY hh:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('MM.DD.YYYY hh:mm:ss');\n\t\t\texpect(format).toBe('12.25.2024 04:10:00 PM');\n\t\t});\n\n\t\tit('should format to MM.DD.YYYY HH:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('MM.DD.YYYY HH:mm:ss');\n\t\t\texpect(format).toBe('12.25.2024 16:10:00');\n\t\t});\n\n\t\tit('should format to MM.DD.YY hh:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('MM.DD.YY hh:mm:ss');\n\t\t\texpect(format).toBe('12.25.24 04:10:00 PM');\n\t\t});\n\n\t\tit('should format to MM.DD.YY HH:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('MM.DD.YY HH:mm:ss');\n\t\t\texpect(format).toBe('12.25.24 16:10:00');\n\t\t});\n\n\t\tit('should format to YYYY.MM.DD hh:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('YYYY.MM.DD hh:mm:ss');\n\t\t\texpect(format).toBe('2024.12.25 04:10:00 PM');\n\t\t});\n\n\t\tit('should format to YYYY.MM.DD HH:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('YYYY.MM.DD HH:mm:ss');\n\t\t\texpect(format).toBe('2024.12.25 16:10:00');\n\t\t});\n\n\t\tit('should format to YYYY-MM.DD HH:mm:ss', () => {\n\t\t\tconst date = new Date('2024-12-25T16:10:00.000Z');\n\t\t\tconst format = Dates.init(date).format('YYYY_MM_DD' as any);\n\t\t\texpect(format).toBe('2024-12-25');\n\t\t});\n\t});\n\n});\n"
  },
  {
    "path": "packages/date/index.ts",
    "content": "import { Result, ValueObject } from 'rich-domain';\nimport { TimeZones } from './types';\n\nconst timeFormat12h = { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true };\nconst timeFormat24h = { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false };\n\nfunction commonDateFormat(timeFormat = null) {\n  const date = { year: 'numeric', month: '2-digit', day: '2-digit' };\n  const time = timeFormat ? { ...timeFormat } : null;\n  return { date, time };\n}\n\nconst DateFormats = {\n  // only dates\n  'DD-MM-YYYY': commonDateFormat(),\n  'MM-DD-YYYY': commonDateFormat(),\n  'DD-MM-YY': commonDateFormat(),\n  'MM-DD-YY': commonDateFormat(),\n\n  'MM/DD/YYYY': commonDateFormat(),\n  'MM/DD/YY': commonDateFormat(),\n  'DD/MM/YYYY': commonDateFormat(),\n  'DD/MM/YY': commonDateFormat(),\n\n  'YYYY-MM-DD': commonDateFormat(),\n  'YYYY/MM/DD': commonDateFormat(),\n\n  // separate with dot\n  'DD.MM.YYYY': commonDateFormat(),\n  'MM.DD.YYYY': commonDateFormat(),\n  'DD.MM.YY': commonDateFormat(),\n  'MM.DD.YY': commonDateFormat(),\n  'YYYY.MM.DD': commonDateFormat(),\n\n  'DD.MM.YYYY hh:mm:ss': commonDateFormat(timeFormat12h),\n  'DD.MM.YY hh:mm:ss': commonDateFormat(timeFormat12h),\n  'MM.DD.YYYY hh:mm:ss': commonDateFormat(timeFormat12h),\n  'MM.DD.YY hh:mm:ss': commonDateFormat(timeFormat12h),\n\n  'DD.MM.YYYY HH:mm:ss': commonDateFormat(timeFormat24h),\n  'DD.MM.YY HH:mm:ss': commonDateFormat(timeFormat24h),\n  'MM.DD.YYYY HH:mm:ss': commonDateFormat(timeFormat24h),\n  'MM.DD.YY HH:mm:ss': commonDateFormat(timeFormat24h),\n\n  'YYYY.MM.DD hh:mm:ss': commonDateFormat(timeFormat12h),\n  'YYYY.MM.DD HH:mm:ss': commonDateFormat(timeFormat24h),\n\n  // with time 12h\n  'DD/MM/YYYY hh:mm:ss': commonDateFormat(timeFormat12h),\n  'DD-MM-YYYY hh:mm:ss': commonDateFormat(timeFormat12h),\n  'DD/MM/YY hh:mm:ss': commonDateFormat(timeFormat12h),\n  'DD-MM-YY hh:mm:ss': commonDateFormat(timeFormat12h),\n  'MM/DD/YYYY hh:mm:ss': commonDateFormat(timeFormat12h),\n  'MM-DD-YYYY hh:mm:ss': commonDateFormat(timeFormat12h),\n  'MM/DD/YY hh:mm:ss': commonDateFormat(timeFormat12h),\n  'MM-DD-YY hh:mm:ss': commonDateFormat(timeFormat12h),\n\n  // with time 24h\n  'DD/MM/YYYY HH:mm:ss': commonDateFormat(timeFormat24h),\n  'DD-MM-YYYY HH:mm:ss': commonDateFormat(timeFormat24h),\n  'DD/MM/YY HH:mm:ss': commonDateFormat(timeFormat24h),\n  'DD-MM-YY HH:mm:ss': commonDateFormat(timeFormat24h),\n  'MM/DD/YYYY HH:mm:ss': commonDateFormat(timeFormat24h),\n  'MM-DD-YYYY HH:mm:ss': commonDateFormat(timeFormat24h),\n  'MM/DD/YY HH:mm:ss': commonDateFormat(timeFormat24h),\n  'MM-DD-YY HH:mm:ss': commonDateFormat(timeFormat24h),\n\n  // manual\n  'YYYY/MM/DD hh:mm:ss': commonDateFormat(timeFormat12h),\n  'YYYY-MM-DD hh:mm:ss': commonDateFormat(timeFormat12h),\n\n  'YYYY/MM/DD HH:mm:ss': commonDateFormat(timeFormat24h),\n  'YYYY-MM-DD HH:mm:ss': commonDateFormat(timeFormat24h),\n};\n\ntype DateFormat = keyof typeof DateFormats;\n\ntype FormatParams = { date: Intl.DateTimeFormatOptions; time: Intl.DateTimeFormatOptions | null };\n\nexport class Dates extends ValueObject<Date> {\n\tprotected static readonly MESSAGE: string = 'Invalid date value';\n\tprivate readonly ONE_DAY: number = 86400000;\n\tprivate readonly ONE_HOUR: number = 3600000;\n\tprivate readonly ONE_MINUTE: number = 60000;\n\tprivate readonly ONE_MONTH: number = 2678400000;\n\tprivate readonly ONE_WEEK: number = 604800000;\n\tprivate readonly ONE_YEAR: number = 31622400000;\n\n\tprivate constructor(props: Date) {\n\t\tsuper(props);\n\t}\n\n\t/**\n\t * @returns instance value as Date\n\t */\n\tvalue(): Date {\n\t\treturn this.props;\n\t}\n\n\t/**\n\t *\n\t * @param days as number to be added\n\t * @returns instance of Dates with updated value\n\t */\n\taddDays(days: number): Dates {\n\t\treturn new Dates(this.util.date(this.props).add(days).days());\n\t}\n\n\t/**\n\t *\n\t * @param months as number to be added\n\t * @returns instance of Dates with updated value\n\t */\n\taddMonths(months: number): Dates {\n\t\treturn new Dates(this.util.date(this.props).add(months).months());\n\t}\n\n\t/**\n\t *\n\t * @param hours as number to be added\n\t * @returns instance of Dates with updated value\n\t */\n\taddHours(hours: number): Dates {\n\t\treturn new Dates(this.util.date(this.props).add(hours).hours());\n\t}\n\n\t/**\n\t *\n\t * @param minutes as number to be added\n\t * @returns instance of Dates with updated value\n\t */\n\taddMinutes(minutes: number): Dates {\n\t\treturn new Dates(this.util.date(this.props).add(minutes).minutes());\n\t}\n\n\t/**\n\t *\n\t * @param weeks as number to be added\n\t * @returns instance of Dates with updated value\n\t */\n\taddWeeks(weeks: number): Dates {\n\t\treturn new Dates(this.util.date(this.props).add(weeks).weeks());\n\t}\n\n\t/**\n\t *\n\t * @param years as number to be added\n\t * @returns instance of Dates with updated value\n\t */\n\taddYears(years: number): Dates {\n\t\treturn new Dates(this.util.date(this.props).add(years).years());\n\t}\n\n\t/**\n\t *\n\t * @param days as number to be subtracted\n\t * @returns instance of Dates with updated value\n\t */\n\tsubtractDays(days: number): Dates {\n\t\treturn new Dates(this.util.date(this.props).remove(days).days());\n\t}\n\n\t/**\n\t *\n\t * @param months as number to be subtracted\n\t * @returns instance of Dates with updated value\n\t */\n\tsubtractMonths(months: number): Dates {\n\t\treturn new Dates(this.util.date(this.props).remove(months).months());\n\t}\n\n\t/**\n\t *\n\t * @param hours as number to be subtracted\n\t * @returns instance of Dates with updated value\n\t */\n\tsubtractHours(hours: number): Dates {\n\t\treturn new Dates(this.util.date(this.props).remove(hours).hours());\n\t}\n\n\t/**\n\t *\n\t * @param minutes as number to be subtracted\n\t * @returns instance of Dates with updated value\n\t */\n\tsubtractMinutes(minutes: number): Dates {\n\t\treturn new Dates(this.util.date(this.props).remove(minutes).minutes());\n\t}\n\n\t/**\n\t *\n\t * @param weeks as number to be subtracted\n\t * @returns instance of Dates with updated value\n\t */\n\tsubtractWeeks(weeks: number): Dates {\n\t\treturn new Dates(this.util.date(this.props).remove(weeks).weeks());\n\t}\n\n\t/**\n\t *\n\t * @param years as number to be subtracted\n\t * @returns instance of Dates with updated value\n\t */\n\tsubtractYears(years: number): Dates {\n\t\treturn new Dates(this.util.date(this.props).remove(years).years());\n\t}\n\n\t/**\n\t *\n\t * @param date as Date to be compared or instance of Dates\n\t * @returns result as number of days\n\t * @summary returns positive result if instance value is greater than provided value\n\t */\n\tdifferenceInDays(date: Date | Dates): number {\n\t\tif (date instanceof Date) {\n\t\t\tconst currentDays = this.props.getTime() / this.ONE_DAY;\n\t\t\tconst dateTime = date.getTime() / this.ONE_DAY;\n\t\t\tconst calc = (currentDays * 100 - dateTime * 100) / 100;\n\t\t\treturn parseFloat(calc.toFixed(2));\n\t\t}\n\t\tif (date instanceof Dates) {\n\t\t\treturn this.differenceInDays(date.value());\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t *\n\t * @param date to be compared or instance of Dates\n\t * @returns result as number of hours\n\t * @summary returns positive result if instance value is greater than provided value\n\t */\n\tdifferenceInHours(date: Date | Dates): number {\n\t\tif (date instanceof Date) {\n\t\t\tconst currentDays = this.props.getTime() / this.ONE_HOUR;\n\t\t\tconst dateTime = date.getTime() / this.ONE_HOUR;\n\t\t\tconst calc = (currentDays * 100 - dateTime * 100) / 100;\n\t\t\treturn parseFloat(calc.toFixed(2));\n\t\t}\n\t\tif (date instanceof Dates) {\n\t\t\treturn this.differenceInHours(date.value());\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t *\n\t * @param date to be compared or instance of Dates\n\t * @returns result as number of minutes\n\t * @summary returns positive result if instance value is greater than provided value\n\t */\n\tdifferenceInMinutes(date: Date | Dates): number {\n\t\tif (date instanceof Date) {\n\t\t\tconst currentDays = this.props.getTime() / this.ONE_MINUTE;\n\t\t\tconst dateTime = date.getTime() / this.ONE_MINUTE;\n\t\t\tconst calc = (currentDays * 100 - dateTime * 100) / 100;\n\t\t\treturn parseFloat(calc.toFixed(2));\n\t\t}\n\t\tif (date instanceof Dates) {\n\t\t\treturn this.differenceInMinutes(date.value());\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t *\n\t * @param date to be compared or Dates\n\t * @returns result as number of months\n\t * @summary returns positive result if instance value is greater than provided value\n\t */\n\tdifferenceInMonths(date: Date | Dates): number {\n\t\tif (date instanceof Date) {\n\t\t\tconst currentDays = this.props.getTime() / this.ONE_MONTH;\n\t\t\tconst dateTime = date.getTime() / this.ONE_MONTH;\n\t\t\tconst calc = (currentDays * 100 - dateTime * 100) / 100;\n\t\t\treturn parseFloat(calc.toFixed(2));\n\t\t}\n\t\tif (date instanceof Dates) {\n\t\t\treturn this.differenceInMonths(date.value());\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t *\n\t * @param date to be compared or Dates\n\t * @returns result as number of years\n\t * @summary returns positive result if instance value is greater than provided value\n\t */\n\tdifferenceInYears(date: Date | Dates): number {\n\t\tif (date instanceof Date) {\n\t\t\tconst currentDays = this.props.getTime() / this.ONE_YEAR;\n\t\t\tconst dateTime = date.getTime() / this.ONE_YEAR;\n\t\t\tconst calc = (currentDays * 100 - dateTime * 100) / 100;\n\t\t\treturn parseFloat(calc.toFixed(2));\n\t\t}\n\t\tif (date instanceof Dates) {\n\t\t\treturn this.differenceInYears(date.value());\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t *\n\t * @param date to be compared or instance of Dates\n\t * @returns result as number of weeks\n\t * @summary returns positive result if instance value is greater than provided value\n\t */\n\tdifferenceInWeeks(date: Date | Dates): number {\n\t\tif (date instanceof Date) {\n\t\t\tconst currentDays = this.props.getTime() / this.ONE_WEEK;\n\t\t\tconst dateTime = date.getTime() / this.ONE_WEEK;\n\t\t\tconst calc = (currentDays * 100 - dateTime * 100) / 100;\n\t\t\treturn parseFloat(calc.toFixed(2));\n\t\t}\n\t\tif (date instanceof Dates) {\n\t\t\treturn this.differenceInWeeks(date.value());\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t *\n\t * @param format pattern to be applied\n\t * @param timeZone as TimeZone name as string to be considered\n\t * @returns formatted date as string\n\t */\n\tformat(format: DateFormat, timeZone?: TimeZones): string {\n\t\tconst firstChars = format.slice(0, 2);\n\t\tconst dateLocale = firstChars === 'DD' ? 'pt-BR' : 'en-US';\n\t\tconst formatDate = (date: Date, formats: FormatParams) => {\n\n\t\t\tconst locale = (format.slice(0, 2) === 'YY') ? 'sv-SE' : undefined;\n\t\t\tconst year = (format.includes('YYYY')) ? 'numeric' : '2-digit';\n\n\t\t\tconst dateFn = new Intl.DateTimeFormat(locale || dateLocale, {\n\t\t\t\tmonth: '2-digit',\n\t\t\t\tday: '2-digit',\n\t\t\t\t...(formats?.date ?? {}),\n\t\t\t\tyear,\n\t\t\t\ttimeZone\n\t\t\t}).format(date);\n\n\t\t\tif (formats?.time) {\n\t\t\t\tconst timeFn = new Intl.DateTimeFormat(dateLocale, {\n\t\t\t\t\t...formats.time,\n\t\t\t\t\ttimeZone\n\t\t\t\t}).format(date);\n\t\t\t\treturn { dateFn, timeFn }\n\t\t\t}\n\n\t\t\treturn { dateFn, timeFn: '' };\n\t\t};\n\t\tconst result = formatDate(this.props, DateFormats[format] as FormatParams);\n\n\t\tconst applySeparator = (date: string): string => {\n\t\t\tif (format.includes('/')) return date.replace(/-/g, '/');\n\t\t\tif (format.includes('-')) return date.replace(/\\//g, '-');\n\t\t\tif (format.includes('.')) return date.replace(/\\/|\\-/g, '.');\n\t\t\treturn date;\n\t\t}\n\t\treturn applySeparator(`${result.dateFn} ${result.timeFn}`.trim());\n\t}\n\n\t/**\n\t * @param value as Date or date string\n\t * @returns true if provided value is instance of date, and false if not.\n\t */\n\tpublic static isValidProps(value: Date | string | number): boolean {\n\t\tif(typeof value === 'number') {\n\t\t\tconst date = new Date(value);\n\t\t\treturn date instanceof Date;\n\t\t}\n\t\tif (typeof value === 'string') {\n\t\t\tconst date = new Date(value);\n\t\t\treturn (\n\t\t\t\t!isNaN(date as unknown as number) &&\n\t\t\t\tdate.toISOString().slice(0, 10) === value &&\n\t\t\t\t!isNaN(date.getFullYear())\n\t\t\t);\n\t\t}\n\t\treturn this.validator.isDate(value);\n\t}\n\n\t/**\n\t * @param value as Date or date string or number as timestamp\n\t * @returns true if provided value is instance of date, and false if not.\n\t */\n\tpublic static isValid(value: Date | string): boolean {\n\t\treturn this.isValidProps(value);\n\t}\n\n\t/**\n\t *\n\t * @returns true if date day is week day [Monday-Friday]\n\t */\n\tisWeekday(): boolean {\n\t\treturn !this.isWeekend()\n\t}\n\n\t/**\n\t *\n\t * @returns true if date value day is weekend day [Saturday-Sunday]\n\t */\n\tisWeekend(): boolean {\n\t\treturn this.validator.date(this.props).isWeekend();\n\t}\n\n\t/**\n\t *\n\t * @param date value as date.\n\t * @returns true if date day is week day [Monday-Friday]\n\t */\n\tpublic static isWeekday(date: Date): boolean {\n\t\treturn !this.isWeekend(date);\n\t}\n\n\t/**\n\t *\n\t * @param date value as date.\n\t * @returns true if date day is weekend day [Sat-Sunday]\n\t */\n\tpublic static isWeekend(date: Date): boolean {\n\t\treturn this.validator.date(date).isWeekend();\n\t}\n\n\t/**\n\t *\n\t * @param date as Date or instance of Dates\n\t * @returns true or false. True if instance date is greater than provided value\n\t * @example\n\t *\n\t * const date = new Date(\"1989-05-31 11:42:00\");\n\t *\n\t * const vo = Dates.create(date).value();\n\t *\n\t * const isAfter = vo.isAfter(new Date());\n\t *\n\t * console.log(isAfter);\n\t *\n\t * > false\n\t *\n\t * ...\n\t */\n\tisAfter(date: Date | Dates): boolean {\n\t\tif (date instanceof Date) {\n\t\t\treturn this.validator.date(this.props).isAfterThan(date);\n\t\t}\n\t\tif (date instanceof Dates) {\n\t\t\treturn this.isAfter(date.value());\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t *\n\t * @param date as Date or instance of Dates\n\t * @returns true or false. True if instance date is less than provided value\n\t * @example\n\t *\n\t * const date = new Date(\"1989-05-31 11:42:00\");\n\t *\n\t * const vo = Dates.create(date).value();\n\t *\n\t * const isBefore = vo.isBefore(new Date());\n\t *\n\t * console.log(isBefore);\n\t *\n\t * > true\n\t *\n\t * ...\n\t */\n\tisBefore(date: Date | Dates): boolean {\n\t\tif (date instanceof Date) {\n\t\t\treturn this.validator.date(this.props).isBeforeThan(date);\n\t\t}\n\t\tif (date instanceof Dates) {\n\t\t\treturn this.isBefore(date.value());\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t *\n\t * @param date as Date or instance of Dates\n\t * @returns true or false. True if instance date is equal to provided value\n\t */\n\tisEqualDate(date: Date | Dates): boolean {\n\t\tif (date instanceof Date) {\n\t\t\tconst time = date.getTime();\n\t\t\tconst instanceTime = this.props.getTime();\n\t\t\treturn this.validator.number(time).isEqualTo(instanceTime);\n\t\t}\n\t\tif (date instanceof Dates) {\n\t\t\treturn this.isEqualDate(date.value());\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * \n\t * @param value value as Date or date string or number as timestamp\n\t * @returns instance of Dates or throw an error\n\t */\n\tpublic static init(value?: Date | string | number): Dates {\n\t\tif (!value) return new Dates(new Date());\n\t\tconst isValidValue = Dates.isValidProps(value);\n\t\tif (!isValidValue) throw new Error(Dates.MESSAGE);\n\t\tif (value instanceof Date) return new Dates(value);\n\t\treturn new Dates(new Date(value));\n\t}\n\n\t/**\n\t * \n\t * @param value value as Date or date string or number as timestamp\n\t * @returns Result of Dates\n\t */\n\tpublic static create(date?: Date | string | number): Result<Dates | null> {\n\t\tconst value = date ?? new Date();\n\t\tconst isValid = Dates.isValidProps(value);\n\t\tif (!isValid) return Result.fail(Dates.MESSAGE);\n\t\tif (value instanceof Date) return Result.Ok(new Dates(value));\n\t\treturn Result.Ok(new Dates(new Date(value)));\n\t}\n}\n\nexport default Dates;\n"
  },
  {
    "path": "packages/date/package.json",
    "content": "{\n  \"name\": \"@type-ddd/date\",\n  \"description\": \"Library that provides TypeScript type definitions for handling Dates in Domain-Driven Design contexts. It facilitates the validation and manipulation of Dates.\",\n  \"version\": \"0.1.0\",\n  \"main\": \"index.js\",\n  \"types\": \"index.d.ts\",\n  \"author\": \"Alessandro Dev\",\n  \"license\": \"MIT\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"keywords\": [\n    \"Complexity\",\n    \"Business Logic\",\n    \"DDD\",\n    \"Domain Driving Design\",\n    \"DDD-Utils\",\n    \"Base Value Object\",\n    \"Clean Architecture\",\n    \"Date\",\n    \"Validation\",\n    \"Formatting\",\n    \"Value Object\",\n    \"Utility\",\n    \"Security\",\n    \"Standards\"\n  ],\n  \"scripts\": {\n    \"build\": \"tsc\"\n  },\n  \"peerDependencies\": {\n    \"rich-domain\": \"^1.25.0\"\n  },\n  \"files\": [\n    \"index.js\",\n    \"index.d.ts\",\n    \"util.js\",\n    \"util.d.ts\",\n    \"types.js\",\n    \"types.d.ts\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/4lessandrodev/type-ddd.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/4lessandrodev/type-ddd/issues\"\n  },\n  \"homepage\": \"https://github.com/4lessandrodev/type-ddd/tree/main/packages/date\",\n  \"gitHead\": \"4cb9159bde8d6fc951e9d902feed2ad25da49fa4\"\n}\n"
  },
  {
    "path": "packages/date/tsconfig.build.json",
    "content": "{\n    \"extends\": \"../tsconfig.build.json\",\n    \"compilerOptions\": {\n        \"outDir\": \".\",\n        \"rootDir\": \".\",\n        \"paths\": {}\n    },\n    \"exclude\": [\n        \"node_modules\",\n        \"dist\",\n        \"__tests__/**/*\",\n        \"*.spec.ts\"\n    ],\n    \"references\": []\n}"
  },
  {
    "path": "packages/date/tsconfig.json",
    "content": "{\n\t\"extends\": \"../tsconfig.build.json\",\n\t\"compilerOptions\": {\n\t\t\"types\": [\n\t\t\t\"node\"\n\t\t]\n\t},\n\t\"files\": [],\n\t\"include\": [],\n\t\"references\": [\n\t\t{\n\t\t\t\"path\": \"./tsconfig.build.json\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "packages/date/types.ts",
    "content": "export type TimeZones = \n\"Africa/Abidjan\" |\n\"Africa/Accra\" |\n\"Africa/Addis_Ababa\" |\n\"Africa/Algiers\" |\n\"Africa/Asmara\" |\n\"Africa/Asmera\" |\n\"Africa/Bamako\" |\n\"Africa/Bangui\" |\n\"Africa/Banjul\" |\n\"Africa/Bissau\" |\n\"Africa/Blantyre\" |\n\"Africa/Brazzaville\" |\n\"Africa/Bujumbura\" |\n\"Africa/Cairo\" |\n\"Africa/Casablanca\" |\n\"Africa/Ceuta\" |\n\"Africa/Conakry\" |\n\"Africa/Dakar\" |\n\"Africa/Dar_es_Salaam\" |\n\"Africa/Djibouti\" |\n\"Africa/Douala\" |\n\"Africa/El_Aaiun\" |\n\"Africa/Freetown\" |\n\"Africa/Gaborone\" |\n\"Africa/Harare\" |\n\"Africa/Johannesburg\" |\n\"Africa/Juba\" |\n\"Africa/Kampala\" |\n\"Africa/Khartoum\" |\n\"Africa/Kigali\" |\n\"Africa/Kinshasa\" |\n\"Africa/Lagos\" |\n\"Africa/Libreville\" |\n\"Africa/Lome\" |\n\"Africa/Luanda\" |\n\"Africa/Lubumbashi\" |\n\"Africa/Lusaka\" |\n\"Africa/Malabo\" |\n\"Africa/Maputo\" |\n\"Africa/Maseru\" |\n\"Africa/Mbabane\" |\n\"Africa/Mogadishu\" |\n\"Africa/Monrovia\" |\n\"Africa/Nairobi\" |\n\"Africa/Ndjamena\" |\n\"Africa/Niamey\" |\n\"Africa/Nouakchott\" |\n\"Africa/Ouagadougou\" |\n\"Africa/Porto-Novo\" |\n\"Africa/Sao_Tome\" |\n\"Africa/Timbuktu\" |\n\"Africa/Tripoli\" |\n\"Africa/Tunis\" |\n\"Africa/Windhoek\" |\n\"America/Adak\" |\n\"America/Anchorage\" |\n\"America/Anguilla\" |\n\"America/Antigua\" |\n\"America/Araguaina\" |\n\"America/Argentina/Buenos_Aires\" |\n\"America/Argentina/Catamarca\" |\n\"America/Argentina/ComodRivadavia\" |\n\"America/Argentina/Cordoba\" |\n\"America/Argentina/Jujuy\" |\n\"America/Argentina/La_Rioja\" |\n\"America/Argentina/Mendoza\" |\n\"America/Argentina/Rio_Gallegos\" |\n\"America/Argentina/Salta\" |\n\"America/Argentina/San_Juan\" |\n\"America/Argentina/San_Luis\" |\n\"America/Argentina/Tucuman\" |\n\"America/Argentina/Ushuaia\" |\n\"America/Aruba\" |\n\"America/Asuncion\" |\n\"America/Atikokan\" |\n\"America/Atka\" |\n\"America/Bahia\" |\n\"America/Bahia_Banderas\" |\n\"America/Barbados\" |\n\"America/Belem\" |\n\"America/Belize\" |\n\"America/Blanc-Sablon\" |\n\"America/Boa_Vista\" |\n\"America/Bogota\" |\n\"America/Boise\" |\n\"America/Buenos_Aires\" |\n\"America/Cambridge_Bay\" |\n\"America/Campo_Grande\" |\n\"America/Cancun\" |\n\"America/Caracas\" |\n\"America/Catamarca\" |\n\"America/Cayenne\" |\n\"America/Cayman\" |\n\"America/Chicago\" |\n\"America/Chihuahua\" |\n\"America/Coral_Harbour\" |\n\"America/Cordoba\" |\n\"America/Costa_Rica\" |\n\"America/Creston\" |\n\"America/Cuiaba\" |\n\"America/Curacao\" |\n\"America/Danmarkshavn\" |\n\"America/Dawson\" |\n\"America/Dawson_Creek\" |\n\"America/Denver\" |\n\"America/Detroit\" |\n\"America/Dominica\" |\n\"America/Edmonton\" |\n\"America/Eirunepe\" |\n\"America/El_Salvador\" |\n\"America/Ensenada\" |\n\"America/Fort_Nelson\" |\n\"America/Fort_Wayne\" |\n\"America/Fortaleza\" |\n\"America/Glace_Bay\" |\n\"America/Godthab\" |\n\"America/Goose_Bay\" |\n\"America/Grand_Turk\" |\n\"America/Grenada\" |\n\"America/Guadeloupe\" |\n\"America/Guatemala\" |\n\"America/Guayaquil\" |\n\"America/Guyana\" |\n\"America/Halifax\" |\n\"America/Havana\" |\n\"America/Hermosillo\" |\n\"America/Indiana/Indianapolis\" |\n\"America/Indiana/Knox\" |\n\"America/Indiana/Marengo\" |\n\"America/Indiana/Petersburg\" |\n\"America/Indiana/Tell_City\" |\n\"America/Indiana/Vevay\" |\n\"America/Indiana/Vincennes\" |\n\"America/Indiana/Winamac\" |\n\"America/Indianapolis\" |\n\"America/Inuvik\" |\n\"America/Iqaluit\" |\n\"America/Jamaica\" |\n\"America/Jujuy\" |\n\"America/Juneau\" |\n\"America/Kentucky/Louisville\" |\n\"America/Kentucky/Monticello\" |\n\"America/Knox_IN\" |\n\"America/Kralendijk\" |\n\"America/La_Paz\" |\n\"America/Lima\" |\n\"America/Los_Angeles\" |\n\"America/Louisville\" |\n\"America/Lower_Princes\" |\n\"America/Maceio\" |\n\"America/Managua\" |\n\"America/Manaus\" |\n\"America/Marigot\" |\n\"America/Martinique\" |\n\"America/Matamoros\" |\n\"America/Mazatlan\" |\n\"America/Mendoza\" |\n\"America/Menominee\" |\n\"America/Merida\" |\n\"America/Metlakatla\" |\n\"America/Mexico_City\" |\n\"America/Miquelon\" |\n\"America/Moncton\" |\n\"America/Monterrey\" |\n\"America/Montevideo\" |\n\"America/Montreal\" |\n\"America/Montserrat\" |\n\"America/Nassau\" |\n\"America/New_York\" |\n\"America/Nipigon\" |\n\"America/Nome\" |\n\"America/Noronha\" |\n\"America/North_Dakota/Beulah\" |\n\"America/North_Dakota/Center\" |\n\"America/North_Dakota/New_Salem\" |\n\"America/Ojinaga\" |\n\"America/Panama\" |\n\"America/Pangnirtung\" |\n\"America/Paramaribo\" |\n\"America/Phoenix\" |\n\"America/Port-au-Prince\" |\n\"America/Port_of_Spain\" |\n\"America/Porto_Acre\" |\n\"America/Porto_Velho\" |\n\"America/Puerto_Rico\" |\n\"America/Punta_Arenas\" |\n\"America/Rainy_River\" |\n\"America/Rankin_Inlet\" |\n\"America/Recife\" |\n\"America/Regina\" |\n\"America/Resolute\" |\n\"America/Rio_Branco\" |\n\"America/Rosario\" |\n\"America/Santa_Isabel\" |\n\"America/Santarem\" |\n\"America/Santiago\" |\n\"America/Santo_Domingo\" |\n\"America/Sao_Paulo\" |\n\"America/Scoresbysund\" |\n\"America/Shiprock\" |\n\"America/Sitka\" |\n\"America/St_Barthelemy\" |\n\"America/St_Johns\" |\n\"America/St_Kitts\" |\n\"America/St_Lucia\" |\n\"America/St_Thomas\" |\n\"America/St_Vincent\" |\n\"America/Swift_Current\" |\n\"America/Tegucigalpa\" |\n\"America/Thule\" |\n\"America/Thunder_Bay\" |\n\"America/Tijuana\" |\n\"America/Toronto\" |\n\"America/Tortola\" |\n\"America/Vancouver\" |\n\"America/Virgin\" |\n\"America/Whitehorse\" |\n\"America/Winnipeg\" |\n\"America/Yakutat\" |\n\"America/Yellowknife\" |\n\"Antarctica/Casey\" |\n\"Antarctica/Davis\" |\n\"Antarctica/DumontDUrville\" |\n\"Antarctica/Macquarie\" |\n\"Antarctica/Mawson\" |\n\"Antarctica/McMurdo\" |\n\"Antarctica/Palmer\" |\n\"Antarctica/Rothera\" |\n\"Antarctica/South_Pole\" |\n\"Antarctica/Syowa\" |\n\"Antarctica/Troll\" |\n\"Antarctica/Vostok\" |\n\"Arctic/Longyearbyen\" |\n\"Asia/Aden\" |\n\"Asia/Almaty\" |\n\"Asia/Amman\" |\n\"Asia/Anadyr\" |\n\"Asia/Aqtau\" |\n\"Asia/Aqtobe\" |\n\"Asia/Ashgabat\" |\n\"Asia/Ashkhabad\" |\n\"Asia/Atyrau\" |\n\"Asia/Baghdad\" |\n\"Asia/Bahrain\" |\n\"Asia/Baku\" |\n\"Asia/Bangkok\" |\n\"Asia/Barnaul\" |\n\"Asia/Beirut\" |\n\"Asia/Bishkek\" |\n\"Asia/Brunei\" |\n\"Asia/Calcutta\" |\n\"Asia/Chita\" |\n\"Asia/Choibalsan\" |\n\"Asia/Chongqing\" |\n\"Asia/Chungking\" |\n\"Asia/Colombo\" |\n\"Asia/Dacca\" |\n\"Asia/Damascus\" |\n\"Asia/Dhaka\" |\n\"Asia/Dili\" |\n\"Asia/Dubai\" |\n\"Asia/Dushanbe\" |\n\"Asia/Famagusta\" |\n\"Asia/Gaza\" |\n\"Asia/Harbin\" |\n\"Asia/Hebron\" |\n\"Asia/Ho_Chi_Minh\" |\n\"Asia/Hong_Kong\" |\n\"Asia/Hovd\" |\n\"Asia/Irkutsk\" |\n\"Asia/Istanbul\" |\n\"Asia/Jakarta\" |\n\"Asia/Jayapura\" |\n\"Asia/Jerusalem\" |\n\"Asia/Kabul\" |\n\"Asia/Kamchatka\" |\n\"Asia/Karachi\" |\n\"Asia/Kashgar\" |\n\"Asia/Kathmandu\" |\n\"Asia/Katmandu\" |\n\"Asia/Khandyga\" |\n\"Asia/Kolkata\" |\n\"Asia/Krasnoyarsk\" |\n\"Asia/Kuala_Lumpur\" |\n\"Asia/Kuching\" |\n\"Asia/Kuwait\" |\n\"Asia/Macao\" |\n\"Asia/Macau\" |\n\"Asia/Magadan\" |\n\"Asia/Makassar\" |\n\"Asia/Manila\" |\n\"Asia/Muscat\" |\n\"Asia/Nicosia\" |\n\"Asia/Novokuznetsk\" |\n\"Asia/Novosibirsk\" |\n\"Asia/Omsk\" |\n\"Asia/Oral\" |\n\"Asia/Phnom_Penh\" |\n\"Asia/Pontianak\" |\n\"Asia/Pyongyang\" |\n\"Asia/Qatar\" |\n\"Asia/Qostanay\" |\n\"Asia/Qyzylorda\" |\n\"Asia/Rangoon\" |\n\"Asia/Riyadh\" |\n\"Asia/Saigon\" |\n\"Asia/Sakhalin\" |\n\"Asia/Samarkand\" |\n\"Asia/Seoul\" |\n\"Asia/Shanghai\" |\n\"Asia/Singapore\" |\n\"Asia/Srednekolymsk\" |\n\"Asia/Taipei\" |\n\"Asia/Tashkent\" |\n\"Asia/Tbilisi\" |\n\"Asia/Tehran\" |\n\"Asia/Tel_Aviv\" |\n\"Asia/Thimbu\" |\n\"Asia/Thimphu\" |\n\"Asia/Tokyo\" |\n\"Asia/Tomsk\" |\n\"Asia/Ujung_Pandang\" |\n\"Asia/Ulaanbaatar\" |\n\"Asia/Ulan_Bator\" |\n\"Asia/Urumqi\" |\n\"Asia/Ust-Nera\" |\n\"Asia/Vientiane\" |\n\"Asia/Vladivostok\" |\n\"Asia/Yakutsk\" |\n\"Asia/Yangon\" |\n\"Asia/Yekaterinburg\" |\n\"Asia/Yerevan\" |\n\"Atlantic/Azores\" |\n\"Atlantic/Bermuda\" |\n\"Atlantic/Canary\" |\n\"Atlantic/Cape_Verde\" |\n\"Atlantic/Faeroe\" |\n\"Atlantic/Faroe\" |\n\"Atlantic/Jan_Mayen\" |\n\"Atlantic/Madeira\" |\n\"Atlantic/Reykjavik\" |\n\"Atlantic/South_Georgia\" |\n\"Atlantic/St_Helena\" |\n\"Atlantic/Stanley\" |\n\"Australia/ACT\" |\n\"Australia/Adelaide\" |\n\"Australia/Brisbane\" |\n\"Australia/Broken_Hill\" |\n\"Australia/Canberra\" |\n\"Australia/Currie\" |\n\"Australia/Darwin\" |\n\"Australia/Eucla\" |\n\"Australia/Hobart\" |\n\"Australia/LHI\" |\n\"Australia/Lindeman\" |\n\"Australia/Lord_Howe\" |\n\"Australia/Melbourne\" |\n\"Australia/NSW\" |\n\"Australia/North\" |\n\"Australia/Perth\" |\n\"Australia/Queensland\" |\n\"Australia/South\" |\n\"Australia/Sydney\" |\n\"Australia/Tasmania\" |\n\"Australia/Victoria\" |\n\"Australia/West\" |\n\"Australia/Yancowinna\" |\n\"Brazil/Acre\" |\n\"Brazil/DeNoronha\" |\n\"Brazil/East\" |\n\"Brazil/West\" |\n\"CET\" |\n\"CST6CDT\" |\n\"Canada/Atlantic\" |\n\"Canada/Central\" |\n\"Canada/Eastern\" |\n\"Canada/Mountain\" |\n\"Canada/Newfoundland\" |\n\"Canada/Pacific\" |\n\"Canada/Saskatchewan\" |\n\"Canada/Yukon\" |\n\"Chile/Continental\" |\n\"Chile/EasterIsland\" |\n\"Cuba\" |\n\"EET\" |\n\"EST\" |\n\"EST5EDT\" |\n\"Egypt\" |\n\"Eire\" |\n\"Etc/GMT\" |\n\"Etc/GMT+0\" |\n\"Etc/GMT+1\" |\n\"Etc/GMT+10\" |\n\"Etc/GMT+11\" |\n\"Etc/GMT+12\" |\n\"Etc/GMT+2\" |\n\"Etc/GMT+3\" |\n\"Etc/GMT+4\" |\n\"Etc/GMT+5\" |\n\"Etc/GMT+6\" |\n\"Etc/GMT+7\" |\n\"Etc/GMT+8\" |\n\"Etc/GMT+9\" |\n\"Etc/GMT-0\" |\n\"Etc/GMT-1\" |\n\"Etc/GMT-10\" |\n\"Etc/GMT-11\" |\n\"Etc/GMT-12\" |\n\"Etc/GMT-13\" |\n\"Etc/GMT-14\" |\n\"Etc/GMT-2\" |\n\"Etc/GMT-3\" |\n\"Etc/GMT-4\" |\n\"Etc/GMT-5\" |\n\"Etc/GMT-6\" |\n\"Etc/GMT-7\" |\n\"Etc/GMT-8\" |\n\"Etc/GMT-9\" |\n\"Etc/GMT0\" |\n\"Etc/Greenwich\" |\n\"Etc/UCT\" |\n\"Etc/UTC\" |\n\"Etc/Universal\" |\n\"Etc/Zulu\" |\n\"Europe/Amsterdam\" |\n\"Europe/Andorra\" |\n\"Europe/Astrakhan\" |\n\"Europe/Athens\" |\n\"Europe/Belfast\" |\n\"Europe/Belgrade\" |\n\"Europe/Berlin\" |\n\"Europe/Bratislava\" |\n\"Europe/Brussels\" |\n\"Europe/Bucharest\" |\n\"Europe/Budapest\" |\n\"Europe/Busingen\" |\n\"Europe/Chisinau\" |\n\"Europe/Copenhagen\" |\n\"Europe/Dublin\" |\n\"Europe/Gibraltar\" |\n\"Europe/Guernsey\" |\n\"Europe/Helsinki\" |\n\"Europe/Isle_of_Man\" |\n\"Europe/Istanbul\" |\n\"Europe/Jersey\" |\n\"Europe/Kaliningrad\" |\n\"Europe/Kiev\" |\n\"Europe/Kirov\" |\n\"Europe/Lisbon\" |\n\"Europe/Ljubljana\" |\n\"Europe/London\" |\n\"Europe/Luxembourg\" |\n\"Europe/Madrid\" |\n\"Europe/Malta\" |\n\"Europe/Mariehamn\" |\n\"Europe/Minsk\" |\n\"Europe/Monaco\" |\n\"Europe/Moscow\" |\n\"Europe/Nicosia\" |\n\"Europe/Oslo\" |\n\"Europe/Paris\" |\n\"Europe/Podgorica\" |\n\"Europe/Prague\" |\n\"Europe/Riga\" |\n\"Europe/Rome\" |\n\"Europe/Samara\" |\n\"Europe/San_Marino\" |\n\"Europe/Sarajevo\" |\n\"Europe/Saratov\" |\n\"Europe/Simferopol\" |\n\"Europe/Skopje\" |\n\"Europe/Sofia\" |\n\"Europe/Stockholm\" |\n\"Europe/Tallinn\" |\n\"Europe/Tirane\" |\n\"Europe/Tiraspol\" |\n\"Europe/Ulyanovsk\" |\n\"Europe/Uzhgorod\" |\n\"Europe/Vaduz\" |\n\"Europe/Vatican\" |\n\"Europe/Vienna\" |\n\"Europe/Vilnius\" |\n\"Europe/Volgograd\" |\n\"Europe/Warsaw\" |\n\"Europe/Zagreb\" |\n\"Europe/Zaporozhye\" |\n\"Europe/Zurich\" |\n\"GB\" |\n\"GB-Eire\" |\n\"GMT\" |\n\"GMT+0\" |\n\"GMT-0\" |\n\"GMT0\" |\n\"Greenwich\" |\n\"HST\" |\n\"Hongkong\" |\n\"Iceland\" |\n\"Indian/Antananarivo\" |\n\"Indian/Chagos\" |\n\"Indian/Christmas\" |\n\"Indian/Cocos\" |\n\"Indian/Comoro\" |\n\"Indian/Kerguelen\" |\n\"Indian/Mahe\" |\n\"Indian/Maldives\" |\n\"Indian/Mauritius\" |\n\"Indian/Mayotte\" |\n\"Indian/Reunion\" |\n\"Iran\" |\n\"Israel\" |\n\"Jamaica\" |\n\"Japan\" |\n\"Kwajalein\" |\n\"Libya\" |\n\"MET\" |\n\"MST\" |\n\"MST7MDT\" |\n\"Mexico/BajaNorte\" |\n\"Mexico/BajaSur\" |\n\"Mexico/General\" |\n\"NZ\" |\n\"NZ-CHAT\" |\n\"Navajo\" |\n\"PRC\" |\n\"PST8PDT\" |\n\"Pacific/Apia\" |\n\"Pacific/Auckland\" |\n\"Pacific/Bougainville\" |\n\"Pacific/Chatham\" |\n\"Pacific/Chuuk\" |\n\"Pacific/Easter\" |\n\"Pacific/Efate\" |\n\"Pacific/Enderbury\" |\n\"Pacific/Fakaofo\" |\n\"Pacific/Fiji\" |\n\"Pacific/Funafuti\" |\n\"Pacific/Galapagos\" |\n\"Pacific/Gambier\" |\n\"Pacific/Guadalcanal\" |\n\"Pacific/Guam\" |\n\"Pacific/Honolulu\" |\n\"Pacific/Johnston\" |\n\"Pacific/Kiritimati\" |\n\"Pacific/Kosrae\" |\n\"Pacific/Kwajalein\" |\n\"Pacific/Majuro\" |\n\"Pacific/Marquesas\" |\n\"Pacific/Midway\" |\n\"Pacific/Nauru\" |\n\"Pacific/Niue\" |\n\"Pacific/Norfolk\" |\n\"Pacific/Noumea\" |\n\"Pacific/Pago_Pago\" |\n\"Pacific/Palau\" |\n\"Pacific/Pitcairn\" |\n\"Pacific/Pohnpei\" |\n\"Pacific/Ponape\" |\n\"Pacific/Port_Moresby\" |\n\"Pacific/Rarotonga\" |\n\"Pacific/Saipan\" |\n\"Pacific/Samoa\" |\n\"Pacific/Tahiti\" |\n\"Pacific/Tarawa\" |\n\"Pacific/Tongatapu\" |\n\"Pacific/Truk\" |\n\"Pacific/Wake\" |\n\"Pacific/Wallis\" |\n\"Pacific/Yap\" |\n\"Poland\" |\n\"Portugal\" |\n\"ROC\" |\n\"ROK\" |\n\"Singapore\" |\n\"Turkey\" |\n\"UCT\" |\n\"US/Alaska\" |\n\"US/Aleutian\" |\n\"US/Arizona\" |\n\"US/Central\" |\n\"US/East-Indiana\" |\n\"US/Eastern\" |\n\"US/Hawaii\" |\n\"US/Indiana-Starke\" |\n\"US/Michigan\" |\n\"US/Mountain\" |\n\"US/Pacific\" |\n\"US/Samoa\" |\n\"UTC\" |\n\"Universal\" |\n\"W-SU\" |\n\"WET\" |\n\"Zulu\" |\n\"America/Rio_Branco\" |\n\"America/Manaus\" |\n\"America/Cuiaba\" |\n\"America/Porto_Velho\" |\n\"America/Boa_Vista\" |\n\"America/Recife\" |\n\"America/Fortaleza\" |\n\"America/Noronha\";\n"
  },
  {
    "path": "packages/date/util.ts",
    "content": "interface CpfDigits {\n\tpenultimateDigit: number;\n\tultimateDigit: number;\n}\n\nconst removeSpecialCharsFromCpfRegex = /[\\.]|[-]/g;\n\nexport const formatValueToCpfPattern = (cpf: string): string => {\n\tconst cpfValue = removeSpecialCharsFromCpf(cpf);\n\tlet formattedValue: string = '';\n\tlet index: number = 0;\n\n\twhile (formattedValue.length < 14 && index < 11) {\n\t\tif (index === 3 || index === 6) {\n\t\t\tformattedValue += '.';\n\t\t} else if (index === 9) {\n\t\t\tformattedValue += '-';\n\t\t}\n\t\tformattedValue += cpfValue[index];\n\t\tindex++;\n\t}\n\n\treturn formattedValue;\n};\n\nexport const removeSpecialCharsFromCpf = (cpf: string): string => {\n\treturn cpf.replace(removeSpecialCharsFromCpfRegex, '');\n};\n\nconst getCpfDigitsNumbers = (cpf: string): CpfDigits => {\n\tconst lastTwoNumbers = cpf.slice(cpf.length - 2);\n\tconst penultimateDigit = parseInt(lastTwoNumbers[0]);\n\tconst ultimateDigit = parseInt(lastTwoNumbers[1]);\n\n\treturn {\n\t\tpenultimateDigit,\n\t\tultimateDigit,\n\t};\n};\n\nconst transformCpfInArrNumber = (cpf: string): number[] => {\n\tvar arr: number[] = [];\n\n\tlet index = 0;\n\twhile (index < 9) {\n\t\tarr.push(parseInt(cpf[index]));\n\t\tindex++;\n\t}\n\n\treturn arr;\n};\n\nexport const calculateCpfDigits = (cpfNumbers: number[]): CpfDigits => {\n\tconst factor = 11;\n\tlet index = 0;\n\tlet startAuxValue = 10;\n\tlet totalForDigit = 0;\n\n\twhile (index < 9) {\n\t\ttotalForDigit = totalForDigit + cpfNumbers[index] * startAuxValue;\n\t\tstartAuxValue--;\n\t\tindex++;\n\t}\n\n\tconst calcPDigit = totalForDigit % factor;\n\tconst resultPDigit = factor - calcPDigit;\n\tconst zeroIfPGreaterThanNine = resultPDigit > 9 ? 0 : resultPDigit;\n\tconst penultimateDigit = zeroIfPGreaterThanNine;\n\n\tindex = 0;\n\tstartAuxValue = 11;\n\ttotalForDigit = 0;\n\n\tcpfNumbers.push(penultimateDigit);\n\n\twhile (index < 10) {\n\t\ttotalForDigit = totalForDigit + cpfNumbers[index] * startAuxValue;\n\t\tstartAuxValue--;\n\t\tindex++;\n\t}\n\n\tconst calcUDigit = totalForDigit % factor;\n\tconst resultUDigit = factor - calcUDigit;\n\tconst zeroIfGreaterThanNine = resultUDigit > 9 ? 0 : resultUDigit;\n\tconst ultimateDigit = zeroIfGreaterThanNine;\n\n\treturn {\n\t\tpenultimateDigit,\n\t\tultimateDigit,\n\t};\n};\n\nexport const isValidCpfDigit = (cpf: string): boolean => {\n\tconst onlyNumbers = removeSpecialCharsFromCpf(cpf);\n\n\tif (onlyNumbers.length !== 11) {\n\t\treturn false;\n\t}\n\n\tconst digits = getCpfDigitsNumbers(onlyNumbers);\n\tconst arrNumbers = transformCpfInArrNumber(onlyNumbers);\n\tconst validDigits = calculateCpfDigits(arrNumbers);\n\n\treturn (\n\t\tdigits.penultimateDigit === validDigits.penultimateDigit &&\n\t\tdigits.ultimateDigit === validDigits.ultimateDigit\n\t);\n};\n\nexport default isValidCpfDigit;\n"
  },
  {
    "path": "packages/email/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.0.5-alpha.0](https://github.com/4lessandrodev/type-ddd/compare/@type-ddd/email@0.0.2...@type-ddd/email@0.0.5-alpha.0) (2024-12-16)\n\n\n\n## 4.0.5 (2024-11-28)\n\n\n### Bug Fixes\n\n* change type create method return null [#194](https://github.com/4lessandrodev/type-ddd/issues/194) ([2cd03bf](https://github.com/4lessandrodev/type-ddd/commit/2cd03bf34387f4889a0a292ba350f2c0cfc753b7))\n* solve error module not found [#449](https://github.com/4lessandrodev/type-ddd/issues/449) ([e9d14f6](https://github.com/4lessandrodev/type-ddd/commit/e9d14f694cafc9c2123cc31055a4561f460a82d3))\n\n\n\n## 4.0.3 (2024-07-26)\n\n\n\n\n\n# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n## Unreleased\n\n---\n\n## Released\n\n---\n\n### [0.0.4] - 2024-11-28\n\n### Fix\n\n- update rich-domain lib to check nullish type: now 'create' return a possibly null value in Result instance.\n\n---\n\n### [0.0.3] - 2024-09-26\n\n### Fix\n\n- Corrected `\"files\"` in `package.json` to include `utils.js` and `utils.d.ts`, resolving module not found errors during compilation.\n\n---\n\n### [0.0.2] - 2024-05-31\n\n### Docs\n\n- Doc: update documentation\n\n---\n\n### [0.0.1] - 2024-05-31\n\n### Base\n\n- Create base value object as single pack\n"
  },
  {
    "path": "packages/email/README.md",
    "content": "# `@type-ddd/email`\n\n> The @type-ddd/email module provides a class Email for handling email addresses in TypeScript. It includes methods for validating email addresses, extracting parts of the email (such as nickname and domain), and creating instances of validated emails.\n\n## Installation\n\nInstall `rich-domain` and `@type-ddd/email` with your favorite package manager:\n\n```sh\n\nnpm i rich-domain @type-ddd/email\n\n#OR \n\nyarn add rich-domain @type-ddd/email\n\n```\n\n## Usage\n\n```ts\n\nimport { Email } from '@type-ddd/email';\n\n// Check if is valid value \nconst isValid = Email.isValid('sample@domain.com');\n// true\n\n// Initialize Email instance with a valid email address\nconst email = Email.init('example@example.com');\n\n// OR\n\n// Create Email instance from provided email address\nconst result = Email.create('example@example.com');\n\n// Get parts of the email address\nconst nickname = email.nick();\nconst domain = email.domain();\n\n\n```\n\n### Block some domains\n\nIf you want to block some specifics domains\n\n```ts\n\nimport { Email } from '@type-ddd/email';\n\nconst list = ['hack.com'];\n\nReflect.set(Email, 'BLOCKED_DOMAINS', list);\n\nconst isValid = Email.isValid('user@hack.com');\n// false\n\nconst isValid = Email.isValid('user@gmail.com');\n// true\n\n```\n\n### Allowed some domains\n\nIf you want to allow only some specifics domains\n\n```ts\n\nimport { Email } from '@type-ddd/email';\n\nconst list = ['my-company.com'];\n\nReflect.set(Email, 'VALID_DOMAINS', list);\n\nconst isValid = Email.isValid('user@my-company.com');\n// true\n\nconst isValid = Email.isValid('user@gmail.com');\n// false\n\n```\n"
  },
  {
    "path": "packages/email/__tests__/email-validator.spec.ts",
    "content": "import IsValidEmail, { GetCharCode, IsSpecialChar } from '../email.validator.util';\n\ndescribe('email-validator', () => {\n    it('should return 0 if is not string', () => {\n        const code = GetCharCode(3 as any);\n        expect(code).toBe(0);\n    });\n\n    it('should return true', () => {\n        const is = IsSpecialChar('+');\n        expect(is).toBeTruthy();\n    });\n\n    it('should to be false', () => {\n        const invalid = 'invalid-log-email-value'.repeat(10);\n        const long = invalid + '@gmail.com';\n        expect(IsValidEmail(long)).toBeFalsy();\n    });\n\n    it('should to be false', () => {\n        const invalid = 'invalid-log-email-value'.repeat(20);\n        const long = invalid + '@gmail.com';\n        expect(IsValidEmail(long)).toBeFalsy();\n    });\n\n    it('should to be false', () => {\n        expect(IsValidEmail(0 as any)).toBeFalsy();\n    });\n});\n"
  },
  {
    "path": "packages/email/__tests__/email.value-object.spec.ts",
    "content": "import EmailValueObject from '../index';\n\ndescribe('email-value-object.util', () => {\n\tit('should init an instance with success', () => {\n\t\tconst init = () => EmailValueObject.init('sample@live.com');\n\t\texpect(init).not.toThrowError();\n\t});\n\n\tit('should throw an error on init an instance with invalid value', () => {\n\t\tconst init = () => EmailValueObject.init('invalid');\n\t\texpect(init).toThrowError();\n\t});\n\n\tit('should validate', () => {\n\t\texpect(EmailValueObject.isValid('invalid')).toBeFalsy();\n\t\texpect(EmailValueObject.isValid('sample@gmail.com')).toBeTruthy();\n\t});\n\n\tit('should create a valid email with success', () => {\n\t\tconst valueObject = EmailValueObject.create('john+doe@domain.com');\n\t\texpect(valueObject.isOk()).toBe(true);\n\t});\n\n\tit('should to be invalid email nick ends with +', () => {\n\t\tconst valueObject = EmailValueObject.create('johndoe+@domain.com');\n\t\texpect(valueObject.isFail()).toBe(true);\n\t});\n\n\tit('should to be invalid email nick starts with +', () => {\n\t\tconst valueObject = EmailValueObject.create('+johndoe@domain.com');\n\t\texpect(valueObject.isFail()).toBe(true);\n\t});\n\n\tit('should to be invalid email domain starts with +', () => {\n\t\tconst valueObject = EmailValueObject.create('johndoe@+domain.com');\n\t\texpect(valueObject.isFail()).toBe(true);\n\t});\n\n\tit('should to be invalid email domain ends with +', () => {\n\t\tconst valueObject = EmailValueObject.create('johndoe@domain.com+');\n\t\texpect(valueObject.isFail()).toBe(true);\n\t});\n\n\tit('should be defined', () => {\n\t\tconst valueObject = EmailValueObject.create;\n\t\texpect(valueObject).toBeDefined();\n\t});\n\n\tit('should create a valid email with success', () => {\n\t\tconst valueObject = EmailValueObject.create('valid_email@domain.com');\n\t\texpect(valueObject.isOk()).toBe(true);\n\t});\n\n\tit('should transform value to lower on create', () => {\n\t\tconst valueObject = EmailValueObject.create(\n\t\t\t'Valid_EmaiL@Domain.Com',\n\t\t).value();\n\t\texpect(valueObject?.value()).toBe('valid_email@domain.com');\n\t});\n\n\tit('should create and get value from a valid email with success', () => {\n\t\tconst valueObject = EmailValueObject.create(\n\t\t\t'valid_email@domain.com',\n\t\t).value();\n\t\texpect(valueObject?.value()).toBe('valid_email@domain.com');\n\t});\n\n\tit('should to be a valid email', () => {\n\t\tconst valueObject = EmailValueObject.create(\n\t\t\t'test-email-124@domain.com',\n\t\t);\n\t\texpect(valueObject.isOk()).toBe(true);\n\t\texpect(valueObject.value()?.value()).toBe('test-email-124@domain.com');\n\t});\n\n\tit('should to be a valid email', () => {\n\t\tconst valueObject = EmailValueObject.create(\n\t\t\t'test-some-value-12@domain.name',\n\t\t);\n\t\texpect(valueObject.isOk()).toBe(true);\n\t\texpect(valueObject.value()?.value()).toBe(\n\t\t\t'test-some-value-12@domain.name',\n\t\t);\n\t});\n\n\tit('should fail if provide an invalid value', () => {\n\t\tconst valueObject = EmailValueObject.create('invalid_email');\n\t\texpect(valueObject.isFail()).toBe(true);\n\t\texpect(valueObject.error()).toBe('Invalid email');\n\t});\n\n\tit('should fail if provide an invalid value', () => {\n\t\tconst valueObject = EmailValueObject.create(\n\t\t\t'invalid_email@domain.long-subdomain.br',\n\t\t);\n\t\texpect(valueObject.isFail()).toBe(true);\n\t\texpect(valueObject.error()).toBe('Invalid email');\n\t});\n\n\tit('should fail if provide an invalid value', () => {\n\t\tconst valueObject = EmailValueObject.create(\n\t\t\t'invalid_email@domain.net.long-country',\n\t\t);\n\t\texpect(valueObject.isFail()).toBe(true);\n\t\texpect(valueObject.error()).toBe('Invalid email');\n\t});\n\n\tit('should fail if provide an invalid value', () => {\n\t\tconst valueObject = EmailValueObject.create(\n\t\t\t'invalid_email@-domain.net.tz',\n\t\t);\n\t\texpect(valueObject.isFail()).toBe(true);\n\t\texpect(valueObject.error()).toBe('Invalid email');\n\t});\n\n\tit('should fail if provide an invalid value', () => {\n\t\tconst valueObject = EmailValueObject.create(\n\t\t\t'-invalid_email@domain.net.tz',\n\t\t);\n\t\texpect(valueObject.isFail()).toBe(true);\n\t\texpect(valueObject.error()).toBe('Invalid email');\n\t});\n\n\tit('should fail if provide an invalid value', () => {\n\t\tconst valueObject = EmailValueObject.create(\n\t\t\t'invalid_email@domain.net.tz-',\n\t\t);\n\t\texpect(valueObject.isFail()).toBe(true);\n\t\texpect(valueObject.error()).toBe('Invalid email');\n\t});\n\n\tit('should fail if provide an invalid value', () => {\n\t\tconst valueObject = EmailValueObject.create(\n\t\t\t'invalid_email@domain.net.br8',\n\t\t);\n\t\texpect(valueObject.isFail()).toBe(true);\n\t\texpect(valueObject.error()).toBe('Invalid email');\n\t});\n\n\tit('should get nick', () => {\n\t\tconst valueObject = EmailValueObject.create(\n\t\t\t'username@domain.com',\n\t\t).value();\n\t\texpect(valueObject?.nick()).toBe('username');\n\t});\n\n\tit('should get domain', () => {\n\t\tconst valueObject = EmailValueObject.create(\n\t\t\t'username@domain.com',\n\t\t).value();\n\t\texpect(valueObject?.domain()).toBe('domain.com');\n\t});\n\n\tit('should create value object with success', () => {\n\t\tconst valueObject = EmailValueObject.create(\n\t\t\t'username.nickname@domain.com',\n\t\t);\n\t\texpect(valueObject.isOk()).toBeTruthy();\n\t\texpect(valueObject.value()?.value()).toBe(\n\t\t\t'username.nickname@domain.com',\n\t\t);\n\t});\n\n\tit('should create value object with success', () => {\n\t\tconst valueObject = EmailValueObject.create('rocio65@gmail.com');\n\t\texpect(valueObject.isOk()).toBeTruthy();\n\t\texpect(valueObject.value()?.value()).toBe('rocio65@gmail.com');\n\t});\n\n\tit('should create value object with success', () => {\n\t\tconst valueObject = EmailValueObject.create('user_nick2.0@hotmail.com');\n\t\texpect(valueObject.isOk()).toBeTruthy();\n\t\texpect(valueObject.value()?.value()).toBe('user_nick2.0@hotmail.com');\n\t});\n\n\tit('should create value object with success', () => {\n\t\tconst valueObject = EmailValueObject.create('rocio_65@gmail.com');\n\t\texpect(valueObject.isOk()).toBeTruthy();\n\t\texpect(valueObject.value()?.value()).toBe('rocio_65@gmail.com');\n\t});\n\n\tit('should create value object with success', () => {\n\t\tconst valueObject = EmailValueObject.create('4you@gmail.com');\n\t\texpect(valueObject.isOk()).toBeTruthy();\n\t\texpect(valueObject.value()?.value()).toBe('4you@gmail.com');\n\t});\n\n\tit('should fails if not provide a domain', () => {\n\t\tconst valueObject = EmailValueObject.create('4you@gmail');\n\t\texpect(valueObject.isFail()).toBeTruthy();\n\t});\n\n\tit('should fails if provide two dots', () => {\n\t\tconst valueObject = EmailValueObject.create(\n\t\t\t'my-email8950@hotmail..com',\n\t\t);\n\t\texpect(valueObject.isFail()).toBeTruthy();\n\t});\n\n\tit('should fails if provide an invalid domain', () => {\n\t\tconst valueObject = EmailValueObject.create(\n\t\t\t'inVaLLiD_Email@MYDomain.longInvalid.br',\n\t\t);\n\t\texpect(valueObject.isFail()).toBeTruthy();\n\t});\n\n\tit('should fails if provide an space', () => {\n\t\tconst valueObject = EmailValueObject.create('invalid email@domain.com');\n\t\texpect(valueObject.isFail()).toBeTruthy();\n\t});\n\n\tit('should get domain with success', () => {\n\t\tconst vo = EmailValueObject.create('my-email@domain.com').value();\n\t\texpect(vo?.domain()).toBe('domain.com');\n\t});\n\n\tit('should get nick with success', () => {\n\t\tconst vo = EmailValueObject.create('my-email@domain.com').value();\n\t\texpect(vo?.get('value')).toBe('my-email@domain.com');\n\t\texpect(vo?.nick()).toBe('my-email');\n\t});\n\n\tit('should to be a valid domain', () => {\n\t\tconst result = EmailValueObject.create('some-name@gmail.com');\n\t\texpect(result.isOk()).toBeTruthy();\n\t});\n});\n\ndescribe('email-blocked-list', () => {\n\tit('should fail if domain is on blocked list', () => {\n\t\tReflect.set(EmailValueObject, 'BLOCKED_DOMAINS', [\n\t\t\t'gmail.com',\n\t\t\t'hotmail.com',\n\t\t]);\n\t\tconst result = EmailValueObject.create('some-name@gmail.com');\n\t\texpect(result.isFail()).toBeTruthy();\n\t});\n\n\tit('should fail is domain is not available', () => {\n\t\tReflect.set(EmailValueObject, 'VALID_DOMAINS', [\n\t\t\t'types.com',\n\t\t\t'finance.com',\n\t\t]);\n\t\tconst result1 = EmailValueObject.create('some-name@crypto.com');\n\t\tconst result2 = EmailValueObject.create('some-name@finance.com');\n\n\t\texpect(result1.isFail()).toBeTruthy();\n\t\texpect(result2.isOk()).toBeTruthy();\n\t});\n\n\tit('should fail with custom message', () => {\n\t\tReflect.set(EmailValueObject, 'MESSAGE', 'Valor inválido para email');\n\t\tconst result = EmailValueObject.create('invalid');\n\n\t\texpect(result.isFail()).toBeTruthy();\n\t\texpect(result.error()).toBe('Valor inválido para email');\n\t});\n});\n"
  },
  {
    "path": "packages/email/email.validator.util.ts",
    "content": "/**\n * a-z = 97 - 122\n * 0-9 = 48 - 57\n * 95 = _\n * 45 = -\n * 64 = @\n * 46 = .\n */\nconst ValidChars = { min: 97, max: 122, specials: [95, 45, 64, 46, 43] };\n\nconst ValidCharsNum = { min: 48, max: 57 };\n\nexport const GetCharCode = (char: string): number => {\n\treturn typeof char === 'string' ? char.charCodeAt(0) : 0;\n};\n\nexport const IsSpecialChar = (char: string): boolean => {\n\tconst code = GetCharCode(char);\n\treturn ValidChars.specials.includes(code);\n};\n\nexport const IsAlphabet = (char: string): boolean => {\n\tconst code = GetCharCode(char);\n\tconst isGreaterThanMin = code >= ValidChars.min;\n\tconst isLessThanMax = code <= ValidChars.max;\n\treturn isGreaterThanMin && isLessThanMax;\n};\n\nexport const IsNumber = (char: string): boolean => {\n\tconst charCode = GetCharCode(char);\n\tconst isValid =\n\t\tcharCode >= ValidCharsNum.min && charCode <= ValidCharsNum.max;\n\treturn isValid;\n};\n\nexport const IsValidChar = (char: string): boolean => {\n\tconst isAlphabet = IsAlphabet(char);\n\tconst isSpecial = IsSpecialChar(char);\n\tconst isNumber = IsNumber(char);\n\n\treturn isAlphabet || isSpecial || isNumber;\n};\n\nexport const HasValidLength = (email: string): boolean => {\n\treturn typeof email === 'string' && email.length <= 256;\n};\n\nexport const IsValidPart = (part: string): boolean => {\n\tconst hifen = 45;\n\tconst isValidSpecialChar = (char: string): boolean =>\n\t\tGetCharCode(char) === hifen;\n\tconst chars = part.replace(/\\./g, '').split('');\n\tlet i = 0;\n\twhile (chars[i]) {\n\t\tconst isValidChar =\n\t\t\tIsAlphabet(chars[i]) ||\n\t\t\tIsNumber(chars[i]) ||\n\t\t\tisValidSpecialChar(chars[i]);\n\t\tif (!isValidChar) return false;\n\t\ti++;\n\t}\n\n\treturn true;\n};\n\nexport const IsValidOrganizationName = (name: string): boolean => {\n\treturn name.length <= 10 && name.length >= 2;\n};\n\nexport const IsValidCountry = (country: string): boolean => {\n\tconst isValidLength = country.length > 0 && country.length <= 4;\n\tif (!isValidLength) return false;\n\n\tconst chars = country.split('');\n\n\tlet i = 0;\n\twhile (chars[i]) {\n\t\tconst isChar = IsAlphabet(chars[i]);\n\t\tif (!isChar) return false;\n\t\ti++;\n\t}\n\n\treturn true;\n};\n\nexport const IsValidNick = (email: string): boolean => {\n\tconst nick = email.split('@')?.[0];\n\treturn (\n\t\t!nick.startsWith('+') &&\n\t\t!nick.endsWith('+') &&\n\t\t!nick.startsWith('-') &&\n\t\t!nick.endsWith('-')\n\t);\n};\n\nexport const IsValidDomain = (email: string): boolean => {\n\tconst domain = email.split('@');\n\tconst parts = domain[1].split('.');\n\tif (parts.length === 1 || parts.length > 3) return false;\n\n\tconst isInValidStartAndEnd = domain[1].startsWith('-') ||\n\t\tdomain[1].endsWith('-');\n\n\tif (isInValidStartAndEnd) return false;\n\n\tconst isLessThanMax = email.length <= 64;\n\tif (!isLessThanMax) return false;\n\n\tconst isValidOrgName = IsValidOrganizationName(parts[1]);\n\n\tif (typeof parts[2] === 'string') {\n\t\tconst isValidCountry = IsValidCountry(parts[2]);\n\t\tif (!isValidCountry) return false;\n\t}\n\n\tif (!isValidOrgName) return false;\n\n\tlet i = 0;\n\twhile (parts[i]) {\n\t\tconst isValidPart = IsValidPart(parts[i]);\n\t\tif (!isValidPart) return false;\n\t\ti++;\n\t}\n\treturn true;\n};\n\n/**\n * @description validate email\n * @param email string with @ symbol\n * @returns true if is a valid email and false if not\n */\nexport const IsValidEmail = (email: string): boolean => {\n\tconst isString: boolean = typeof email === 'string';\n\tif (!isString) return false;\n\n\tconst trimEmail = email.trim().toLowerCase();\n\n\tconst isValidFirsChar: boolean = IsAlphabet(trimEmail[0]) ||\n\t\tIsNumber(trimEmail[0]);\n\n\tif (!isValidFirsChar) return false;\n\n\tconst hasOnlyOneAt: boolean = trimEmail.split('')\n\t\t.filter((char) => char === '@').length === 1;\n\n\tconst hasOnlyOnePlus: boolean = trimEmail.split('')\n\t\t.filter((char) => char === '+').length > 1;\n\n\tif (!hasOnlyOneAt || hasOnlyOnePlus) return false;\n\n\tconst isValidLength = HasValidLength(trimEmail);\n\n\tif (!isValidLength) return false;\n\n\tconst isValidDomain = IsValidDomain(trimEmail);\n\n\tif (!isValidDomain) return false;\n\n\tif (!IsValidNick(trimEmail)) return false;\n\n\tconst hasInvalidChar = trimEmail\n\t\t.split('')\n\t\t.map((char): boolean => IsValidChar(char))\n\t\t.includes(false);\n\n\tif (hasInvalidChar) return false;\n\n\treturn true;\n};\n\nexport default IsValidEmail;\n"
  },
  {
    "path": "packages/email/index.ts",
    "content": "import { Result, ValueObject } from 'rich-domain';\nimport IsValidEmail from './email.validator.util';\n\nexport class Email extends ValueObject<string> {\n\tprotected static readonly BLOCKED_DOMAINS: Array<string> = [];\n\tprotected static readonly VALID_DOMAINS: Array<string> = [];\n\tprotected static readonly MESSAGE: string = 'Invalid email';\n\n\tprivate constructor(props: string) {\n\t\tsuper(props);\n\t}\n\n\tvalue(): string {\n\t\treturn this.props;\n\t}\n\n\tnick(): string {\n\t\treturn this.props.slice(0, this.props.indexOf('@'));\n\t}\n\n\tdomain(): string {\n\t\treturn this.props\n\t\t\t.slice(this.props.indexOf('@') + 1);\n\t}\n\n\tpublic static isValid(value: string): boolean {\n\t\treturn this.isValidProps(value);\n\t}\n\n\t/**\n\t * @description validate email value\n\t * @param email string\n\t * @returns true if email value is valid and returns false if not.\n\t *\n\t * @requires email not greater than 256 char.\n\t * @requires contain symbol @\n\t * @requires contain [domain].[org].[optional country]\n\t * @requires contain [nick letters] with [hifen or numbers]\n\t * @requires starts [a-z]\n\t * @requires ends [a-z]\n\t */\n\tpublic static isValidProps(email: string): boolean {\n\t\tconst isValid = IsValidEmail(email);\n\t\tif (!isValid) return false;\n\n\t\tconst domain = email.slice(email.indexOf('@') + 1).toLowerCase();\n\n\t\tconst isBlockedDomain = Email.BLOCKED_DOMAINS.map(\n\t\t\t(blockedDomain) => blockedDomain.toLowerCase().includes(domain),\n\t\t).includes(true);\n\n\t\tif (Email.VALID_DOMAINS.length === 0) {\n\t\t\treturn !isBlockedDomain;\n\t\t}\n\n\t\tconst isAvailable = Email.VALID_DOMAINS.map((freeDomain) =>\n\t\t\tfreeDomain.toLowerCase().includes(domain),\n\t\t).includes(true);\n\n\t\treturn isAvailable && !isBlockedDomain;\n\t}\n\n\n\t/**\n\t * \n\t * @param value value as string\n\t * @returns instance of Email or throw an error\n\t */\n\tpublic static init(value: string): Email {\n\t\tconst isValidValue = Email.isValidProps(value);\n\t\tif (!isValidValue) throw new Error(Email.MESSAGE);\n\t\treturn new Email(value.toLowerCase());\n\t}\n\n\tpublic static create(value: string): Result<Email | null> {\n\t\tif (!Email.isValidProps(value)) {\n\t\t\treturn Result.fail(Email.MESSAGE);\n\t\t}\n\t\treturn Result.Ok(new Email(value.toLowerCase()));\n\t}\n}\n\nexport default Email;\n"
  },
  {
    "path": "packages/email/package.json",
    "content": "{\n  \"name\": \"@type-ddd/email\",\n  \"description\": \"Library that provides TypeScript type definitions for handling Email in Domain-Driven Design contexts. It facilitates the validation and manipulation of emails.\",\n  \"version\": \"0.1.0\",\n  \"main\": \"index.js\",\n  \"types\": \"index.d.ts\",\n  \"author\": \"Alessandro Dev\",\n  \"license\": \"MIT\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"keywords\": [\n    \"Complexity\",\n    \"Business Logic\",\n    \"DDD\",\n    \"Domain Driving Design\",\n    \"DDD-Utils\",\n    \"Base Value Object\",\n    \"Clean Architecture\",\n    \"Email\",\n    \"Validation\",\n    \"Formatting\",\n    \"Value Object\",\n    \"Utility\",\n    \"Security\",\n    \"Standards\"\n  ],\n  \"scripts\": {\n    \"build\": \"tsc\"\n  },\n  \"peerDependencies\": {\n    \"rich-domain\": \"^1.25.0\"\n  },\n  \"files\": [\n    \"index.js\",\n    \"index.d.ts\",\n    \"email.validator.util.js\",\n    \"email.validator.util.d.ts\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/4lessandrodev/type-ddd.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/4lessandrodev/type-ddd/issues\"\n  },\n  \"homepage\": \"https://github.com/4lessandrodev/type-ddd/tree/main/packages/email\",\n  \"gitHead\": \"4cb9159bde8d6fc951e9d902feed2ad25da49fa4\"\n}\n"
  },
  {
    "path": "packages/email/tsconfig.build.json",
    "content": "{\n    \"extends\": \"../tsconfig.build.json\",\n    \"compilerOptions\": {\n        \"outDir\": \".\",\n        \"rootDir\": \".\",\n        \"paths\": {}\n    },\n    \"exclude\": [\n        \"node_modules\",\n        \"dist\",\n        \"__tests__/**/*\",\n        \"*.spec.ts\"\n    ],\n    \"references\": []\n}"
  },
  {
    "path": "packages/email/tsconfig.json",
    "content": "{\n\t\"extends\": \"../tsconfig.build.json\",\n\t\"compilerOptions\": {\n\t\t\"types\": [\n\t\t\t\"node\"\n\t\t]\n\t},\n\t\"files\": [],\n\t\"include\": [],\n\t\"references\": [\n\t\t{\n\t\t\t\"path\": \"./tsconfig.build.json\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "packages/logger/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.0.3-alpha.0](https://github.com/4lessandrodev/type-ddd/compare/@type-ddd/logger@0.0.2...@type-ddd/logger@0.0.3-alpha.0) (2024-12-16)\n\n**Note:** Version bump only for package @type-ddd/logger\n\n\n\n\n\n# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n## Unreleased\n\n---\n\n## Released\n\n### [0.0.2] - 2024-05-31\n\n### Docs\n\n- Doc: update documentation\n\n---\n\n### [0.0.1] - 2024-05-31\n\n### Base\n\n- Create base value object as single pack\n"
  },
  {
    "path": "packages/logger/README.md",
    "content": "# `types-ddd`\n\n> TODO: description\n\n## Usage\n\n```\nconst typesDdd = require('types-ddd');\n\n// TODO: DEMONSTRATE API\n```\n"
  },
  {
    "path": "packages/logger/__tests__/logger.spec.ts",
    "content": "import Logger, { checkEnv } from '../index';\n\ndescribe('Logger', () => {\n\tit('should log if is not production and log is not off', () => {\n\t\tprocess.env.NODE_ENV = undefined;\n\t\tprocess.env.TYPES_DDD_LOGS = undefined;\n\n\t\tconst callback = jest.fn(() => 'Info');\n\n\t\tcheckEnv(callback);\n\n\t\texpect(callback).toHaveBeenCalled();\n\t});\n\n\tit('should not log if is production and log is not off', () => {\n\t\tprocess.env.NODE_ENV = 'production';\n\t\tprocess.env.TYPES_DDD_LOGS = undefined;\n\n\t\tconst callback = jest.fn(() => 'Info');\n\n\t\tcheckEnv(callback);\n\n\t\texpect(callback).not.toHaveBeenCalled();\n\t});\n\n\tit('should not log if is not production and log is off', () => {\n\t\tprocess.env.NODE_ENV = undefined;\n\t\tprocess.env.TYPES_DDD_LOGS = 'off';\n\n\t\tconst callback = jest.fn(() => 'Info');\n\n\t\tcheckEnv(callback);\n\n\t\texpect(callback).not.toHaveBeenCalled();\n\t});\n\n\tit('should log if is production and log is error', () => {\n\t\tprocess.env.NODE_ENV = 'production';\n\t\tprocess.env.TYPES_DDD_LOGS = 'error';\n\n\t\tconst callback = jest.fn(() => 'Error');\n\n\t\tcheckEnv(callback, 'error');\n\n\t\texpect(callback).toHaveBeenCalled();\n\t});\n\n\tit('should log if is production and log is error', () => {\n\t\tprocess.env.NODE_ENV = 'production';\n\t\tprocess.env.TYPES_DDD_LOGS = 'info';\n\n\t\tconst callback = jest.fn(() => 'Info');\n\n\t\tcheckEnv(callback, 'info');\n\n\t\texpect(callback).toHaveBeenCalled();\n\t});\n\n\tit('should log if is production and log is warn', () => {\n\t\tprocess.env.NODE_ENV = 'production';\n\t\tprocess.env.TYPES_DDD_LOGS = 'warn';\n\n\t\tconst callback = jest.fn(() => 'Warn');\n\n\t\tcheckEnv(callback, 'warn');\n\n\t\texpect(callback).toHaveBeenCalled();\n\t});\n\n\tit('should not log if is production and log is error, but is info log', () => {\n\t\tprocess.env.NODE_ENV = 'production';\n\t\tprocess.env.TYPES_DDD_LOGS = 'error';\n\n\t\tconst callback = jest.fn(() => 'Error');\n\n\t\tcheckEnv(callback, 'info');\n\n\t\texpect(callback).not.toHaveBeenCalled();\n\t});\n\n\tit('should not log if is production and log is off', () => {\n\t\tprocess.env.NODE_ENV = 'production';\n\t\tprocess.env.TYPES_DDD_LOGS = 'off';\n\n\t\tconst callback = jest.fn(() => 'Info');\n\n\t\tcheckEnv(callback);\n\n\t\texpect(callback).not.toHaveBeenCalled();\n\t});\n\n\tit('logger must print message', () => {\n\t\tprocess.env.NODE_ENV = undefined;\n\t\tprocess.env.TYPES_DDD_LOGS = undefined;\n\t\tLogger.info('some success message');\n\t});\n});\n"
  },
  {
    "path": "packages/logger/index.ts",
    "content": "import pino, { BaseLogger } from 'pino';\nimport { LoggerOptions } from 'pino';\n\nclass DefaultLogger {\n\tprotected static pino: BaseLogger = null as unknown as BaseLogger;\n\tprotected static config: LoggerOptions = {\n\t\ttransport: {\n\t\t\ttarget: 'pino-pretty',\n\t\t\toptions: {\n\t\t\t\ttranslateTime: 'HH:MM:ss',\n\t\t\t\tignore: 'pid,hostname',\n\t\t\t\tprettyPrint: {\n\t\t\t\t\tcolorize: true,\n\t\t\t\t\tlevelFirst: true,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t};\n\n\tpublic static instance() {\n\t\tif (!DefaultLogger.pino) {\n\t\t\tthis.pino = pino(DefaultLogger.config);\n\t\t}\n\t\treturn this.pino;\n\t}\n}\n\ntype LogsType = 'error' | 'info' | 'warn';\n\nexport const checkEnv = (callback: Function, type?: LogsType): void => {\n\tconst isProduction = process.env.NODE_ENV === 'production';\n\tconst isLogOff = process.env.TYPES_DDD_LOGS === 'off';\n\tconst errorTypeMatch = process.env.TYPES_DDD_LOGS === type;\n\n\tif ((!isProduction && !isLogOff) || errorTypeMatch) {\n\t\tcallback();\n\t}\n};\n\nconst loggerInstance = DefaultLogger.instance();\n\nconst Logger = {\n\tinfo: (message: string) => {\n\t\tconst callback = () => loggerInstance.info(message);\n\t\tcheckEnv(callback, 'info');\n\t},\n\terror: (message: string) => {\n\t\tconst callback = () => loggerInstance.error(message);\n\t\tcheckEnv(callback, 'error');\n\t},\n\twarn: (message: string) => {\n\t\tconst callback = () => loggerInstance.warn(message);\n\t\tcheckEnv(callback, 'warn');\n\t},\n};\n\nexport { Logger };\nexport default Logger;\n"
  },
  {
    "path": "packages/logger/package.json",
    "content": "{\n  \"name\": \"@type-ddd/logger\",\n  \"description\": \"This package provide utils file and interfaces to assistant build a complex application with domain driving design\",\n  \"version\": \"0.1.0\",\n  \"main\": \"index.js\",\n  \"types\": \"index.d.ts\",\n  \"author\": \"Alessandro Dev\",\n  \"license\": \"MIT\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\"\n  },\n  \"dependencies\": {\n    \"pino\": \"^9.0.0\",\n    \"pino-pretty\": \"^13.0.0\"\n  },\n  \"files\": [\n    \"index.js\",\n    \"index.d.ts\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/4lessandrodev/type-ddd.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/4lessandrodev/type-ddd/issues\"\n  },\n  \"homepage\": \"https://github.com/4lessandrodev/type-ddd/tree/main/packages/logger\",\n  \"gitHead\": \"4cb9159bde8d6fc951e9d902feed2ad25da49fa4\"\n}\n"
  },
  {
    "path": "packages/logger/tsconfig.build.json",
    "content": "{\n    \"extends\": \"../tsconfig.build.json\",\n    \"compilerOptions\": {\n        \"outDir\": \".\",\n        \"rootDir\": \".\",\n        \"paths\": {}\n    },\n    \"exclude\": [\n        \"node_modules\",\n        \"dist\",\n        \"__tests__/**/*\",\n        \"*.spec.ts\"\n    ],\n    \"references\": []\n}"
  },
  {
    "path": "packages/logger/tsconfig.json",
    "content": "{\n\t\"extends\": \"../tsconfig.build.json\",\n\t\"compilerOptions\": {\n\t\t\"types\": [\n\t\t\t\"node\"\n\t\t]\n\t},\n\t\"files\": [],\n\t\"include\": [],\n\t\"references\": [\n\t\t{\n\t\t\t\"path\": \"./tsconfig.build.json\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "packages/money/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.0.4-alpha.0](https://github.com/4lessandrodev/type-ddd/compare/@type-ddd/money@0.0.2...@type-ddd/money@0.0.4-alpha.0) (2024-12-16)\n\n\n\n## 4.0.5 (2024-11-28)\n\n\n### Bug Fixes\n\n* change type create method return null [#194](https://github.com/4lessandrodev/type-ddd/issues/194) ([2cd03bf](https://github.com/4lessandrodev/type-ddd/commit/2cd03bf34387f4889a0a292ba350f2c0cfc753b7))\n\n\n\n## 4.0.3 (2024-07-26)\n\n\n\n\n\n# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n## Unreleased\n\n---\n\n## Released\n\n---\n\n### [0.0.3] - 2024-11-28\n\n### Fix\n\n- update rich-domain lib to check nullish type: now 'create' return a possibly null value in Result instance.\n\n### [0.0.2] - 2024-05-31\n\n### Docs\n\n- Doc: update documentation\n\n---\n\n### [0.0.1] - 2024-05-14\n\n### Base\n\n- Create base value object as single pack\n"
  },
  {
    "path": "packages/money/README.md",
    "content": "# `@type-ddd/money`\n\n> The @type-ddd/money library provides TypeScript type definitions for handling Money in Domain-Driven Design contexts. It facilitates the validation, formatting, and manipulation of monetary values, adhering to DDD principles.\n\n---\n\n## Installation\n\nInstall `rich-domain` and `@type-ddd/money` with your favorite package manager\n\n---\n\n```sh\n\nnpm i rich-domain @type-ddd/money\n\n# OR\n\nyarn add rich-domain @type-ddd/money\n\n```\n\n## Usage\n\n```ts\n\n\nimport { Money } from '@type-ddd/money'\n\n// Initialize a Money object with the provided value\nconst amount = Money.init(100);\n\n// OR\n\nconst result = Money.create(100);\n\n// Check if a value is a valid monetary amount\nconst isValid = Money.isValid(100);\n\n// Sum two monetary values or Money objects\nconst total = Money.sum(amount, 50);\n\n// Subtract one monetary value or Money object from another\nconst difference = Money.subtract(total, 25);\n\n// Multiply two monetary values or Money objects\nconst product = Money.multiply(difference, 2);\n\n// Divide one monetary value or Money object by another\nconst quotient = Money.divide(product, 4);\n\n// Round down the monetary value to the nearest integer\nconst floorValue = quotient.floor();\n\n// Round up the monetary value to the nearest integer\nconst ceilValue = quotient.ceil();\n\n// Calculate compound interest based on the provided rate and periods\nconst interest = Money.compoundInterest(5, 10);\n\n// Generate a random monetary value within the specified range\nconst randomAmount = Money.random(10, 100);\n\n// Calculate the average value among the provided Money objects\nconst average = Money.average([amount, total, difference]);\n\n// Convert the current Money value to another currency using the provided exchange rate\nconst convertedAmount = amount.convertTo(2);\n\n// Generate a formatted string representing the monetary value in a specific currency and locale\nconst formattedAmount = amount.coin('USD', 'en-US');\n\nconsole.log(formattedAmount);\n// Output: $100.00 (assuming 100 is the amount in USD)\n\n```\n"
  },
  {
    "path": "packages/money/__tests__/money.spec.ts",
    "content": "import { Money } from '../index';\n\ndescribe('money', () => {\n\tdescribe('create', () => {\n\t\tit('should create instance with success', () => {\n\t\t\tconst result = Money.create(1);\n\t\t\texpect(result.isOk()).toBeTruthy();\n\t\t});\n\n\t\tit('should create instance with success', () => {\n\t\t\tconst result = Money.create(-1);\n\t\t\texpect(result.isOk()).toBeTruthy();\n\t\t});\n\n\t\tit('should create instance with success', () => {\n\t\t\tconst result = Money.init(1);\n\t\t\texpect(result.value()).toBe(1);\n\t\t});\n\n\t\tit('should create instance with success', () => {\n\t\t\tconst result = Money.init(-1);\n\t\t\texpect(result.value()).toBe(-1);\n\t\t});\n\n\t\tit('should return fail', () => {\n\t\t\tconst result = Money.create(Number.MAX_SAFE_INTEGER + 1);\n\t\t\texpect(result.isFail()).toBeTruthy();\n\t\t});\n\n\t\tit('should return fail', () => {\n\t\t\tconst result = Money.create(Number.MIN_SAFE_INTEGER - 1);\n\t\t\texpect(result.isFail()).toBeTruthy();\n\t\t});\n\n\t\tit('should throws', () => {\n\t\t\tconst result = () => Money.init(Number.MAX_SAFE_INTEGER + 1);\n\t\t\texpect(result).toThrowError();\n\t\t});\n\n\t\tit('should throws', () => {\n\t\t\tconst result = () => Money.init(Number.MIN_SAFE_INTEGER - 1);\n\t\t\texpect(result).toThrowError();\n\t\t});\n\n\t\tit('should return 0', () => {\n\t\t\tconst amount = Money.zero();\n\t\t\texpect(amount.value()).toBe(0);\n\t\t});\n\n\t\tit('should return 10', () => {\n\t\t\tconst amount = Money.ten();\n\t\t\texpect(amount.value()).toBe(10);\n\t\t});\n\n\t\tit('should return 100', () => {\n\t\t\tconst amount = Money.one_hundred();\n\t\t\texpect(amount.value()).toBe(100);\n\t\t});\n\n\t\tit('should return 1000', () => {\n\t\t\tconst amount = Money.one_thousand();\n\t\t\texpect(amount.value()).toBe(1000);\n\t\t});\n\t});\n\n\tdescribe('isValid', () => {\n\t\tit('should return false', () => {\n\t\t\tconst isValid = Money.isValid(Number.MIN_SAFE_INTEGER - 1);\n\t\t\texpect(isValid).toBeFalsy();\n\t\t});\n\n\t\tit('should return false', () => {\n\t\t\tconst isValid = Money.isValid(Number.MAX_SAFE_INTEGER + 1);\n\t\t\texpect(isValid).toBeFalsy();\n\t\t});\n\n\t\tit('should return true', () => {\n\t\t\tconst isValid = Money.isValid(1000);\n\t\t\texpect(isValid).toBeTruthy();\n\t\t});\n\n\t\tit('should return true', () => {\n\t\t\tconst isValid = Money.isValid(-1000);\n\t\t\texpect(isValid).toBeTruthy();\n\t\t});\n\t});\n\n\tdescribe('coin', () => {\n\t\tit('should transform to coin', () => {\n\t\t\tconst total = Money.one_hundred();\n\t\t\texpect(total.coin('BRL', 'pt-BR')).toBe('R$ 100,00');\n\t\t\texpect(total.coin('USD', 'pt-BR')).toBe('US$ 100,00');\n\t\t\texpect(total.coin('USD', 'en-US')).toBe('$100.00');\n\t\t\texpect(total.coin('BRL', 'en-US')).toBe('R$100.00');\n\t\t});\n\n\t\tit('should get default', () => {\n\t\t\tconst coin = Money.one().coin();\n\t\t\texpect(coin).toBe('R$ 1,00');\n\t\t});\n\t});\n\n\tdescribe('sum', () => {\n\t\tit('should sum with success', () => {\n\t\t\tconst total = Money.one_thousand();\n\t\t\tconst amount = total.sum(Money.ten());\n\t\t\texpect(amount.value()).toBe(1010);\n\t\t});\n\n\t\tit('should sum with success', () => {\n\t\t\tconst total = Money.one_thousand();\n\t\t\tconst amount = total.sum(10);\n\t\t\texpect(amount.value()).toBe(1010);\n\t\t});\n\n\t\tit('should sum with success', () => {\n\t\t\tconst total = Money.one_thousand();\n\t\t\tconst amount = total.sum(-10);\n\t\t\texpect(amount.value()).toBe(990);\n\t\t});\n\t});\n\n\tdescribe('subtract', () => {\n\t\tit('should subtract with success', () => {\n\t\t\tconst total = Money.one_thousand();\n\t\t\tconst amount = total.subtract(10);\n\t\t\texpect(amount.value()).toBe(990);\n\t\t});\n\n\t\tit('should subtract with success', () => {\n\t\t\tconst total = Money.one_thousand();\n\t\t\tconst amount = total.subtract(Money.ten());\n\t\t\texpect(amount.value()).toBe(990);\n\t\t});\n\n\t\tit('should subtract with success', () => {\n\t\t\tconst total = Money.one_thousand();\n\t\t\tconst amount = total.subtract(-10);\n\t\t\texpect(amount.value()).toBe(1010);\n\t\t});\n\n\t\tit('should subtract with success', () => {\n\t\t\tconst total = Money.subtract(1, 10);\n\t\t\texpect(total).toBe(-9);\n\t\t\texpect(Money.subtract(Money.one(), Money.ten())).toBe(-9);\n\t\t});\n\t});\n\n\tdescribe('multiply', () => {\n\t\tit('should return 100', () => {\n\t\t\tconst ten = Money.ten();\n\t\t\tconst total = ten.multiply(Money.ten());\n\t\t\texpect(total.value()).toBe(100);\n\t\t});\n\n\t\tit('should return 100', () => {\n\t\t\tconst ten = Money.ten();\n\t\t\tconst total = ten.multiply(10);\n\t\t\texpect(total.value()).toBe(100);\n\t\t});\n\t});\n\n\tdescribe('divide', () => {\n\t\tit('should return 10', () => {\n\t\t\tconst amount = Money.one_hundred();\n\t\t\tconst total = amount.divide(10);\n\t\t\texpect(total.value()).toBe(10);\n\t\t});\n\n\t\tit('should return 10', () => {\n\t\t\tconst amount = Money.one_hundred();\n\t\t\tconst total = amount.divide(Money.ten());\n\t\t\texpect(total.value()).toBe(10);\n\t\t});\n\t});\n\n\tdescribe('addPercent', () => {\n\t\tit('should add percent with success', () => {\n\t\t\tconst money = Money.init(200);\n\t\t\texpect(money.addPercent(20).value()).toBe(240);\n\t\t});\n\n\t\tit('should discount percent with success', () => {\n\t\t\tconst money = Money.init(200);\n\t\t\texpect(money.addPercent(-20).value()).toBe(160);\n\t\t});\n\t});\n\n\tdescribe('percent', () => {\n\t\tit('should return 10', () => {\n\t\t\tconst amount = Money.one_hundred();\n\t\t\tconst total = amount.percent(10);\n\t\t\texpect(total.value()).toBe(10);\n\t\t});\n\n\t\tit('should return -50', () => {\n\t\t\tconst amount = Money.one_hundred().multiply(5);\n\t\t\tconst total = amount.percent(-10);\n\t\t\texpect(total.value()).toBe(-50);\n\t\t});\n\t});\n\n\tdescribe('isGt', () => {\n\t\tit('should return true', () => {\n\t\t\tconst a = Money.one_hundred();\n\t\t\tconst b = Money.ten();\n\t\t\texpect(a.isGt(b)).toBeTruthy();\n\t\t\texpect(a.isGt(10)).toBeTruthy();\n\t\t});\n\n\t\tit('should return false', () => {\n\t\t\tconst a = Money.one_hundred();\n\t\t\tconst b = Money.ten();\n\t\t\texpect(b.isGt(a)).toBeFalsy();\n\t\t\texpect(Money.ten().isGt(Money.ten())).toBeFalsy();\n\t\t\texpect(Money.ten().isGt(10)).toBeFalsy();\n\t\t});\n\t});\n\n\tdescribe('isGte', () => {\n\t\tit('should return true', () => {\n\t\t\tconst a = Money.one_hundred();\n\t\t\tconst b = Money.ten();\n\t\t\texpect(a.isGte(b)).toBeTruthy();\n\t\t\texpect(Money.one_hundred().isGte(Money.ten())).toBeTruthy();\n\t\t\texpect(Money.ten().isGte(10)).toBeTruthy();\n\t\t});\n\n\t\tit('should return false', () => {\n\t\t\tconst a = Money.one_hundred();\n\t\t\tconst b = Money.ten();\n\t\t\texpect(b.isGte(a)).toBeFalsy();\n\t\t\texpect(b.isGte(11)).toBeFalsy();\n\t\t});\n\t});\n\n\tdescribe('isLt', () => {\n\t\tit('should return true', () => {\n\t\t\tconst a = Money.ten();\n\t\t\tconst b = Money.one_hundred();\n\t\t\texpect(a.isLt(b)).toBeTruthy();\n\t\t\texpect(a.isLt(11)).toBeTruthy();\n\t\t});\n\n\t\tit('should return false', () => {\n\t\t\tconst a = Money.ten();\n\t\t\tconst b = Money.one_hundred();\n\t\t\texpect(b.isLt(a)).toBeFalsy();\n\t\t\texpect(a.isLt(5)).toBeFalsy();\n\t\t});\n\t});\n\n\tdescribe('isLte', () => {\n\t\tit('should return true', () => {\n\t\t\tconst a = Money.ten();\n\t\t\tconst b = Money.ten();\n\t\t\texpect(a.isLte(b)).toBeTruthy();\n\t\t\texpect(a.isLte(b.sum(1))).toBeTruthy();\n\t\t\texpect(a.isLte(10)).toBeTruthy();\n\t\t\texpect(a.isLte(11)).toBeTruthy();\n\t\t});\n\n\t\tit('should return false', () => {\n\t\t\tconst a = Money.ten();\n\t\t\tconst b = Money.one_hundred();\n\t\t\texpect(b.isLte(a)).toBeFalsy();\n\t\t\texpect(a.isLte(5)).toBeFalsy();\n\t\t});\n\t});\n\n\tdescribe('isEq', () => {\n\t\tit('should return true', () => {\n\t\t\tconst a = Money.ten();\n\t\t\tconst b = Money.ten();\n\t\t\texpect(a.isEq(b)).toBeTruthy();\n\t\t\texpect(a.isEq(10)).toBeTruthy();\n\t\t});\n\n\t\tit('should return false', () => {\n\t\t\tconst a = Money.ten();\n\t\t\tconst b = Money.one_hundred();\n\t\t\texpect(b.isEq(a)).toBeFalsy();\n\t\t\texpect(a.isEq(5)).toBeFalsy();\n\t\t});\n\t});\n\n\tdescribe('isPos', () => {\n\t\tit('should return true', () => {\n\t\t\tconst money = Money.ten();\n\t\t\texpect(money.isPos()).toBeTruthy();\n\t\t});\n\n\t\tit('should return false', () => {\n\t\t\tconst money = Money.ten().makeNeg();\n\t\t\texpect(money.isPos()).toBeFalsy();\n\t\t});\n\t});\n\n\tdescribe('isNeg', () => {\n\t\tit('should return true', () => {\n\t\t\tconst money = Money.ten().makeNeg();\n\t\t\texpect(money.isNeg()).toBeTruthy();\n\t\t});\n\n\t\tit('should return false', () => {\n\t\t\tconst money = Money.ten();\n\t\t\texpect(money.isNeg()).toBeFalsy();\n\t\t});\n\t});\n\n\tdescribe('isZero', () => {\n\t\tit('should return true', () => {\n\t\t\tconst money = Money.zero();\n\t\t\texpect(money.isZero()).toBeTruthy();\n\t\t});\n\n\t\tit('should return false', () => {\n\t\t\tconst money = Money.ten();\n\t\t\texpect(money.isZero()).toBeFalsy();\n\t\t});\n\t});\n\n\tdescribe('makePos', () => {\n\t\tit('should return true', () => {\n\t\t\tconst money = Money.init(-10).makePos();\n\t\t\texpect(money.isPos()).toBeTruthy();\n\t\t});\n\n\t\tit('should return false', () => {\n\t\t\tconst money = Money.init(10).makeNeg();\n\t\t\texpect(money.isPos()).toBeFalsy();\n\t\t});\n\n\t\tit('should continue positive', () => {\n\t\t\tconst money = Money.init(10).makePos();\n\t\t\texpect(money.isPos()).toBeTruthy();\n\t\t});\n\t});\n\n\tdescribe('makeNeg', () => {\n\t\tit('should return true', () => {\n\t\t\tconst money = Money.init(10).makeNeg();\n\t\t\texpect(money.isNeg()).toBeTruthy();\n\t\t});\n\n\t\tit('should return false', () => {\n\t\t\tconst money = Money.init(-10).makePos();\n\t\t\texpect(money.isNeg()).toBeFalsy();\n\t\t});\n\n\t\tit('should return true', () => {\n\t\t\tconst money = Money.init(-10).makeNeg();\n\t\t\texpect(money.isNeg()).toBeTruthy();\n\t\t});\n\t});\n\n\tdescribe('sum', () => {\n\t\tit('should return 200', () => {\n\t\t\tconst amount = Money.one_hundred();\n\t\t\tconst total = amount.sum(amount);\n\t\t\texpect(total.value()).toBe(200);\n\t\t\texpect(amount.sum(100).value()).toBe(200);\n\t\t\texpect(Money.sum(amount, amount)).toBe(200);\n\t\t\texpect(Money.sum(amount, amount)).toBe(200);\n\t\t});\n\n\t\tit('should return 0', () => {\n\t\t\tconst amount = Money.one_hundred();\n\t\t\tconst total = amount.sum(amount.makeNeg());\n\t\t\texpect(total.value()).toBe(0);\n\t\t\texpect(amount.sum(-100).value()).toBe(0);\n\t\t\texpect(Money.sum(-100, 100)).toBe(0);\n\t\t});\n\t});\n\n\tdescribe('divide', () => {\n\t\tit('should return 50', () => {\n\t\t\tconst amount = Money.one_hundred();\n\t\t\tconst total = amount.divide(2);\n\t\t\texpect(total.value()).toBe(50);\n\t\t\texpect(amount.divide(2).value()).toBe(50);\n\t\t\texpect(Money.divide(amount, 2)).toBe(50);\n\t\t});\n\n\t\tit('should return 1', () => {\n\t\t\tconst amount = Money.one_hundred();\n\t\t\tconst total = amount.divide(amount);\n\t\t\texpect(total.value()).toBe(1);\n\t\t\texpect(amount.divide(100).value()).toBe(1);\n\t\t\texpect(Money.divide(amount, amount)).toBe(1)\n\t\t});\n\t});\n\n\tdescribe('multiply', () => {\n\t\tit('should return 81', () => {\n\t\t\tconst amount = Money.ten().subtract(1);\n\t\t\texpect(amount.multiply(9).value()).toBe(81);\n\t\t\texpect(amount.multiply(amount).value()).toBe(81);\n\t\t\texpect(Money.multiply(9, 9)).toBe(81);\n\t\t});\n\n\t\tit('should return 81', () => {\n\t\t\tconst amount = Money.ten().subtract(1).makeNeg();\n\t\t\texpect(amount.multiply(9).value()).toBe(-81);\n\t\t\texpect(amount.multiply(amount).value()).toBe(81);\n\t\t\texpect(Money.multiply(amount, amount)).toBe(81);\n\t\t});\n\t});\n\n\tdescribe('subtract', () => {\n\t\tit('should return 50', () => {\n\t\t\tconst amount = Money.one_hundred();\n\t\t\tconst total = amount.subtract(amount.divide(2));\n\t\t\texpect(total.value()).toBe(50);\n\t\t\texpect(amount.subtract(50).value()).toBe(50);\n\t\t\texpect(Money.subtract(amount, 50)).toBe(50);\n\t\t});\n\t});\n\n\tdescribe('floor', () => {\n\t\tit('should return 101', () => {\n\t\t\tconst amount = Money.one_hundred().sum(1.5);\n\t\t\texpect(amount.floor().value()).toBe(101);\n\t\t});\n\t});\n\n\tdescribe('ceil', () => {\n\t\tit('should return 102', () => {\n\t\t\tconst amount = Money.one_hundred().sum(1.5);\n\t\t\texpect(amount.ceil().value()).toBe(102);\n\t\t});\n\t});\n\n\tdescribe('closure', () => {\n\t\tit('should calc', () => {\n\t\t\tconst closure = Money.closure(100);\n\t\t\texpect(closure.sum(20)).toBe(120);\n\t\t\texpect(closure.subtract(20)).toBe(80);\n\t\t\texpect(closure.divide(2)).toBe(50);\n\t\t\texpect(closure.multiply(2)).toBe(200);\n\t\t});\n\t});\n\n\tdescribe('calcInterest', () => {\n\t\tit('should calculate interest', () => {\n\t\t\tconst total = Money.one_hundred();\n\t\t\tconst amount = total.interest(1.5, 36);\n\t\t\texpect(amount.value()).toBe(54);\n\t\t});\n\n\t\tit('should throw', () => {\n\t\t\tconst total = Money.one_hundred();\n\t\t\tconst calc = (rate: number, period: number) => total.interest(rate, period);\n\t\t\texpect(() => calc(-1, 36)).toThrowError();\n\t\t\texpect(() => calc(1, -36)).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('calcCompoundInterest', () => {\n\t\tit('should calculate interest', () => {\n\t\t\tconst total = Money.one_hundred();\n\t\t\tconst amount = total.compoundInterest(1.5, 36);\n\t\t\texpect(amount.value()).toBe(70.913);\n\t\t});\n\n\t\tit('should throw', () => {\n\t\t\tconst total = Money.one_hundred();\n\t\t\tconst calc = (rate: number, period: number) => total.compoundInterest(rate, period);\n\t\t\texpect(() => calc(-1, 36)).toThrowError();\n\t\t\texpect(() => calc(1, -36)).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('max', () => {\n\t\tit('should return 1000', () => {\n\t\t\tconst arr = [Money.ten(), Money.one_hundred(), Money.zero(), Money.one_thousand()];\n\t\t\texpect(Money.max(arr).value()).toBe(1000);\n\t\t});\n\t});\n\n\tdescribe('min', () => {\n\t\tit('should return 0', () => {\n\t\t\tconst arr = [Money.ten(), Money.one_hundred(), Money.zero(), Money.one_thousand()];\n\t\t\texpect(Money.min(arr).value()).toBe(0);\n\t\t});\n\t});\n\n\tdescribe('random', () => {\n\t\tit('should return value between 100 and 1000', () => {\n\t\t\tconst random = Money.random(100, 1000);\n\t\t\texpect(random.isGte(100) && random.isLte(1000)).toBeTruthy();\n\t\t});\n\n\t\tit('should return 0', () => {\n\t\t\tconst random = Money.random(10, 10);\n\t\t\texpect(random.value()).toBe(0);\n\t\t});\n\t});\n\n\tdescribe('average', () => {\n\t\tit('should', () => {\n\t\t\tconst cl = Money.closure(100);\n\t\t\tconst a = Money.init(cl.sum(20));\n\t\t\tconst b = Money.init(cl.sum(10));\n\t\t\tconst c = Money.init(cl.subtract(5));\n\t\t\texpect(Money.average([a, b, c]).value()).toBe(108.333);\n\t\t});\n\t});\n\n\tdescribe('convertTo', () => {\n\t\tit('should convert to real', () => {\n\t\t\tconst dollar = Money.one_hundred();\n\t\t\tconst reals = dollar.convertTo(5);\n\t\t\texpect(reals.value()).toBe(500);\n\t\t});\n\n\t\tit('should convert to real', () => {\n\t\t\tconst dollar = Money.one_hundred();\n\t\t\tconst reals = dollar.convertTo(Money.one().multiply(5));\n\t\t\texpect(reals.value()).toBe(500);\n\t\t});\n\n\t\tit('should convert to dollars', () => {\n\t\t\tconst reals = Money.one_hundred();\n\t\t\tconst dollars = reals.convertTo(0.2);\n\t\t\texpect(dollars.value()).toBe(20);\n\t\t});\n\n\t\tit('should convert to dollars', () => {\n\t\t\tconst reals = Money.one_hundred();\n\t\t\tconst dollars = reals.convertTo(Money.init(0.2));\n\t\t\texpect(dollars.value()).toBe(20);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/money/index.ts",
    "content": "import { Result, ValueObject } from 'rich-domain';\n\nexport enum Currencies {\n\tUSD = 'USD', // Dólar Americano\n\tEUR = 'EUR', // Euro\n\tJPY = 'JPY', // Iene Japonês\n\tGBP = 'GBP', // Libra Esterlina\n\tAUD = 'AUD', // Dólar Australiano\n\tCAD = 'CAD', // Dólar Canadense\n\tCHF = 'CHF', // Franco Suíço\n\tCNY = 'CNY', // Renminbi Chinês\n\tSEK = 'SEK', // Coroa Sueca\n\tNZD = 'NZD', // Dólar da Nova Zelândia\n\tKRW = 'KRW', // Won Sul-Coreano\n\tSGD = 'SGD', // Dólar de Singapura\n\tNOK = 'NOK', // Coroa Norueguesa\n\tMXN = 'MXN', // Peso Mexicano\n\tINR = 'INR', // Rúpia Indiana\n\tBRL = 'BRL', // Real Brasileiro\n\tRUB = 'RUB', // Rublo Russo\n\tZAR = 'ZAR', // Rand Sul-Africano\n\tTRY = 'TRY', // Lira Turca\n\tHKD = 'HKD', // Dólar de Hong Kong\n}\n\nexport enum Locales {\n\t'en-US' = 'en-US', // Inglês (Estados Unidos)\n\t'en-GB' = 'en-GB', // Inglês (Reino Unido)\n\t'en-CA' = 'en-CA', // Inglês (Canadá)\n\t'en-AU' = 'en-AU', // Inglês (Austrália)\n\t'en-NZ' = 'en-NZ', // Inglês (Nova Zelândia)\n\t'fr-FR' = 'fr-FR', // Francês (França)\n\t'fr-CA' = 'fr-CA', // Francês (Canadá)\n\t'es-ES' = 'es-ES', // Espanhol (Espanha)\n\t'es-MX' = 'es-MX', // Espanhol (México)\n\t'pt-BR' = 'pt-BR', // Português (Brasil)\n\t'pt-PT' = 'pt-PT', // Português (Portugal)\n\t'de-DE' = 'de-DE', // Alemão (Alemanha)\n\t'it-IT' = 'it-IT', // Italiano (Itália)\n\t'ja-JP' = 'ja-JP', // Japonês (Japão)\n\t'ko-KR' = 'ko-KR', // Coreano (Coreia do Sul)\n\t'zh-CN' = 'zh-CN', // Chinês (China)\n\t'zh-TW' = 'zh-TW', // Chinês (Taiwan)\n\t'ru-RU' = 'ru-RU', // Russo (Rússia)\n}\n\ntype Locale = keyof typeof Locales;\ntype Currency = keyof typeof Currencies;\n\nclass Money extends ValueObject<number> {\n\tprotected static readonly MESSAGE: string = 'Invalid money value';\n\n\tprivate constructor(prop: number) {\n\t\tsuper(prop);\n\t}\n\n\tvalue(): number {\n\t\treturn this.props;\n\t}\n\n\t/**\n\t * @description Validate if provided value is a valid money value.\n\t * @param value The value to validate.\n\t * @returns A boolean indicating whether the provided value is a valid money value.\n\t */\n\tpublic static isValid(value: number): boolean {\n\t\treturn this.isValidProps(value);\n\t}\n\n\t/**\n\t * @description Validate if provided value is a valid money value.\n\t * @param value The value to validate.\n\t * @returns A boolean indicating whether the provided value is a valid money value.\n\t */\n\tpublic static isValidProps(value: number): boolean {\n\t\treturn this.validator.number(value).isSafeInteger();\n\t}\n\n\t/**\n\t * @description Formats the money value as currency according to the specified currency and locale.\n\t * @param currency The currency code or enum representing the currency. Defaults to Brazilian Real (BRL).\n\t * @param locale The locale code or enum representing the locale. Defaults to Brazilian Portuguese (pt-BR).\n\t * @returns A string representing the money value formatted as currency.\n\t */\n\tcoin(currency?: Currency | Currencies, locale?: Locale | Locales): string {\n\t\treturn Intl.NumberFormat(locale ?? Locales['pt-BR'], {\n\t\t\tcurrency: currency ?? Currencies.BRL,\n\t\t\tstyle: 'currency'\n\t\t}).format(this.value());\n\t}\n\n\t/**\n\t * @description Performs addition with another Money object or a numeric value.\n\t * @param money The Money object or numeric value to add.\n\t * @returns A new Money object representing the result of the addition.\n\t */\n\tsum(money: Money | number): Money {\n\t\tconst current = this.value();\n\t\tconst target = money instanceof Money ? money.value() : money;\n\t\tconst total = this.util.number(current).sum(target, { fractionDigits: 3 });\n\t\treturn new Money(total);\n\t}\n\n\t/**\n\t * @description Performs subtraction with another Money object or a numeric value.\n\t * @param money The Money object or numeric value to subtract.\n\t * @returns A new Money object representing the result of the subtraction.\n\t */\n\tsubtract(money: Money | number): Money {\n\t\tconst current = this.value();\n\t\tconst target = money instanceof Money ? money.value() : money;\n\t\tconst total = this.util.number(current).subtract(target, { fractionDigits: 3 });\n\t\treturn new Money(total);\n\t}\n\n\t/**\n\t * @description Performs multiplication with another Money object or a numeric value.\n\t * @param money The Money object or numeric value to multiply by.\n\t * @returns A new Money object representing the result of the multiplication.\n\t */\n\tmultiply(money: Money | number): Money {\n\t\tconst current = this.value();\n\t\tconst target = money instanceof Money ? money.value() : money;\n\t\tconst total = this.util.number(current).multiplyBy(target, { fractionDigits: 3 });\n\t\treturn new Money(total);\n\t}\n\n\t/**\n\t * @description Performs division with another Money object or a numeric value.\n\t * @param money The Money object or numeric value to divide by.\n\t * @returns A new Money object representing the result of the division.\n\t */\n\tdivide(money: Money | number): Money {\n\t\tconst current = this.value();\n\t\tconst target = money instanceof Money ? money.value() : money;\n\t\tconst total = this.util.number(current).divideBy(target, { fractionDigits: 3 });\n\t\treturn new Money(total);\n\t}\n\n\t/**\n\t * @description Adds a percentage to the money value.\n\t * @param percent The percentage to add.\n\t * @returns A new Money object representing the result of adding the percentage.\n\t */\n\taddPercent(percent: number): Money {\n\t\tconst current = this.value();\n\t\tconst multiply = this.util.number(current).multiplyBy(percent);\n\t\tconst percents = this.util.number(multiply).divideBy(100);\n\t\tconst total = this.util.number(percents).sum(current, { fractionDigits: 3 });\n\t\treturn new Money(total);\n\t}\n\n\t/**\n\t * @description Calculates the percentage of the money value.\n\t * @param percent The percentage to calculate.\n\t * @returns A new Money object representing the calculated percentage.\n\t */\n\tpercent(percent: number): Money {\n\t\tconst current = this.value();\n\t\tconst multiply = this.util.number(current).multiplyBy(percent);\n\t\tconst percents = this.util.number(multiply).divideBy(100, { fractionDigits: 3 });\n\t\treturn new Money(percents);\n\t}\n\n\t/**\n\t * @description Checks if the money value is greater than the provided value.\n\t * @param value The value to compare.\n\t * @returns A boolean indicating whether the money value is greater than the provided value.\n\t */\n\tisGt(value: Money | number): boolean {\n\t\tconst target = value instanceof Money ? value.value() : value;\n\t\tconst current = this.value();\n\t\treturn this.validator.number(current).isGreaterThan(target);\n\t}\n\n\t/**\n\t * @description Checks if the money value is greater than or equal to the provided value.\n\t * @param value The value to compare.\n\t * @returns A boolean indicating whether the money value is greater than or equal to the provided value.\n\t */\n\tisGte(value: Money | number): boolean {\n\t\tconst target = value instanceof Money ? value.value() : value;\n\t\tconst current = this.value();\n\t\treturn this.validator.number(current).isGreaterOrEqualTo(target);\n\t}\n\n\t/**\n\t * @description Checks if the money value is less than the provided value.\n\t * @param value The value to compare.\n\t * @returns A boolean indicating whether the money value is less than the provided value.\n\t */\n\tisLt(value: Money | number): boolean {\n\t\tconst target = value instanceof Money ? value.value() : value;\n\t\tconst current = this.value();\n\t\treturn this.validator.number(current).isLessThan(target);\n\t}\n\n\t/**\n\t * @description Checks if the money value is less than or equal to the provided value.\n\t * @param value The value to compare.\n\t * @returns A boolean indicating whether the money value is less than or equal to the provided value.\n\t */\n\tisLte(value: Money | number): boolean {\n\t\tconst target = value instanceof Money ? value.value() : value;\n\t\tconst current = this.value();\n\t\treturn this.validator.number(current).isLessOrEqualTo(target);\n\t}\n\n\t/**\n\t * @description Checks if the money value is equal to the provided value.\n\t * @param value The value to compare.\n\t * @returns A boolean indicating whether the money value is equal to the provided value.\n\t */\n\tisEq(value: Money | number): boolean {\n\t\tconst target = value instanceof Money ? value.value() : value;\n\t\tconst current = this.value();\n\t\treturn this.validator.number(current).isEqualTo(target);\n\t}\n\n\t/**\n\t * @description Checks if the money value is positive.\n\t * @returns A boolean indicating whether the money value is positive.\n\t */\n\tisPos(): boolean {\n\t\treturn this.validator.number(this.props).isPositive();\n\t}\n\n\t/**\n\t * @description Checks if the money value is negative.\n\t * @returns A boolean indicating whether the money value is negative.\n\t */\n\tisNeg(): boolean {\n\t\treturn this.validator.number(this.props).isNegative();\n\t}\n\n\t/**\n\t * @description Checks if the money value is zero.\n\t * @returns A boolean indicating whether the money value is zero.\n\t */\n\tisZero(): boolean {\n\t\treturn this.validator.number(this.props).isEqualTo(0);\n\t}\n\n\t/**\n\t * @description Makes the money value positive.\n\t * @returns A new Money object with a positive value.\n\t */\n\tmakePos(): Money {\n\t\tconst value = this.value();\n\t\tif (this.validator.number(value).isNegative()) {\n\t\t\treturn new Money(value * -1);\n\t\t}\n\t\treturn new Money(value);\n\t}\n\n\t/**\n\t * @description Makes the money value negative.\n\t * @returns A new Money object with a negative value.\n\t */\n\tmakeNeg(): Money {\n\t\tconst value = this.value();\n\t\tif (this.validator.number(value).isPositive()) {\n\t\t\treturn new Money(value * -1);\n\t\t}\n\t\treturn new Money(value);\n\t}\n\n\t/**\n\t * @description Creates a new Money object with a value of zero.\n\t * @returns A new Money object initialized with a value of zero.\n\t */\n\tpublic static zero(): Money {\n\t\treturn new Money(0);\n\t}\n\n\t/**\n\t * @description Creates a new Money object with a value of one.\n\t * @returns A new Money object initialized with a value of one.\n\t */\n\tpublic static one(): Money {\n\t\treturn new Money(1);\n\t}\n\n\t/**\n\t * @description Creates a new Money object with a value of ten.\n\t * @returns A new Money object initialized with a value of ten.\n\t */\n\tpublic static ten(): Money {\n\t\treturn new Money(10);\n\t}\n\n\t/**\n\t * @description Creates a new Money object with a value of one hundred.\n\t * @returns A new Money object initialized with a value of one hundred.\n\t */\n\tpublic static one_hundred(): Money {\n\t\treturn new Money(100);\n\t}\n\n\t/**\n\t * @description Creates a new Money object with a value of one thousand.\n\t * @returns A new Money object initialized with a value of one thousand.\n\t */\n\tpublic static one_thousand(): Money {\n\t\treturn new Money(1000);\n\t}\n\n\t/**\n\t * @description Performs summation of two values.\n\t * @param a The first value to sum, which can be a number or a Money object.\n\t * @param b The second value to sum, which can be a number or a Money object.\n\t * @returns The result of the summation as a number.\n\t */\n\tpublic static sum(a: number | Money, b: number | Money): number {\n\t\tconst valueA = a instanceof Money ? a.value() : a;\n\t\tconst valueB = b instanceof Money ? b.value() : b;\n\t\treturn this.util.number(valueA).sum(valueB, { fractionDigits: 3 });\n\t}\n\n\t/**\n\t * @description Performs division of two values.\n\t * @param a The numerator value, which can be a number or a Money object.\n\t * @param b The denominator value, which can be a number or a Money object.\n\t * @returns The result of the division as a number.\n\t */\n\tpublic static divide(a: number | Money, b: number | Money): number {\n\t\tconst valueA = a instanceof Money ? a.value() : a;\n\t\tconst valueB = b instanceof Money ? b.value() : b;\n\t\treturn this.util.number(valueA).divideBy(valueB, { fractionDigits: 3 });\n\t}\n\n\t/**\n\t * @description Performs multiplication of two values.\n\t * @param a The first value to multiply, which can be a number or a Money object.\n\t * @param b The second value to multiply, which can be a number or a Money object.\n\t * @returns The result of the multiplication as a number.\n\t */\n\tpublic static multiply(a: number | Money, b: number | Money): number {\n\t\tconst valueA = a instanceof Money ? a.value() : a;\n\t\tconst valueB = b instanceof Money ? b.value() : b;\n\t\treturn this.util.number(valueA).multiplyBy(valueB, { fractionDigits: 3 });\n\t}\n\n\t/**\n\t * @description Performs subtraction of two values.\n\t * @param a The minuend value, which can be a number or a Money object.\n\t * @param b The subtrahend value, which can be a number or a Money object.\n\t * @returns The result of the subtraction as a number.\n\t */\n\tpublic static subtract(a: number | Money, b: number | Money): number {\n\t\tconst valueA = a instanceof Money ? a.value() : a;\n\t\tconst valueB = b instanceof Money ? b.value() : b;\n\t\treturn this.util.number(valueA).subtract(valueB, { fractionDigits: 3 });\n\t}\n\n\t/**\n\t * @description Rounds down the money value to the nearest integer.\n\t * @returns A new Money object representing the rounded-down value.\n\t */\n\tfloor(): Money {\n\t\tconst ceil = Math.floor(this.props);\n\t\treturn new Money(ceil);\n\t};\n\n\t/**\n\t * @description Rounds up the money value to the nearest integer.\n\t * @returns A new Money object representing the rounded-up value.\n\t */\n\tceil(): Money {\n\t\tconst ceil = Math.ceil(this.props);\n\t\treturn new Money(ceil);\n\t}\n\n\t/**\n\t * @description Generates a closure that performs arithmetic operations with a predefined initial value.\n\t * @param initial The initial value for arithmetic operations.\n\t * @returns An object containing functions for performing `summation`, `division`, `multiplication`, and `subtraction` with the initial value.\n\t */\n\tpublic static closure(initial: number) {\n\t\treturn {\n\t\t\tsum: (value: number): number => Money.sum(initial, value),\n\t\t\tdivide: (value: number): number => Money.divide(initial, value),\n\t\t\tmultiply: (value: number): number => Money.multiply(initial, value),\n\t\t\tsubtract: (value: number): number => Money.subtract(initial, value)\n\t\t};\n\t}\n\n\t/**\n\t * @description Calculates the simple interest based on the provided rate and periods.\n\t * @param rate The interest rate as a percentage.\n\t * @param periods The number of periods over which the interest is applied.\n\t * @returns A new Money object representing the calculated interest.\n\t * @throws {Error} If either the rate or periods is negative.\n\t */\n\tinterest(rate: number, periods: number): Money {\n\t\tif (\n\t\t\tthis.validator.number(rate).isNegative() ||\n\t\t\tthis.validator.number(periods).isNegative()\n\t\t) {\n\t\t\tthrow new Error('period and rate must be greater than zero');\n\t\t}\n\t\tconst rateBy100 = this.util.number(rate).divideBy(100);\n\t\tconst amount = this.util.number(this.props).multiplyBy(rateBy100);\n\t\tconst interest = this.util.number(amount).multiplyBy(periods);\n\t\treturn new Money(interest);\n\t}\n\n\t/**\n\t * @description Finds the maximum value among the provided Money objects.\n\t * @param values An array of Money objects.\n\t * @returns A new Money object representing the maximum value found.\n\t */\n\tpublic static max(values: Money[]): Money {\n\t\tconst arr = values.map((item): number => item.value());\n\t\tconst max = Math.max(...arr);\n\t\treturn new Money(max);\n\t}\n\n\t/**\n\t * @description Finds the minimum value among the provided Money objects.\n\t * @param values An array of Money objects.\n\t * @returns A new Money object representing the minimum value found.\n\t */\n\tpublic static min(values: Money[]): Money {\n\t\tconst arr = values.map((item): number => item.value());\n\t\tconst max = Math.min(...arr);\n\t\treturn new Money(max);\n\t}\n\n\t/**\n\t * @description Calculates the compound interest based on the provided rate and periods.\n\t * @param rate The interest rate as a percentage.\n\t * @param periods The number of periods over which the interest is applied.\n\t * @returns A new Money object representing the calculated compound interest.\n\t * @throws {Error} If either the rate or periods is negative.\n\t */\n\tcompoundInterest(rate: number, periods: number): Money {\n\t\tif (\n\t\t\tthis.validator.number(rate).isNegative() ||\n\t\t\tthis.validator.number(periods).isNegative()\n\t\t) {\n\t\t\tthrow new Error('period and rate must be greater than zero');\n\t\t};\n\t\tconst rateBy100 = this.util.number(rate).divideBy(100);\n\t\tconst base = this.util.number(rateBy100).sum(1);\n\t\tconst pow = Math.pow(base, periods);\n\t\tconst amount = this.util.number(this.props).multiplyBy(pow);\n\t\tconst compoundInterest = this.util.number(amount).subtract(this.props, { fractionDigits: 3 });\n\t\treturn new Money(compoundInterest);\n\t}\n\n\t/**\n\t * @description Generates a random Money value within the specified range.\n\t * @param min The minimum value of the range.\n\t * @param max The maximum value of the range.\n\t * @returns A new Money object representing a random value within the specified range.\n\t */\n\tpublic static random(min: number, max: number): Money {\n\t\tif (min >= max) return Money.zero();\n\t\tconst randomValue = Math.random() * (max - min) + min;\n\t\tconst roundedValue = Math.round(randomValue * 100) / 100;\n\t\treturn new Money(roundedValue);\n\t}\n\n\t/**\n\t * @description Calculates the average value among the provided Money objects.\n\t * @param values An array of Money objects.\n\t * @returns A new Money object representing the average value of the Money objects.\n\t */\n\tpublic static average(values: Money[]): Money {\n\t\tconst items = values.length;\n\t\tconst calc = (prev: Money, current: Money): Money => current.sum(prev);\n\t\tconst total = values.reduce(calc, Money.zero());\n\t\treturn total.divide(items);\n\t}\n\n\t/**\n\t * @description Converts the current Money value to another currency using the provided exchange rate.\n\t * @param exchangeRate The exchange rate, which can be a Money object representing the rate or a number.\n\t * @returns A new Money object representing the converted value.\n\t */\n\tconvertTo(exchangeRate: Money | number): Money {\n\t\tconst current = this.value();\n\t\tconst rate = exchangeRate instanceof Money ? exchangeRate.value() : exchangeRate;\n\t\tconst value = this.util.number(current).multiplyBy(rate, { fractionDigits: 3 });\n\t\treturn new Money(value);\n\t}\n\n\t/**\n\t * @description Initializes a Money object with the provided value.\n\t * @param value The initial value for the Money object.\n\t * @returns A new Money object initialized with the provided value.\n\t * @throws {Error} If the provided value is invalid.\n\t */\n\tpublic static init(value: number): Money {\n\t\tconst isValidValue = Money.isValidProps(value);\n\t\tif (!isValidValue) throw new Error(Money.MESSAGE);\n\t\treturn new Money(value);\n\t}\n\n\t/**\n\t * @description Creates a Result object containing a Money object initialized with the provided value.\n\t * @param value The initial value for the Money object.\n\t * @returns A Result object containing either a Money object or an error message.\n\t */\n\tpublic static create(value: number): Result<Money | null> {\n\t\tif (!Money.isValidProps(value)) {\n\t\t\treturn Result.fail(Money.MESSAGE);\n\t\t}\n\t\treturn Result.Ok(new Money(value));\n\t};\n}\n\nexport { Money };\nexport default Money;\n"
  },
  {
    "path": "packages/money/package.json",
    "content": "{\n  \"name\": \"@type-ddd/money\",\n  \"description\": \"This package provides TypeScript type definitions for handling Money in Domain-Driven Design contexts\",\n  \"version\": \"0.1.0\",\n  \"main\": \"index.js\",\n  \"types\": \"index.d.ts\",\n  \"author\": \"Alessandro Dev\",\n  \"license\": \"MIT\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"keywords\": [\n    \"Complexity\",\n    \"Business Logic\",\n    \"DDD\",\n    \"Domain Driving Design\",\n    \"DDD-Utils\",\n    \"Base Value Object\",\n    \"Domain Events\",\n    \"Clean Architecture\",\n    \"Money\",\n    \"Validation\",\n    \"Formatting\",\n    \"Value Object\",\n    \"Utility\",\n    \"Security\",\n    \"Standards\"\n  ],\n  \"scripts\": {\n    \"build\": \"tsc\"\n  },\n  \"peerDependencies\": {\n    \"rich-domain\": \"^1.25.0\"\n  },\n  \"files\": [\n    \"index.js\",\n    \"index.d.ts\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/4lessandrodev/type-ddd.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/4lessandrodev/type-ddd/issues\"\n  },\n  \"homepage\": \"https://github.com/4lessandrodev/type-ddd/tree/main/packages/money\",\n  \"gitHead\": \"4cb9159bde8d6fc951e9d902feed2ad25da49fa4\"\n}\n"
  },
  {
    "path": "packages/money/tsconfig.build.json",
    "content": "{\n    \"extends\": \"../tsconfig.build.json\",\n    \"compilerOptions\": {\n        \"outDir\": \".\",\n        \"rootDir\": \".\",\n        \"paths\": {}\n    },\n    \"exclude\": [\n        \"node_modules\",\n        \"dist\",\n        \"__tests__/**/*\",\n        \"*.spec.ts\"\n    ],\n    \"references\": []\n}"
  },
  {
    "path": "packages/money/tsconfig.json",
    "content": "{\n\t\"extends\": \"../tsconfig.build.json\",\n\t\"compilerOptions\": {\n\t\t\"types\": [\n\t\t\t\"node\"\n\t\t]\n\t},\n\t\"files\": [],\n\t\"include\": [],\n\t\"references\": [\n\t\t{\n\t\t\t\"path\": \"./tsconfig.build.json\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "packages/password/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.0.5-alpha.0](https://github.com/4lessandrodev/type-ddd/compare/@type-ddd/password@0.0.2...@type-ddd/password@0.0.5-alpha.0) (2024-12-16)\n\n\n\n## 4.0.5 (2024-11-28)\n\n\n### Bug Fixes\n\n* change type create method return null [#194](https://github.com/4lessandrodev/type-ddd/issues/194) ([2cd03bf](https://github.com/4lessandrodev/type-ddd/commit/2cd03bf34387f4889a0a292ba350f2c0cfc753b7))\n* solve error module not found [#449](https://github.com/4lessandrodev/type-ddd/issues/449) ([e9d14f6](https://github.com/4lessandrodev/type-ddd/commit/e9d14f694cafc9c2123cc31055a4561f460a82d3))\n* solve error module not found [#449](https://github.com/4lessandrodev/type-ddd/issues/449) ([7c85419](https://github.com/4lessandrodev/type-ddd/commit/7c85419376860b9b94fbee3f16bc2b10592221f6))\n\n\n\n## 4.0.3 (2024-07-26)\n\n\n\n\n\n# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n## Unreleased\n\n---\n\n## Released\n\n---\n\n### [0.0.4] - 2024-11-28\n\n### Fix\n\n- update rich-domain lib to check nullish type: now 'create' return a possibly null value in Result instance.\n\n### [0.0.3] - 2024-09-26\n\n### Fix\n\n- Corrected `\"files\"` in `package.json` to include `utils.js` and `utils.d.ts`, resolving module not found errors during compilation.\n\n---\n\n\n### [0.0.2] - 2024-05-31\n\n### Docs\n\n- Doc: update documentation\n\n---\n\n### [0.0.1] - 2024-05-31\n\n### Base\n\n- Create base value object as single pack\n"
  },
  {
    "path": "packages/password/README.md",
    "content": "# `@type-ddd/password`\n\n> The @type-ddd/password module provides a class Password for handling password in TypeScript. It includes methods for validating password, encrypt and compare.\n\n## Installation\n\nInstall `rich-domain`, `@type-ddd/password` and `bcrypt` with your favorite package manager:\n\n```sh\n\nnpm i rich-domain @type-ddd/password bcrypt\n\n#OR \n\nyarn add rich-domain @type-ddd/password bcrypt\n\n```\n\n## Usage\n\n```ts\n\nimport { Password } from '@type-ddd/password';\n\n// Initialize Password instance with a valid value\nconst password = Password.init('Y8237FNB@');\n\n// OR\n\n// Create Password instance from provided value\nconst result = Password.create('Y8237FNB@');\n\n// Or create a strong password\nconst pass = Password.random();\n\n```\n\n### Compare password\n\nYou may compare password with plain text to check if is equal\n\n```ts\n\nconst password = Password.init('#$89ABC_v');\n\n// check if password is encrypted\npassword.isEncrypted();\n// false\n\nconst encrypted = password.encrypt();\n\n// compare\nencrypted.compare('#$89ABC_v');\n// true\n\n```\n"
  },
  {
    "path": "packages/password/__tests__/password.spec.ts",
    "content": "import PasswordValueObject from '../index'\n\ndescribe('password.value-object', () => {\n\tdescribe('default', () => {\n\t\tit('should be defined', () => {\n\t\t\tconst valueObject = PasswordValueObject.create('12345');\n\t\t\texpect(valueObject).toBeDefined();\n\t\t});\n\n\t\tit('should create a not encrypted pass', () => {\n\t\t\tconst valueObject = PasswordValueObject.create('12345');\n\t\t\texpect(valueObject.isOk()).toBe(true);\n\t\t});\n\n\t\tit('should fail if try to create a password less than 5 char', () => {\n\t\t\tconst valueObject = PasswordValueObject.create('1234');\n\t\t\texpect(valueObject.isOk()).toBe(false);\n\t\t\texpect(valueObject.error()).toBe(\n\t\t\t\t'Password must has min 5 and max 22 chars',\n\t\t\t);\n\t\t});\n\n\t\tit('should fail if try to create a password greater than 22 char', () => {\n\t\t\tconst valueObject = PasswordValueObject.create(\n\t\t\t\t'123456789101112131415161718',\n\t\t\t);\n\t\t\texpect(valueObject.isOk()).toBe(false);\n\t\t\texpect(valueObject.error()).toBe(\n\t\t\t\t'Password must has min 5 and max 22 chars',\n\t\t\t);\n\t\t});\n\n\t\tit('should validate password with success', () => {\n\t\t\tconst result = PasswordValueObject.isValidProps('123456');\n\t\t\texpect(result).toBe(true);\n\t\t});\n\n\t\tit('should validate password with success', () => {\n\t\t\tconst result = PasswordValueObject.isValidProps('1234');\n\t\t\texpect(result).toBe(false);\n\t\t});\n\n\t\tit('should validate encrypted password with success', () => {\n\t\t\tconst result = PasswordValueObject.create('123456').value();\n\t\t\tconst encrypted = result?.encrypt();\n\t\t\tconst isEncrypted = encrypted?.isEncrypted();\n\t\t\texpect(isEncrypted).toBe(true);\n\t\t\texpect(PasswordValueObject.isValid(encrypted?.value() as string)).toBe(true);\n\t\t});\n\n\t\tit('should encrypt password with success', () => {\n\t\t\tconst result = PasswordValueObject.create('123456').value();\n\t\t\texpect(result?.isEncrypted()).toBe(false);\n\t\t\tconst encrypted = result?.encrypt();\n\t\t\tconst isEncrypted = encrypted?.isEncrypted();\n\t\t\texpect(isEncrypted).toBe(true);\n\t\t});\n\n\t\tit('should get value result with success', () => {\n\t\t\tconst result = PasswordValueObject.create('123456').value();\n\t\t\texpect(result?.value()).toBe('123456');\n\t\t});\n\n\t\tit('should generate a valid random password not encrypted', () => {\n\t\t\tconst result = PasswordValueObject.random(8);\n\t\t\tconst isEncrypted = result.isEncrypted();\n\t\t\texpect(isEncrypted).toBe(false);\n\t\t});\n\n\t\tit('should not generate equal password', () => {\n\t\t\tconst passA = PasswordValueObject.random(12);\n\t\t\tconst passB = PasswordValueObject.random(12);\n\t\t\tconst isEqual = passA.isEqual(passB);\n\t\t\texpect(isEqual).toBe(false);\n\t\t});\n\n\t\tit('should password to be equal', () => {\n\t\t\tconst passA = PasswordValueObject.create('123456abc!').value();\n\t\t\tconst passC = PasswordValueObject.create('123456abc!').value();\n\t\t\tconst passB = passA?.clone();\n\t\t\tconst isEqual1 = passA?.isEqual(passB as PasswordValueObject);\n\t\t\tconst isEqual2 = passA?.isEqual(passC as PasswordValueObject);\n\t\t\texpect(isEqual1).toBe(true);\n\t\t\texpect(isEqual2).toBe(true);\n\t\t});\n\n\t\tit('should generate a valid random password not encrypted default 12 chars', () => {\n\t\t\tconst result = PasswordValueObject.random();\n\t\t\tconst isEncrypted = result.isEncrypted();\n\t\t\texpect(isEncrypted).toBe(false);\n\t\t\texpect(result.value()).toHaveLength(12);\n\t\t});\n\n\t\tit('should compare password not encrypted', () => {\n\t\t\tconst result = PasswordValueObject.create('123456').value();\n\t\t\tconst match = result?.compare('123456');\n\t\t\texpect(match).toBeTruthy();\n\t\t});\n\n\t\tit('should compare encrypted password', () => {\n\t\t\tconst result = PasswordValueObject.create('123456').value();\n\t\t\tconst encrypted = result?.encrypt();\n\t\t\tconst match = encrypted?.compare('123456');\n\t\t\texpect(match).toBeTruthy();\n\t\t});\n\n\t\tit('should compare password not encrypted', () => {\n\t\t\tconst result = PasswordValueObject.create('123456').value();\n\t\t\tconst match = result?.compare('abcdef');\n\t\t\texpect(match).toBeFalsy();\n\t\t});\n\n\t\tit('should compare encrypted password', () => {\n\t\t\tconst result = PasswordValueObject.create('123456').value();\n\t\t\tconst encrypted = result?.encrypt();\n\t\t\tconst match = encrypted?.compare('abcdef');\n\t\t\texpect(match).toBeFalsy();\n\t\t});\n\n\t\tit('should encrypt many times and keep value', () => {\n\t\t\tconst valueObject = PasswordValueObject.create('12345').value();\n\t\t\texpect(valueObject?.isEncrypted()).toBeFalsy();\n\t\t\tconst encrypted1 = valueObject?.encrypt();\n\t\t\texpect(encrypted1?.isEncrypted()).toBeTruthy();\n\t\t\texpect(valueObject?.compare('12345')).toBeTruthy();\n\n\t\t\texpect(encrypted1?.compare('12345')).toBe(true);\n\t\t\texpect(encrypted1?.isEncrypted()).toBeTruthy();\n\t\t});\n\t});\n\n\tdescribe('custom password', () => {\n\t\tbeforeAll(() => {\n\t\t\tReflect.set(PasswordValueObject, 'MAX_LENGTH', 22);\n\t\t\tReflect.set(PasswordValueObject, 'MIN_LENGTH', 10);\n\t\t});\n\n\t\tit('should validate custom password', () => {\n\t\t\tconst pass = PasswordValueObject.create('123456');\n\t\t\texpect(pass.isFail()).toBeTruthy();\n\t\t\texpect(Reflect.get(PasswordValueObject, 'MIN_LENGTH')).toBe(10);\n\t\t});\n\t});\n\n\n\tit('should init an instance with success', () => {\n\t\tconst init = () => PasswordValueObject.init('sample1234');\n\t\texpect(init).not.toThrowError();\n\t});\n\n\tit('should throw an error on init an instance with invalid value', () => {\n\t\tconst init = () => PasswordValueObject.init('');\n\t\texpect(init).toThrowError();\n\t});\n\n\tit('should return the same password if already is encrypted', () => {\n\t\tconst password = PasswordValueObject.random().encrypt();\n\t\tconst encrypted = password.encrypt();\n\t\texpect(password.isEqual(encrypted)).toBeTruthy();\n\t});\n});\n"
  },
  {
    "path": "packages/password/__tests__/util.spec.ts",
    "content": "import { passwordGenerator } from '../utils';\n\ndescribe('password-generator.util', () => {\n\tit('should be defined', () => {\n\t\tconst generator = passwordGenerator;\n\t\texpect(generator).toBeDefined();\n\t});\n\n\tit('should generate a random password with 8 chars', () => {\n\t\tconst password = passwordGenerator(8);\n\t\texpect(password).toHaveLength(8);\n\t});\n\n\tit('should generate a random password with 10 chars', () => {\n\t\tconst password = passwordGenerator(10);\n\t\texpect(password).toHaveLength(10);\n\t});\n\n\tit('should generate a random password with 12 chars', () => {\n\t\tconst password = passwordGenerator(12);\n\t\texpect(password).toHaveLength(12);\n\t});\n\n\tit('should generate a random password with 14 chars', () => {\n\t\tconst password = passwordGenerator(14);\n\t\texpect(password).toHaveLength(14);\n\t});\n\n\tit('should generate a random password with 16 chars', () => {\n\t\tconst password = passwordGenerator(16);\n\t\texpect(password).toHaveLength(16);\n\t});\n\n\tit('should generate a random password with 18 chars', () => {\n\t\tconst password = passwordGenerator(18);\n\t\texpect(password).toHaveLength(18);\n\t});\n});\n"
  },
  {
    "path": "packages/password/index.ts",
    "content": "import { genSaltSync, hashSync, compareSync } from 'bcrypt';\nimport { Result, ValueObject } from 'rich-domain';\nimport passwordGenerator, { ILength } from './utils';\nconst regexHash = /^\\$2b\\$10\\$.{53}$/;\n\nclass Password extends ValueObject<string> {\n\tprotected static readonly MAX_LENGTH = 22;\n\tprotected static readonly MIN_LENGTH = 5;\n\tprotected static readonly REGEX = regexHash;\n\tprotected static readonly MESSAGE: string = `Password must has min ${Password.MIN_LENGTH} and max ${Password.MAX_LENGTH} chars`;\n\n\tprivate constructor(props: string) {\n\t\tsuper(props);\n\t}\n\n\t/**\n\t * @returns value as string\n\t */\n\tvalue(): string {\n\t\treturn this.props;\n\t}\n\n\t/**\n\t *\n\t * @description compare plainText with encrypted password\n\t * @param plainText plainText not encrypted to compare with encrypted password\n\t * @returns true if match else false\n\t */\n\tpublic compare(plainText: string): boolean {\n\t\tif (this.isEncrypted()) {\n\t\t\treturn compareSync(plainText, this.props);\n\t\t}\n\t\treturn plainText === this.props;\n\t}\n\n\t/**\n\t *\n\t * @returns true if instance value is encrypted else false\n\t */\n\tpublic isEncrypted(): boolean {\n\t\tconst isEncrypted = this.validator\n\t\t\t.string(this.props)\n\t\t\t.match(Password.REGEX);\n\t\treturn isEncrypted;\n\t}\n\n\t/**\n\t *\n\t * @returns true if provided value is encrypted else false\n\t */\n\tpublic static isEncrypted(value: string): boolean {\n\t\treturn this.validator.string(value).match(Password.REGEX);\n\t}\n\n\t/**\n\t *\n\t * @param length password length as number 8/10/12/14/16/18\n\t * @returns PasswordValueObject\n\t * @default 12 chars or greater is recommended for strongest password\n\t */\n\tpublic static random(length?: ILength): Password {\n\t\tconst pass = passwordGenerator(length ?? 12);\n\t\treturn Password.create(pass).value();\n\t}\n\n\t/**\n\t * @summary Encrypts the password.\n\t * @description This method encrypts the password using bcrypt hashing algorithm. If the password is already encrypted, it returns the encrypted password as it is. Otherwise, it generates a salt, hashes the password with the salt, and returns the encrypted password.\n\t * @returns A Password object representing the encrypted password.\n\t */\n\tpublic encrypt(): Password {\n\t\tconst isEncrypted = this.isEncrypted();\n\t\tif (isEncrypted) {\n\t\t\tconst encrypted = this.props;\n\t\t\treturn new Password(encrypted);\n\t\t}\n\t\tconst salt = genSaltSync();\n\t\tconst encrypted = hashSync(this.props, salt);\n\t\treturn new Password(encrypted);\n\t}\n\n\t/**\n\t *\n\t * @param value check if password has a valid value length\n\t * @returns true if is all ok or false else not\n\t */\n\tpublic static isValid(value: string): boolean {\n\t\treturn this.isValidProps(value);\n\t}\n\n\t/**\n\t *\n\t * @param value check if password has a valid value length\n\t * @returns true if is all ok or false else not\n\t */\n\tpublic static isValidProps(value: string): boolean {\n\t\tconst { string } = this.validator;\n\t\tif (!Password.isEncrypted(value)) {\n\t\t\tconst passwordHasRequiredLength = string(\n\t\t\t\tvalue,\n\t\t\t).hasLengthBetweenOrEqual(\n\t\t\t\tPassword.MIN_LENGTH,\n\t\t\t\tPassword.MAX_LENGTH,\n\t\t\t);\n\t\t\treturn passwordHasRequiredLength;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * \n\t * @param value value as string\n\t * @returns instance of Password or throw an error\n\t */\n\tpublic static init(value: string): Password {\n\t\tconst isValidValue = Password.isValidProps(value);\n\t\tif (!isValidValue) throw new Error(Password.MESSAGE);\n\t\treturn new Password(value);\n\t}\n\n\t/**\n\t *\n\t * @param value password to create\n\t * @returns Result of PasswordValueObject\n\t */\n\tstatic create(value: string): Result<Password | null> {\n\t\tif (!Password.isValidProps(value)) {\n\t\t\treturn Result.fail(Password.MESSAGE);\n\t\t}\n\t\treturn Result.Ok(new Password(value));\n\t}\n}\n\nexport { Password };\nexport default Password;\n"
  },
  {
    "path": "packages/password/package.json",
    "content": "{\n  \"name\": \"@type-ddd/password\",\n  \"description\": \"Library that provides TypeScript type definitions for handling Password in Domain-Driven Design contexts. It facilitates the validation and manipulation of passwords.\",\n  \"version\": \"0.1.0\",\n  \"main\": \"index.js\",\n  \"types\": \"index.d.ts\",\n  \"author\": \"Alessandro Dev\",\n  \"license\": \"MIT\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"keywords\": [\n    \"Complexity\",\n    \"Business Logic\",\n    \"DDD\",\n    \"Domain Driving Design\",\n    \"DDD-Utils\",\n    \"Base Value Object\",\n    \"Domain Events\",\n    \"Clean Architecture\",\n    \"Password\",\n    \"Validation\",\n    \"Formatting\",\n    \"Value Object\",\n    \"Utility\",\n    \"Security\",\n    \"Standards\"\n  ],\n  \"scripts\": {\n    \"build\": \"tsc\"\n  },\n  \"devDependencies\": {\n    \"@types/bcrypt\": \"^5.0.0\",\n    \"bcrypt\": \"^5.0.1\"\n  },\n  \"peerDependencies\": {\n    \"bcrypt\": \"^5.0.1\",\n    \"rich-domain\": \"^1.25.0\"\n  },\n  \"files\": [\n    \"index.js\",\n    \"index.d.ts\",\n    \"utils.d.ts\",\n    \"utils.js\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/4lessandrodev/type-ddd.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/4lessandrodev/type-ddd/issues\"\n  },\n  \"homepage\": \"https://github.com/4lessandrodev/type-ddd/tree/main/packages/password\",\n  \"gitHead\": \"4cb9159bde8d6fc951e9d902feed2ad25da49fa4\"\n}\n"
  },
  {
    "path": "packages/password/tsconfig.build.json",
    "content": "{\n    \"extends\": \"../tsconfig.build.json\",\n    \"compilerOptions\": {\n        \"outDir\": \".\",\n        \"rootDir\": \".\",\n        \"paths\": {}\n    },\n    \"exclude\": [\n        \"node_modules\",\n        \"dist\",\n        \"__tests__/**/*\",\n        \"*.spec.ts\"\n    ],\n    \"references\": []\n}"
  },
  {
    "path": "packages/password/tsconfig.json",
    "content": "{\n\t\"extends\": \"../tsconfig.build.json\",\n\t\"compilerOptions\": {\n\t\t\"types\": [\n\t\t\t\"node\"\n\t\t]\n\t},\n\t\"files\": [],\n\t\"include\": [],\n\t\"references\": [\n\t\t{\n\t\t\t\"path\": \"./tsconfig.build.json\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "packages/password/utils.ts",
    "content": "const upper = [\n\t'A',\n\t'B',\n\t'C',\n\t'D',\n\t'E',\n\t'F',\n\t'G',\n\t'H',\n\t'I',\n\t'J',\n\t'K',\n\t'L',\n\t'M',\n\t'N',\n\t'O',\n\t'P',\n\t'Q',\n\t'R',\n\t'S',\n\t'T',\n\t'U',\n\t'V',\n\t'X',\n\t'Y',\n\t'Z',\n\t'W',\n];\nconst lower = [\n\t'a',\n\t'b',\n\t'c',\n\t'd',\n\t'e',\n\t'f',\n\t'g',\n\t'h',\n\t'i',\n\t'j',\n\t'k',\n\t'l',\n\t'm',\n\t'n',\n\t'o',\n\t'p',\n\t'q',\n\t'r',\n\t's',\n\t't',\n\t'u',\n\t'v',\n\t'x',\n\t'y',\n\t'z',\n\t'w',\n];\nconst numbers = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'];\nconst special = [\n\t'!',\n\t'-',\n\t'@',\n\t'$',\n\t'#',\n\t'%',\n\t'&',\n\t'*',\n\t'_',\n\t'+',\n\t'?'\n];\nconst availableChars = [upper, lower, numbers, special];\n\nexport type ILength = 8 | 10 | 12 | 14 | 16 | 18;\n\nconst getChar = (chars: string[]) =>{\n\treturn chars[Math.floor(Math.random() * chars.length)];\n}\n\n/**\n *\n * @param length password length as number 8/10/12/14/16/18\n * @returns string password as plainText\n * @default 14 chars is recommended for strongest password\n */\nconst passwordGenerator = (length: ILength): string => {\n\tlet strongPassword = '';\n\twhile (strongPassword.length < length) {\n\t\tconst random = Math.floor(Math.random() * availableChars.length);\n\t\tstrongPassword += getChar(availableChars[random]);\n\t}\n\n\treturn strongPassword;\n};\n\nexport { passwordGenerator };\nexport default passwordGenerator;\n"
  },
  {
    "path": "packages/patterns/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.0.4-alpha.0](https://github.com/4lessandrodev/type-ddd/compare/@type-ddd/patterns@0.0.2...@type-ddd/patterns@0.0.4-alpha.0) (2024-12-16)\n\n\n\n## 4.0.5 (2024-11-28)\n\n\n### Bug Fixes\n\n* change type create method return null [#194](https://github.com/4lessandrodev/type-ddd/issues/194) ([2cd03bf](https://github.com/4lessandrodev/type-ddd/commit/2cd03bf34387f4889a0a292ba350f2c0cfc753b7))\n\n\n\n## 4.0.3 (2024-07-26)\n\n\n\n\n\n# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n## Unreleased\n\n---\n\n## Released\n\n---\n\n### [0.0.3] - 2024-11-28\n\n### Fix\n\n- update rich-domain lib to check nullish type: now 'create' return a possibly null value in Result instance.\n\n### [0.0.2] - 2024-05-31\n\n### Docs\n\n- Doc: update documentation\n\n---\n\n### [0.0.1] - 2024-05-31\n\n### Base\n\n- Create base value object as single pack\n"
  },
  {
    "path": "packages/patterns/README.md",
    "content": "# `types-ddd`\n\n> TODO: description\n\n## Usage\n\n```\nconst typesDdd = require('types-ddd');\n\n// TODO: DEMONSTRATE API\n```\n"
  },
  {
    "path": "packages/patterns/__tests__/specification.value-object.spec.ts",
    "content": "import { Specification } from '../index';\n\ntype User = {\n\tname: string;\n\tage: number;\n\tpermission: 'ADMIN' | 'CLIENT' | 'OWNER';\n};\n\nclass AdultSpecification extends Specification<User> {\n\tisSatisfiedBy(user: User): boolean {\n\t\treturn user.age > 18;\n\t}\n}\n\nclass AdminSpecification extends Specification<User> {\n\tisSatisfiedBy(user: User): boolean {\n\t\treturn user.permission === 'ADMIN';\n\t}\n}\n\nclass CanAccessSpecification extends Specification<User> {\n\tisSatisfiedBy(user: User): boolean {\n\t\treturn user.permission === 'OWNER';\n\t}\n}\n\ndescribe('specification', () => {\n\tit('should be defined', () => {\n\t\tconst specification = Specification;\n\t\texpect(specification).toBeDefined();\n\t});\n\n\tit('should be adult', () => {\n\t\tconst IsAdult = new AdultSpecification().isSatisfiedBy({\n\t\t\tage: 20,\n\t\t\tname: 'john stuart',\n\t\t\tpermission: 'ADMIN',\n\t\t});\n\t\texpect(IsAdult).toBeTruthy();\n\t});\n\n\tit('should be admin', () => {\n\t\tconst IsAdult = new AdminSpecification().isSatisfiedBy({\n\t\t\tage: 20,\n\t\t\tname: 'john stuart',\n\t\t\tpermission: 'ADMIN',\n\t\t});\n\t\texpect(IsAdult).toBeTruthy();\n\t});\n\n\tit('should be can access OWNER', () => {\n\t\tconst IsAdult = new CanAccessSpecification().isSatisfiedBy({\n\t\t\tage: 20,\n\t\t\tname: 'john stuart',\n\t\t\tpermission: 'OWNER',\n\t\t});\n\t\texpect(IsAdult).toBeTruthy();\n\t});\n\n\tit('should be defined 15 yrs old & OWNER', () => {\n\t\tconst IsAdult = new CanAccessSpecification().isSatisfiedBy({\n\t\t\tage: 15,\n\t\t\tname: 'john stuart',\n\t\t\tpermission: 'OWNER',\n\t\t});\n\t\texpect(IsAdult).toBeTruthy();\n\t});\n\n\tit('should be can access +18 & !ADMIN', () => {\n\t\tconst IsAdult = new CanAccessSpecification().isSatisfiedBy({\n\t\t\tage: 20,\n\t\t\tname: 'john stuart',\n\t\t\tpermission: 'CLIENT',\n\t\t});\n\t\texpect(IsAdult).toBeFalsy();\n\t});\n\n\tit('should not to have access -18 & !ADMIN', () => {\n\t\tconst IsAdult = new CanAccessSpecification().isSatisfiedBy({\n\t\t\tage: 12,\n\t\t\tname: 'john stuart',\n\t\t\tpermission: 'CLIENT',\n\t\t});\n\t\texpect(IsAdult).toBeFalsy();\n\t});\n\n\tit('should be NOT to be not be adult and not have access', () => {\n\t\tconst IsAdult = new CanAccessSpecification()\n\t\t\t.or(new AdultSpecification())\n\t\t\t.isSatisfiedBy({\n\t\t\t\tage: 12,\n\t\t\t\tname: 'john stuart',\n\t\t\t\tpermission: 'CLIENT',\n\t\t\t});\n\t\texpect(IsAdult).toBeFalsy();\n\t});\n\n\tit('should be adult cause OR', () => {\n\t\tconst IsAdult = new CanAccessSpecification()\n\t\t\t.or(new AdultSpecification())\n\t\t\t.isSatisfiedBy({\n\t\t\t\tage: 21,\n\t\t\t\tname: 'john stuart',\n\t\t\t\tpermission: 'CLIENT',\n\t\t\t});\n\t\texpect(IsAdult).toBeTruthy();\n\t});\n\n\tit('should be have access ADMIN cause OR', () => {\n\t\tconst IsAdult = new CanAccessSpecification()\n\t\t\t.or(new AdminSpecification())\n\t\t\t.isSatisfiedBy({\n\t\t\t\tage: 12,\n\t\t\t\tname: 'john stuart',\n\t\t\t\tpermission: 'ADMIN',\n\t\t\t});\n\t\texpect(IsAdult).toBeTruthy();\n\t});\n\n\tit('should have access cause AND adult or ADMIN', () => {\n\t\tconst IsAdult = new CanAccessSpecification()\n\t\t\t.or(new AdminSpecification())\n\t\t\t.and(new AdultSpecification())\n\t\t\t.isSatisfiedBy({\n\t\t\t\tage: 25,\n\t\t\t\tname: 'john stuart',\n\t\t\t\tpermission: 'ADMIN',\n\t\t\t});\n\t\texpect(IsAdult).toBeTruthy();\n\t});\n\n\tit('should NOT have access cause AND is not adult', () => {\n\t\tconst IsAdult = new CanAccessSpecification()\n\t\t\t.or(new AdminSpecification())\n\t\t\t.and(new AdultSpecification())\n\t\t\t.isSatisfiedBy({\n\t\t\t\tage: 11,\n\t\t\t\tname: 'john stuart',\n\t\t\t\tpermission: 'ADMIN',\n\t\t\t});\n\t\texpect(IsAdult).toBeFalsy();\n\t});\n\n\tit('should have access cause not Adult', () => {\n\t\tconst IsAdult = new CanAccessSpecification()\n\t\t\t.andNot(new AdultSpecification())\n\t\t\t.or(new AdminSpecification())\n\t\t\t.isSatisfiedBy({\n\t\t\t\tage: 11,\n\t\t\t\tname: 'john stuart',\n\t\t\t\tpermission: 'CLIENT',\n\t\t\t});\n\t\texpect(IsAdult).toBeTruthy();\n\t});\n\n\tit('should invert condition', () => {\n\t\tconst IsAdult = new CanAccessSpecification()\n\t\t\t.or(new AdminSpecification())\n\t\t\t.not()\n\t\t\t.isSatisfiedBy({\n\t\t\t\tage: 11,\n\t\t\t\tname: 'john stuart',\n\t\t\t\tpermission: 'CLIENT',\n\t\t\t});\n\t\texpect(IsAdult).toBeTruthy();\n\t});\n\n\tit('should have access cause orNot adult', () => {\n\t\tconst IsAdult = new CanAccessSpecification()\n\t\t\t.orNot(new AdultSpecification())\n\t\t\t.isSatisfiedBy({\n\t\t\t\tage: 11,\n\t\t\t\tname: 'john stuart',\n\t\t\t\tpermission: 'CLIENT',\n\t\t\t});\n\t\texpect(IsAdult).toBeTruthy();\n\t});\n});\n"
  },
  {
    "path": "packages/patterns/index.ts",
    "content": "export interface ISpecification<T> {\n\tisSatisfiedBy: (target: T) => boolean;\n\tand: (other: ISpecification<T>) => ISpecification<T>;\n\tor: (other: ISpecification<T>) => ISpecification<T>;\n\tandNot: (other: ISpecification<T>) => ISpecification<T>;\n\torNot: (other: ISpecification<T>) => ISpecification<T>;\n\tnot: () => ISpecification<T>;\n}\n\nexport abstract class Specification<T> implements ISpecification<T> {\n\tabstract isSatisfiedBy(target: T): boolean;\n\n\tand(other: ISpecification<T>): ISpecification<T> {\n\t\treturn new AndSpecification<T>(this, other);\n\t}\n\n\tor(other: ISpecification<T>): ISpecification<T> {\n\t\treturn new OrSpecification<T>(this, other);\n\t}\n\n\torNot(other: ISpecification<T>): ISpecification<T> {\n\t\treturn new OrNotSpecification<T>(this, other);\n\t}\n\n\tandNot(other: ISpecification<T>): ISpecification<T> {\n\t\treturn new AndNotSpecification<T>(this, other);\n\t}\n\n\tnot(): ISpecification<T> {\n\t\treturn new NotSpecification<T>(this);\n\t}\n}\n\nexport class AndSpecification<T> extends Specification<T> {\n\tconstructor(\n\t\tprivate readonly one: ISpecification<T>,\n\t\tprivate readonly other: ISpecification<T>,\n\t) {\n\t\tsuper();\n\t}\n\n\tisSatisfiedBy(target: T): boolean {\n\t\treturn (\n\t\t\tthis.one.isSatisfiedBy(target) && this.other.isSatisfiedBy(target)\n\t\t);\n\t}\n}\n\nexport class OrSpecification<T> extends Specification<T> {\n\tconstructor(\n\t\tprivate readonly one: ISpecification<T>,\n\t\tprivate readonly other: ISpecification<T>,\n\t) {\n\t\tsuper();\n\t}\n\n\tisSatisfiedBy(target: T): boolean {\n\t\treturn (\n\t\t\tthis.one.isSatisfiedBy(target) || this.other.isSatisfiedBy(target)\n\t\t);\n\t}\n}\n\nexport class OrNotSpecification<T> extends Specification<T> {\n\tconstructor(\n\t\tprivate readonly one: ISpecification<T>,\n\t\tprivate readonly other: ISpecification<T>,\n\t) {\n\t\tsuper();\n\t}\n\n\tisSatisfiedBy(target: T): boolean {\n\t\treturn (\n\t\t\t(this.one.isSatisfiedBy(target) ||\n\t\t\t\tthis.other.isSatisfiedBy(target)) !== true\n\t\t);\n\t}\n}\n\nexport class AndNotSpecification<T> extends Specification<T> {\n\tconstructor(\n\t\tprivate readonly one: ISpecification<T>,\n\t\tprivate readonly other: ISpecification<T>,\n\t) {\n\t\tsuper();\n\t}\n\n\tisSatisfiedBy(target: T): boolean {\n\t\treturn (\n\t\t\t(this.one.isSatisfiedBy(target) &&\n\t\t\t\tthis.other.isSatisfiedBy(target)) !== true\n\t\t);\n\t}\n}\n\nexport class NotSpecification<T> extends Specification<T> {\n\tconstructor(private readonly other: ISpecification<T>) {\n\t\tsuper();\n\t}\n\n\tisSatisfiedBy(target: T): boolean {\n\t\treturn !this.other.isSatisfiedBy(target);\n\t}\n}\n\nexport default Specification;\n"
  },
  {
    "path": "packages/patterns/package.json",
    "content": "{\n  \"name\": \"@type-ddd/patterns\",\n  \"description\": \"This package provide utils file and interfaces to assistant build a complex application with domain driving design\",\n  \"version\": \"0.1.0\",\n  \"main\": \"index.js\",\n  \"types\": \"index.d.ts\",\n  \"author\": \"Alessandro Dev\",\n  \"license\": \"MIT\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"keywords\": [\n    \"Complexity\",\n    \"Business Logic\",\n    \"DDD\",\n    \"Domain Driving Design\",\n    \"DDD-Utils\",\n    \"Base Value Object\",\n    \"Domain Events\",\n    \"Clean Architecture\",\n    \"CPF\",\n    \"Validation\",\n    \"Formatting\",\n    \"Value Object\",\n    \"Utility\",\n    \"Security\",\n    \"Standards\",\n    \"Brazil\"\n  ],\n  \"scripts\": {\n    \"prebuild\": \"rimraf ./dist\",\n    \"build\": \"tsc\"\n  },\n  \"peerDependencies\": {\n    \"rich-domain\": \"^1.25.0\"\n  },\n  \"files\": [\n    \"index.js\",\n    \"index.d.ts\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/4lessandrodev/type-ddd.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/4lessandrodev/type-ddd/issues\"\n  },\n  \"homepage\": \"https://github.com/4lessandrodev/type-ddd/tree/main/packages/patterns\",\n  \"gitHead\": \"4cb9159bde8d6fc951e9d902feed2ad25da49fa4\"\n}\n"
  },
  {
    "path": "packages/patterns/tsconfig.build.json",
    "content": "{\n    \"extends\": \"../tsconfig.build.json\",\n    \"compilerOptions\": {\n        \"outDir\": \".\",\n        \"rootDir\": \".\",\n        \"paths\": {}\n    },\n    \"exclude\": [\n        \"node_modules\",\n        \"dist\",\n        \"__tests__/**/*\",\n        \"*.spec.ts\"\n    ],\n    \"references\": []\n}"
  },
  {
    "path": "packages/patterns/tsconfig.json",
    "content": "{\n\t\"extends\": \"../tsconfig.build.json\",\n\t\"compilerOptions\": {\n\t\t\"types\": [\n\t\t\t\"node\"\n\t\t]\n\t},\n\t\"files\": [],\n\t\"include\": [],\n\t\"references\": [\n\t\t{\n\t\t\t\"path\": \"./tsconfig.build.json\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "packages/phone/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.0.4-alpha.0](https://github.com/4lessandrodev/type-ddd/compare/@type-ddd/phone@0.0.2...@type-ddd/phone@0.0.4-alpha.0) (2024-12-16)\n\n\n\n## 4.0.5 (2024-11-28)\n\n\n### Bug Fixes\n\n* change type create method return null [#194](https://github.com/4lessandrodev/type-ddd/issues/194) ([2cd03bf](https://github.com/4lessandrodev/type-ddd/commit/2cd03bf34387f4889a0a292ba350f2c0cfc753b7))\n\n\n\n## 4.0.3 (2024-07-26)\n\n\n\n\n\n# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n## Unreleased\n\n---\n\n## Released\n\n---\n\n### [0.0.3] - 2024-11-28\n\n### Fix\n\n- update rich-domain lib to check nullish type: now 'create' return a possibly null value in Result instance.\n\n### [0.0.2] - 2024-05-31\n\n### Docs\n\n- Doc: update documentation\n\n---\n\n### [0.0.1] - 2024-05-31\n\n### Base\n\n- Create base value object as single pack\n"
  },
  {
    "path": "packages/phone/README.md",
    "content": "# `@type-ddd/phone`\n\n> The @type-ddd/phone library provides TypeScript type definitions for handling phone (Brazilian) in Domain-Driven Design contexts. It facilitates the validation and manipulation of phone numbers, ensuring they adhere to the Brazilian legal standards.\n\n---\n\n## Installation\n\nInstall `rich-domain` and `@type-ddd/phone` with your favorite package manager\n\n```sh\n\nnpm i rich-domain @type-ddd/phone\n\n# OR\n\nyarn add rich-domain @type-ddd/phone\n\n```\n\n## Usage\n\nDon't worry about removing special characters; they are automatically stripped from all instances.\n\n```ts\n\nimport { Phone } from '@type-ddd/phone'\n\n// Instance of phone or throws an error if provide an invalid value\nconst phone = Phone.init('11994882021');\n\n// OR\n\n// Result of phone (Check Result pattern docs)\nconst result = Phone.create('11994882021');\n\nresult.isOk(); // true\n\n// phone instance or null if provide an invalid value\nconst phone = result.value();\n\n```\n\n## Check phone type\n\nMethod to verify instance type.\n\n```ts\n\n// value as string \nconst isMobile = Phone.isMobile('11994882021');\n// Output: true\n\n// OR\n\n// value as string \nconst isMobile = Phone.isHome('11994882021');\n// Output: false\n\n```\n\n## Special Chars\n\nDon't worry about removing special characters; they are automatically stripped from all instances.\n\n```ts\n\nconst result = Phone.isValid('(11) 99488-2021');\n// Output: true\n\n```\n\n## Special chars\n\nIf you need the value with the mask, you can use the `toPattern` method:\n\n```ts\n\nphone.toPattern();\n\n// Output: '(11) 99488-2021'\n\n```\n\nOr if you need to apply mask from a string value you may use `addMask` method\n\n\n```ts\n\nPhone.addMask('11994882021');\n\n// Output: (11) 99488-2021\n\n```\n\nOr if you need to remove mask from a string value you may use `removeSpecialChars` method\n\n\n```ts\n\nPhone.removeSpecialChars('(11) 99488-2021');\n\n// Output: 11994882021\n\n```\n\nIf you need to identify uf from a phone number\n\n```ts\n\nconst phone = Phone.init('(11) 99488-2021');\n\nphone.uf();\n// Output: \"São Paulo\"\n\nphone.code();\n// 11\n\nphone.number();\n// 994882021\n\nphone.toCall();\n// 011994882021\n\n```\n"
  },
  {
    "path": "packages/phone/__tests__/home-phone.value-object.spec.ts",
    "content": "import { HomePhone as HomePhoneValueObject } from '../home.value-object';\n\ndescribe('home-phone.value-object', () => {\n\tit('should be defined', () => {\n\t\tconst valueObject = HomePhoneValueObject.create;\n\t\texpect(valueObject).toBeDefined();\n\t});\n\n\tit('should create homePhone with success', () => {\n\t\tconst valueObject = HomePhoneValueObject.create('(11) 3404-1111');\n\t\texpect(valueObject.isOk()).toBe(true);\n\t});\n\n\tit('should return true', () => {\n\t\tconst isValid = HomePhoneValueObject.isValid('(11) 3404-1111');\n\t\texpect(isValid).toBe(true);\n\t});\n\n\tit('should return true', () => {\n\t\tconst isValid = HomePhoneValueObject.isValid('1134041111');\n\t\texpect(isValid).toBe(true);\n\t});\n\n\tit('should return false', () => {\n\t\tconst isValid = HomePhoneValueObject.isValid('(52) 3404-1111');\n\t\texpect(isValid).toBe(false);\n\t});\n\n\tit('should return only numbers', () => {\n\t\tconst value = HomePhoneValueObject.removeSpecialChars('(11) 3404-1111');\n\t\texpect(value).toBe('1134041111');\n\t});\n\n\tit('should return numbers with mask', () => {\n\t\tconst value = HomePhoneValueObject.addMask('1134041111');\n\t\texpect(value).toBe('(11) 3404-1111');\n\t});\n\n\tit('should fail if try to create an invalid home phone number', () => {\n\t\tconst valueObject = HomePhoneValueObject.create('(11) 1111-1111');\n\t\texpect(valueObject.isOk()).toBe(false);\n\t});\n\n\tit('should fail if try to create an invalid home phone number', () => {\n\t\tconst valueObject = HomePhoneValueObject.create('(11) 11111111');\n\t\texpect(valueObject.isOk()).toBe(false);\n\t});\n\n\tit('should fail if try to create an invalid home phone number', () => {\n\t\tconst valueObject = HomePhoneValueObject.create('(01) 3404-1111');\n\t\texpect(valueObject.isOk()).toBe(false);\n\t});\n\n\tit('should fail if try to create an invalid home phone number', () => {\n\t\tconst valueObject = HomePhoneValueObject.create('01 3404-1111');\n\t\texpect(valueObject.isOk()).toBe(false);\n\t});\n\n\tit('should fail if try to create an invalid home phone number', () => {\n\t\tconst valueObject = HomePhoneValueObject.create('013404-1111');\n\t\texpect(valueObject.isOk()).toBe(false);\n\t});\n\n\tit('should get value', () => {\n\t\tconst valueObject =\n\t\t\tHomePhoneValueObject.create('(71) 2254-1211').value();\n\t\texpect(valueObject?.value()).toBe('7122541211');\n\t\texpect(valueObject?.toPattern()).toBe('(71) 2254-1211');\n\t});\n\n\tit('should get only numbers value', () => {\n\t\tconst valueObject =\n\t\t\tHomePhoneValueObject.create('(71) 2254-1211').value();\n\t\texpect(valueObject?.number()).toBe('22541211');\n\t\texpect(valueObject?.toCall()).toBe('07122541211');\n\t});\n\n\tit('should get only DDD number', () => {\n\t\tconst valueObject =\n\t\t\tHomePhoneValueObject.create('(71) 2254-1211').value();\n\t\texpect(valueObject?.code()).toBe(71);\n\t});\n\n\tit('should init an instance with success', () => {\n\t\tconst init = () => HomePhoneValueObject.init('(71) 2253-1213');\n\t\texpect(init).not.toThrowError();\n\t});\n\n\tit('should throw an error on init an instance with invalid value', () => {\n\t\tconst init = () => HomePhoneValueObject.init('');\n\t\texpect(init).toThrowError();\n\t});\n\n\tit('should get uf', () => {\n\t\tconst home = HomePhoneValueObject.init('(71) 2253-1213');\n\t\texpect(home.uf()).toBe('Bahia');\n\t});\n});\n"
  },
  {
    "path": "packages/phone/__tests__/mobile-phone.value-object.spec.ts",
    "content": "import { MobilePhone as MobilePhoneValueObject } from '../mobile.value-object';\n\ndescribe('home-phone.value-object', () => {\n\tit('should be defined', () => {\n\t\tconst valueObject = MobilePhoneValueObject.create;\n\t\texpect(valueObject).toBeDefined();\n\t});\n\n\tit('should create mobile phone number with success', () => {\n\t\tconst valueObject = MobilePhoneValueObject.create('(11) 99604-1111');\n\t\texpect(valueObject.isOk()).toBe(true);\n\t});\n\n\tit('should create mobile phone number with success', () => {\n\t\tconst valueObject = MobilePhoneValueObject.create('11996041111');\n\t\texpect(valueObject.isOk()).toBe(true);\n\t});\n\n\tit('should create mobile phone number with success', () => {\n\t\tconst phone = MobilePhoneValueObject.init('11996041111');\n\t\texpect(phone.uf()).toBe('São Paulo');\n\t});\n\n\tit('should create mobile phone number with success', () => {\n\t\tconst valueObject = MobilePhoneValueObject.create('(52) 99604-1111');\n\t\texpect(valueObject.isOk()).toBe(false);\n\t});\n\n\tit('should remove special chars with success', () => {\n\t\tconst value = MobilePhoneValueObject.removeSpecialChars('(11) 99604-1111');\n\t\texpect(value).toBe('11996041111');\n\t});\n\n\tit('should add mask with success', () => {\n\t\tconst value = MobilePhoneValueObject.addMask('11996041111');\n\t\texpect(value).toBe('(11) 99604-1111');\n\t});\n\n\tit('should return true', () => {\n\t\tconst isValid = MobilePhoneValueObject.isValid('(11) 99604-1111');\n\t\texpect(isValid).toBe(true);\n\t});\n\n\tit('should fail if try to create an invalid home phone number', () => {\n\t\tconst valueObject = MobilePhoneValueObject.create('(11) 99999-9999');\n\t\texpect(valueObject.isOk()).toBe(false);\n\t});\n\n\tit('should fail if try to create an invalid home phone number', () => {\n\t\tconst valueObject = MobilePhoneValueObject.create('(11) 11111111');\n\t\texpect(valueObject.isOk()).toBe(false);\n\t});\n\n\tit('should fail if try to create an invalid home phone number', () => {\n\t\tconst valueObject = MobilePhoneValueObject.create('(01) 99061-1111');\n\t\texpect(valueObject.isOk()).toBe(false);\n\t});\n\n\tit('should fail if try to create an invalid home phone number', () => {\n\t\tconst valueObject = MobilePhoneValueObject.create('01 99620-1111');\n\t\texpect(valueObject.isOk()).toBe(false);\n\t});\n\n\tit('should fail if try to create an invalid home phone number', () => {\n\t\tconst valueObject = MobilePhoneValueObject.create('99201-1111');\n\t\texpect(valueObject.isOk()).toBe(false);\n\t});\n\n\tit('should get value', () => {\n\t\tconst valueObject =\n\t\t\tMobilePhoneValueObject.create('(71) 98254-1211').value();\n\t\texpect(valueObject?.value()).toBe('71982541211');\n\t\texpect(valueObject?.toPattern()).toBe('(71) 98254-1211');\n\t});\n\n\tit('should get only numbers value', () => {\n\t\tconst valueObject =\n\t\t\tMobilePhoneValueObject.create('(71) 96254-1211').value();\n\t\texpect(valueObject?.number()).toBe('962541211');\n\t\texpect(valueObject?.toCall()).toBe('071962541211')\n\t});\n\n\tit('should get only DDD number', () => {\n\t\tconst valueObject =\n\t\t\tMobilePhoneValueObject.create('(71) 97254-1211').value();\n\t\texpect(valueObject?.code()).toBe(71);\n\t});\n\n\tit('should init an instance with success', () => {\n\t\tconst init = () => MobilePhoneValueObject.init('(62) 96556-1234');\n\t\texpect(init).not.toThrowError();\n\t});\n\n\tit('should throw an error on init an instance with invalid value', () => {\n\t\tconst init = () => MobilePhoneValueObject.init('');\n\t\texpect(init).toThrowError();\n\t});\n});\n"
  },
  {
    "path": "packages/phone/__tests__/phone.value-object.spec.ts",
    "content": "import { Phone } from '../phone.value-object';\n\ndescribe('phone', () => {\n    it('should create a valid phone', () => {\n        const phone = Phone.init('(11) 99488-2885');\n        expect(phone.isMobile()).toBeTruthy();\n        expect(phone.isHome()).toBeFalsy();\n        expect(Phone.isMobile('(11) 99488-2885')).toBeTruthy();\n        expect(Phone.isHome('(11) 99488-2885')).toBeFalsy();\n    });\n\n    it('should throw error if provide invalid value', () => {\n        const build = () => Phone.init('(52) 99488-2885');\n        expect(build).toThrowError();\n    });\n\n    it('should create a valid phone', () => {\n        const phone = Phone.init('(11) 3404-2885');\n        expect(phone.isHome()).toBeTruthy();\n        expect(phone.isMobile()).toBeFalsy();\n        expect(Phone.isMobile('(11) 3404-2885')).toBeFalsy();\n        expect(Phone.isHome('(11) 3404-2885')).toBeTruthy();\n    });\n\n    it('should return false', () => {\n        const isValid = Phone.isValid('(11) 3404-288500');\n        expect(isValid).toBeFalsy();\n    });\n\n    it('should create a valid phone', () => {\n        const phone = Phone.create('(11) 3404-2885').value();\n        expect(phone?.isHome()).toBeTruthy();\n        expect(phone?.isMobile()).toBeFalsy();\n    });\n\n    it('should create a valid phone', () => {\n        const phone = Phone.create('(11) 99488-2885').value();\n        expect(phone?.isHome()).toBeFalsy();\n        expect(phone?.isMobile()).toBeTruthy();\n    });\n\n    it('should return fail', () => {\n        const result = Phone.create('(11) 99488-28850');\n        expect(result.isFail()).toBeTruthy();\n    });\n\n    it('should add mask', () => {\n        const phone = Phone.addMask('11994885487');\n        expect(phone).toBe('(11) 99488-5487')\n    });\n\n    it('should add mask', () => {\n        const phone = Phone.addMask('1134048956');\n        expect(phone).toBe('(11) 3404-8956')\n    });\n\n    it('should remove mask', () => {\n        const phone = Phone.removeSpecialChars('(11) 3404-8956');\n        expect(phone).toBe('1134048956')\n    });\n\n    it('should get ddd', () => {\n        const ddd = Phone.ddd('(11) 3404-8956');\n        expect(ddd).toBe(11);\n    });\n});\n"
  },
  {
    "path": "packages/phone/ddd.list.ts",
    "content": "export const AreaCodes = [\n    61, 62, 64, 65, 66, 67, // CENTRO OESTE\n    82, 71, 73, 74, 75, 77, 85, 88, 98, 99, 83, 81, 87, 86, 89, 84, 79, // NORDESTE\n    68, 96, 92, 97, 91, 93, 94, 69, 95, 63, // NORTE\n    41, 42, 43, 44, 45, 46, 51, 53, 54, 55, 47, 48, 49, // SUL\n    27, 28, 31, 32, 33, 34, 35, 37, 38, 21, 22, 24, 11, 12, 13, 14, 15, 16, 17, 18, 19 // SUDESTE\n];\n\nexport const UfForCode = {\n    61: \"Distrito Federal\",\n    62: \"Goiás\",\n    64: \"Goiás\",\n    65: \"Mato Grosso\",\n    66: \"Mato Grosso\",\n    67: \"Mato Grosso do Sul\",\n    82: \"Alagoas\",\n    71: \"Bahia\",\n    73: \"Bahia\",\n    74: \"Bahia\",\n    75: \"Bahia\",\n    77: \"Bahia\",\n    85: \"Ceará\",\n    88: \"Ceará\",\n    98: \"Maranhão\",\n    99: \"Maranhão\",\n    83: \"Paraíba\",\n    81: \"Pernambuco\",\n    87: \"Pernambuco\",\n    86: \"Piauí\",\n    89: \"Piauí\",\n    84: \"Rio Grande do Norte\",\n    79: \"Rio Grande do Norte\",\n    68: \"Acre\",\n    96: \"Amapá\",\n    92: \"Amazonas\",\n    97: \"Amazonas\",\n    91: \"Pará\",\n    93: \"Pará\",\n    94: \"Pará\",\n    69: \"Rondônia\",\n    95: \"Roraima\",\n    63: \"Tocantins\",\n    41: \"Paraná\",\n    42: \"Paraná\",\n    43: \"Paraná\",\n    44: \"Paraná\",\n    45: \"Paraná\",\n    46: \"Paraná\",\n    51: \"Rio Grande do Sul\",\n    53: \"Rio Grande do Sul\",\n    54: \"Rio Grande do Sul\",\n    55: \"Rio Grande do Sul\",\n    47: \"Santa Catarina\",\n    48: \"Santa Catarina\",\n    49: \"Santa Catarina\",\n    27: \"Espírito Santo\",\n    28: \"Espírito Santo\",\n    31: \"Minas Gerais\",\n    32: \"Minas Gerais\",\n    33: \"Minas Gerais\",\n    34: \"Minas Gerais\",\n    35: \"Minas Gerais\",\n    37: \"Minas Gerais\",\n    38: \"Minas Gerais\",\n    21: \"Rio de Janeiro\",\n    22: \"Rio de Janeiro\",\n    24: \"Rio de Janeiro\",\n    11: \"São Paulo\",\n    12: \"São Paulo\",\n    13: \"São Paulo\",\n    14: \"São Paulo\",\n    15: \"São Paulo\",\n    16: \"São Paulo\",\n    17: \"São Paulo\",\n    18: \"São Paulo\",\n    19: \"São Paulo\"\n} as const;\nexport type ddd = keyof typeof UfForCode;\n"
  },
  {
    "path": "packages/phone/home.value-object.ts",
    "content": "import { Result, ValueObject } from 'rich-domain';\nimport { AreaCodes, UfForCode, ddd } from './ddd.list';\nconst regexHash = /^\\([1-9]{2}\\)\\s[2-5][0-9]{3}\\-[0-9]{4}$|^[1-9]{2}[2-5]{1}[0-9]{7}$/;\nconst regexHashSpecialChars = /\\(|\\)|-|\\s/g;\n\n/**\n * @description Brazilian Home Phone Number\n * @default (XX) XXXX-XXXX\n */\nclass HomePhone extends ValueObject<string> {\n\tprotected static readonly REGEX = regexHash;\n\tprotected static readonly MESSAGE: string = 'Invalid Home Phone Number';\n\n\tprivate constructor(prop: string) {\n\t\tsuper(prop);\n\t}\n\n\ttoPattern(): string {\n\t\treturn HomePhone.addMask(this.props);\n\t}\n\n\tisMobile(): boolean {\n\t\treturn false;\n\t};\n\n\tisHome(): boolean {\n\t\treturn true;\n\t};\n\n\tpublic static isValid(value: string): boolean {\n\t\treturn this.isValidProps(value);\n\t}\n\n\t/**\n\t *\n\t * @param value Phone number (XX) XXXX-XXXX\n\t * @returns true if pattern match and false if not.\n\t */\n\tpublic static isValidProps(value: string): boolean {\n\t\tconst isValidDDD = AreaCodes.includes(this.code(value));\n\t\tconst matchPattern = this.validator.string(value).match(HomePhone.REGEX);\n\t\treturn isValidDDD && matchPattern;\n\t}\n\n\t/**\n\t * @returns value XXXXXXXXXX as string\n\t */\n\tvalue(): string {\n\t\treturn this.props;\n\t}\n\n\t/**\n\t *\n\t * @returns only numbers without special chars. Includes 0 and DDD.\n\t * @example 01122502301\n\t */\n\ttoCall(): string {\n\t\tconst onlyNumbersAsString = this.props;\n\t\treturn `0${onlyNumbersAsString}`;\n\t}\n\n\tnumber(): string {\n\t\treturn this.props.slice(2);\n\t}\n\n\t/**\n\t *\n\t * @returns only area code (DDD) as number\n\t * @example 11\n\t */\n\tcode(): ddd {\n\t\treturn parseInt(this.props.slice(0, 2)) as ddd;\n\t}\n\n\t/**\n\t *\n\t * @returns only area code (DDD) as number\n\t * @example 11\n\t */\n\tpublic static code(phone: string): ddd {\n\t\tconst value = this.util.string(phone).removeSpecialChars();\n\t\treturn parseInt(value.slice(0, 2)) as ddd;\n\t}\n\n\tuf() {\n\t\tconst ddd = this.code();\n\t\treturn UfForCode[ddd];\n\t}\n\n\tpublic static removeSpecialChars(cell: string): string {\n\t\tconst value = this.util.string(cell).removeSpecialChars();\n\t\treturn this.util.string(value).removeSpaces();\n\t}\n\n\tpublic static addMask(cell: string): string {\n\t\tconst phone = this.removeSpecialChars(cell);\n\t\tconst ddd = phone.slice(0, 2);\n\t\tconst partA = phone.slice(2, 6);\n\t\tconst partB = phone.slice(6, 10);\n\t\treturn `(${ddd}) ${partA}-${partB}`;\n\t}\n\n\t/**\n\t * \n\t * @param value value as string\n\t * @returns instance of HomePhone or throw an error\n\t */\n\tpublic static init(value: string): HomePhone {\n\t\tconst isValidValue = HomePhone.isValidProps(value);\n\t\tif (!isValidValue) throw new Error(HomePhone.MESSAGE);\n\t\tconst phone = this.removeSpecialChars(value);\n\t\treturn new HomePhone(phone);\n\t}\n\n\t/**\n\t *\n\t * @param value Brazilian home phone number\n\t * @example (XX) XXXX-XXXX\n\t * @returns Result of HomePhoneValueObject\n\t */\n\tpublic static create(value: string): Result<HomePhone | null> {\n\t\tif (!HomePhone.isValidProps(value)) {\n\t\t\treturn Result.fail(HomePhone.MESSAGE);\n\t\t}\n\t\tconst phone = this.removeSpecialChars(value);\n\t\treturn Result.Ok(new HomePhone(phone));\n\t}\n}\n\nexport { HomePhone };\nexport default HomePhone;\n"
  },
  {
    "path": "packages/phone/index.ts",
    "content": "export * from './home.value-object';\nexport * from './mobile.value-object';\nexport * from './phone.value-object';\n"
  },
  {
    "path": "packages/phone/mobile.value-object.ts",
    "content": "import { Result, ValueObject } from 'rich-domain';\nimport { UfForCode, ddd, AreaCodes } from './ddd.list';\n\nconst regexHash =\n\t/^\\([1-9]{2}\\)\\s[9](?!\\d(?:(\\d)\\1{2})-(\\d)\\1{3})[5-9][0-9]{3}\\-[0-9]{4}$|^[1-9]{2}9[0-9]{8}$/;\nconst regexHashSpecialChars = /\\(|\\)|-|\\s/g;\n\n/**\n * @description Brazilian Mobile Phone Number\n * @default (XX) 9XXXX-XXXX\n */\nclass MobilePhone extends ValueObject<string> {\n\tprotected static readonly REGEX = regexHash;\n\tprotected static readonly MESSAGE: string = 'Invalid Mobile Phone Number';\n\n\tprivate constructor(prop: string) {\n\t\tsuper(prop);\n\t}\n\n\ttoPattern(): string {\n\t\treturn MobilePhone.addMask(this.props);\n\t}\n\n\t/**\n\t *\n\t * @param value Phone number (XX) 9XXXX-XXXX\n\t * @returns true if pattern match and false if not.\n\t */\n\tpublic static isValidProps(value: string): boolean {\n\t\tconst isValidDDD = AreaCodes.includes(this.code(value));\n\t\tconst matchPattern = this.validator.string(value).match(MobilePhone.REGEX);\n\t\treturn isValidDDD && matchPattern;\n\t}\n\n\tpublic static isValid(value: string): boolean {\n\t\treturn MobilePhone.isValidProps(value);\n\t}\n\n\tisMobile(): boolean {\n\t\treturn true;\n\t};\n\n\tisHome(): boolean {\n\t\treturn false;\n\t};\n\n\t/**\n\t * @returns value XX9XXXXXXXX as string\n\t */\n\tvalue(): string {\n\t\treturn this.props;\n\t}\n\n\t/**\n\t *\n\t * @returns only numbers without special chars. Includes 0 and DDD.\n\t * @example 01199502301\n\t */\n\ttoCall(): string {\n\t\tconst onlyNumbersAsString = this.props;\n\t\treturn `0${onlyNumbersAsString}`;\n\t}\n\n\tnumber(): string {\n\t\treturn this.props.slice(2);\n\t}\n\n\t/**\n\t *\n\t * @returns only area code (DDD) as number\n\t * @example 11\n\t */\n\tcode(): ddd {\n\t\treturn parseInt(this.props.slice(0, 2)) as ddd;\n\t}\n\n\t/**\n\t *\n\t * @returns only area code (DDD) as number\n\t * @example 11\n\t */\n\tpublic static code(phone: string): ddd {\n\t\tconst value = this.util.string(phone).removeSpecialChars();\n\t\treturn parseInt(value.slice(0, 2)) as ddd;\n\t}\n\n\tuf() {\n\t\tconst ddd = this.code();\n\t\treturn UfForCode[ddd];\n\t}\n\n\tpublic static removeSpecialChars(cell: string): string {\n\t\tconst value = this.util.string(cell).removeSpecialChars();\n\t\treturn this.util.string(value).removeSpaces();\n\t}\n\n\tpublic static addMask(cell: string): string {\n\t\tconst phone = this.removeSpecialChars(cell);\n\t\tconst ddd = phone.slice(0, 2);\n\t\tconst partA = phone.slice(2, 7);\n\t\tconst partB = phone.slice(7, 11);\n\t\treturn `(${ddd}) ${partA}-${partB}`;\n\t}\n\n\t/**\n\t * \n\t * @param value value as string\n\t * @returns instance of MobilePhone or throw an error\n\t */\n\tpublic static init(value: string): MobilePhone {\n\t\tconst isValidValue = MobilePhone.isValidProps(value);\n\t\tif (!isValidValue) throw new Error(MobilePhone.MESSAGE);\n\t\tconst phone = this.removeSpecialChars(value);\n\t\treturn new MobilePhone(phone);\n\t}\n\n\t/**\n\t *\n\t * @param value Brazilian Mobile phone number\n\t * @example (XX) 9XXXX-XXXX\n\t * @returns Result of MobilePhoneValueObject\n\t */\n\tpublic static create(value: string): Result<MobilePhone | null> {\n\t\tif (!MobilePhone.isValidProps(value)) {\n\t\t\treturn Result.fail(MobilePhone.MESSAGE);\n\t\t}\n\t\tconst phone = this.removeSpecialChars(value);\n\t\treturn Result.Ok(new MobilePhone(phone));\n\t}\n}\n\nexport { MobilePhone };\nexport default MobilePhone;\n"
  },
  {
    "path": "packages/phone/package.json",
    "content": "{\n  \"name\": \"@type-ddd/phone\",\n  \"description\": \"Library that provides TypeScript type definitions for handling Phone Numbers in Domain-Driven Design contexts. It facilitates the validation and manipulation of Brazilian phone numbers.\",\n  \"version\": \"0.1.0\",\n  \"main\": \"index.js\",\n  \"types\": \"index.d.ts\",\n  \"author\": \"Alessandro Dev\",\n  \"license\": \"MIT\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"keywords\": [\n    \"Complexity\",\n    \"Business Logic\",\n    \"DDD\",\n    \"Domain Driving Design\",\n    \"DDD-Utils\",\n    \"Base Value Object\",\n    \"Domain Events\",\n    \"Clean Architecture\",\n    \"Phone Numbers\",\n    \"Validation\",\n    \"Formatting\",\n    \"Value Object\",\n    \"Utility\",\n    \"Security\",\n    \"Standards\",\n    \"Brazil\"\n  ],\n  \"scripts\": {\n    \"build\": \"tsc\"\n  },\n  \"peerDependencies\": {\n    \"rich-domain\": \"^1.25.0\"\n  },\n  \"files\": [\n    \"index.js\",\n    \"index.d.ts\",\n    \"home.value-object.js\",\n    \"home.value-object.d.ts\",\n    \"mobile.value-object.js\",\n    \"mobile.value-object.d.ts\",\n    \"phone.value-object.js\",\n    \"phone.value-object.d.ts\",\n    \"ddd.list.js\",\n    \"ddd.list.d.ts\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/4lessandrodev/type-ddd.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/4lessandrodev/type-ddd/issues\"\n  },\n  \"homepage\": \"https://github.com/4lessandrodev/type-ddd/tree/main/packages/phone\",\n  \"gitHead\": \"4cb9159bde8d6fc951e9d902feed2ad25da49fa4\"\n}\n"
  },
  {
    "path": "packages/phone/phone.value-object.ts",
    "content": "import { Result, ValueObject } from \"rich-domain\";\nimport MobilePhone from \"./mobile.value-object\";\nimport HomePhone from \"./home.value-object\";\nimport { ddd } from \"./ddd.list\";\n\nexport class Phone extends ValueObject<string> {\n    protected static readonly MESSAGE: string = 'Invalid Phone Number';\n\n    toCall: () => string;\n    number: () => string;\n    value: () => string;\n    ddd: () => ddd;\n    isMobile: () => boolean;\n    isHome: () => boolean;\n    uf: () => string;\n    toPattern: () => string;\n\n    /**\n\t *\n\t * @returns DDD only as number\n\t * @example 11\n\t */\n\tpublic static ddd(phone: string): ddd {\n\t\tconst value = this.util.string(phone).removeSpecialChars();\n\t\treturn parseInt(value.slice(0, 2)) as ddd;\n\t}\n\n    public static removeSpecialChars(cell: string): string {\n        const value = this.util.string(cell).removeSpecialChars();\n        return this.util.string(value).removeSpaces();\n    }\n\n    public static addMask(cell: string): string {\n        if (this.isMobile(cell)) return MobilePhone.addMask(cell);\n        return HomePhone.addMask(cell);\n    }\n\n    public static isValid(phone: string): boolean {\n        return this.isValidProps(phone);\n    }\n\n    public static isValidProps(phone: string): boolean {\n        return this.isHome(phone) || this.isMobile(phone);\n    }\n\n    public static isMobile(phone: string): boolean {\n        return MobilePhone.isValid(phone);\n    };\n\n    public static isHome(phone: string): boolean {\n        return HomePhone.isValid(phone);\n    };\n\n    /**\n     * \n     * @param value value as string\n     * @returns instance of MobilePhone or HomePhone or throw an error\n     */\n    public static init(value: string): MobilePhone | HomePhone {\n        const isValid = this.isValidProps(value);\n        if (!isValid) throw new Error(this.MESSAGE);\n        const isMobile = this.isMobile(value);\n        if (isMobile) return MobilePhone.init(value);\n        return HomePhone.init(value);\n    }\n\n    /**\n     *\n     * @param value Brazilian Mobile or Home phone number\n     * @example (XX) 9XXXX-XXXX or (XX) 3XXX-XXXX\n     * @returns Result of MobilePhone or HomePhone\n     */\n    public static create(value: string): Result<MobilePhone | HomePhone | null> {\n        const isValid = this.isValidProps(value);\n        if (!isValid) return Result.fail(this.MESSAGE);\n        const isMobile = this.isMobile(value);\n        if (isMobile) return MobilePhone.create(value);\n        return HomePhone.create(value);\n    }\n}\n\nexport default Phone;\n"
  },
  {
    "path": "packages/phone/tsconfig.build.json",
    "content": "{\n    \"extends\": \"../tsconfig.build.json\",\n    \"compilerOptions\": {\n        \"outDir\": \".\",\n        \"rootDir\": \".\",\n        \"paths\": {}\n    },\n    \"exclude\": [\n        \"node_modules\",\n        \"dist\",\n        \"__tests__/**/*\",\n        \"*.spec.ts\"\n    ],\n    \"references\": []\n}"
  },
  {
    "path": "packages/phone/tsconfig.json",
    "content": "{\n\t\"extends\": \"../tsconfig.build.json\",\n\t\"compilerOptions\": {\n\t\t\"types\": [\n\t\t\t\"node\"\n\t\t]\n\t},\n\t\"files\": [],\n\t\"include\": [],\n\t\"references\": [\n\t\t{\n\t\t\t\"path\": \"./tsconfig.build.json\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "packages/tsconfig.build.json",
    "content": "{\n    \"compilerOptions\": {\n        \"composite\": true,\n        \"module\": \"commonjs\",\n        \"declaration\": true,\n        \"noImplicitAny\": false,\n        \"skipLibCheck\": true,\n        \"noUnusedLocals\": false,\n        \"importHelpers\": true,\n        \"removeComments\": false,\n        \"noLib\": false,\n        \"emitDecoratorMetadata\": true,\n        \"experimentalDecorators\": true,\n        \"useUnknownInCatchVariables\": false,\n        \"target\": \"ES2021\",\n        \"sourceMap\": false,\n        \"allowJs\": false,\n        \"strict\": true,\n        \"strictNullChecks\": false,\n        \"types\": [\n            \"node\"\n        ]\n    }\n}\n"
  },
  {
    "path": "packages/tsconfig.json",
    "content": "{\n    \"files\": [],\n    \"references\": [\n        {\n            \"path\": \"./cnpj/tsconfig.build.json\"\n        },\n        {\n            \"path\": \"./cpf/tsconfig.build.json\"\n        },\n        {\n            \"path\": \"./date/tsconfig.build.json\"\n        },\n        {\n            \"path\": \"./email/tsconfig.build.json\"\n        },\n        {\n            \"path\": \"./logger/tsconfig.build.json\"\n        },\n        {\n            \"path\": \"./password/tsconfig.build.json\"\n        },\n        {\n            \"path\": \"./patterns/tsconfig.build.json\"\n        },\n        {\n            \"path\": \"./phone/tsconfig.build.json\"\n        },\n        {\n            \"path\": \"./type-ddd/tsconfig.build.json\"\n        },\n        {\n            \"path\": \"./username/tsconfig.build.json\"\n        },\n        {\n            \"path\": \"./zip-code/tsconfig.build.json\"\n        },\n        {\n            \"path\": \"./money/tsconfig.build.json\"\n        }\n    ]\n}"
  },
  {
    "path": "packages/type-ddd/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.0.7-alpha.0](https://github.com/4lessandrodev/type-ddd/compare/@type-ddd/core@0.0.2...@type-ddd/core@0.0.7-alpha.0) (2024-12-16)\n\n\n\n## 4.0.5 (2024-11-28)\n\n\n### Bug Fixes\n\n* change type create method return null [#194](https://github.com/4lessandrodev/type-ddd/issues/194) ([2cd03bf](https://github.com/4lessandrodev/type-ddd/commit/2cd03bf34387f4889a0a292ba350f2c0cfc753b7))\n* export money ([633577e](https://github.com/4lessandrodev/type-ddd/commit/633577eb6aeb4aa7389d747f1b076a042a5e8b22))\n* solve error module not found [#449](https://github.com/4lessandrodev/type-ddd/issues/449) ([e9d14f6](https://github.com/4lessandrodev/type-ddd/commit/e9d14f694cafc9c2123cc31055a4561f460a82d3))\n\n\n\n\n\n# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n## Unreleased\n\n---\n\n## Released\n\n---\n\n### [0.0.5] - 2024-11-28\n\n### Fix\n\n- update rich-domain lib to check nullish type: now 'create' return a possibly null value in Result instance.\n\n### [0.0.4] - 2024-09-26\n\n### Fix\n\n- Corrected `\"files\"` in `package.json` to include `utils.js` and `utils.d.ts`, resolving module not found errors during compilation in email and password.\n\n---\n\n### [0.0.3] - 2024-05-31\n\n### Fix\n\n- Fix: export money v.o\n\n---\n\n### [0.0.2] - 2024-05-31\n\n### Fix\n\n- Fix: add individual package version instead link\n\n---\n\n### [0.0.1] - 2024-05-31\n\n### Base\n\n- Create base value object as single pack\n"
  },
  {
    "path": "packages/type-ddd/README.md",
    "content": "# `@type-ddd/core`\n\n> The @type-ddd/core library provides TypeScript type definitions for handling utils value object in Domain-Driven Design contexts. It facilitates the validation and manipulation, ensuring they adhere to standards.\n\n---\n\n## Installation\n\nInstall `rich-domain` and `@type-ddd/core` with your favorite package manager\n\n```sh\n\nnpm i rich-domain @type-ddd/core\n\n# OR\n\nyarn add rich-domain @type-ddd/core\n\n```\n\n## Packages\n\n- \"@type-ddd/cpf\"\n- \"@type-ddd/cnpj\"\n- \"@type-ddd/date\"\n- \"@type-ddd/email\"\n- \"@type-ddd/password\"\n- \"@type-ddd/patterns\"\n- \"@type-ddd/phone\"\n- \"@type-ddd/username\"\n- \"@type-ddd/zip-code\"\n- \"@type-ddd/money\"\n"
  },
  {
    "path": "packages/type-ddd/index.ts",
    "content": "export * from 'rich-domain';\nexport * from \"@type-ddd/cpf\";\nexport * from \"@type-ddd/cnpj\";\nexport * from \"@type-ddd/date\";\nexport * from \"@type-ddd/email\";\nexport * from \"@type-ddd/password\";\nexport * from \"@type-ddd/patterns\";\nexport * from \"@type-ddd/phone\";\nexport * from \"@type-ddd/username\";\nexport * from \"@type-ddd/zip-code\";\nexport * from '@type-ddd/money';\n"
  },
  {
    "path": "packages/type-ddd/package.json",
    "content": "{\n  \"name\": \"@type-ddd/core\",\n  \"description\": \"This package provide utils file and interfaces to assistant build a complex application with domain driving design\",\n  \"version\": \"0.1.0\",\n  \"main\": \"index.js\",\n  \"types\": \"index.d.ts\",\n  \"author\": \"Alessandro Dev\",\n  \"license\": \"MIT\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\"\n  },\n  \"dependencies\": {\n    \"@type-ddd/cnpj\": \"^0.1.0\",\n    \"@type-ddd/cpf\": \"^0.1.0\",\n    \"@type-ddd/date\": \"^0.1.0\",\n    \"@type-ddd/email\": \"^0.1.0\",\n    \"@type-ddd/money\": \"^0.1.0\",\n    \"@type-ddd/password\": \"^0.1.0\",\n    \"@type-ddd/patterns\": \"^0.1.0\",\n    \"@type-ddd/phone\": \"^0.1.0\",\n    \"@type-ddd/username\": \"^0.1.0\",\n    \"@type-ddd/zip-code\": \"^0.1.0\",\n    \"rich-domain\": \"^1.25.0\"\n  },\n  \"files\": [\n    \"index.js\",\n    \"index.d.ts\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/4lessandrodev/type-ddd.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/4lessandrodev/type-ddd/issues\"\n  },\n  \"homepage\": \"https://github.com/4lessandrodev/type-ddd/tree/main\",\n  \"gitHead\": \"4cb9159bde8d6fc951e9d902feed2ad25da49fa4\"\n}\n"
  },
  {
    "path": "packages/type-ddd/tsconfig.build.json",
    "content": "{\n    \"extends\": \"../tsconfig.build.json\",\n    \"compilerOptions\": {\n        \"outDir\": \".\",\n        \"rootDir\": \".\",\n        \"paths\": {}\n    },\n    \"exclude\": [\n        \"node_modules\",\n        \"dist\",\n        \"__tests__/**/*\",\n        \"*.spec.ts\"\n    ],\n    \"references\": []\n}"
  },
  {
    "path": "packages/type-ddd/tsconfig.json",
    "content": "{\n\t\"extends\": \"../tsconfig.build.json\",\n\t\"compilerOptions\": {\n\t\t\"types\": [\n\t\t\t\"node\"\n\t\t]\n\t},\n\t\"files\": [],\n\t\"include\": [],\n\t\"references\": [\n\t\t{\n\t\t\t\"path\": \"./tsconfig.build.json\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "packages/username/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.0.4-alpha.0](https://github.com/4lessandrodev/type-ddd/compare/@type-ddd/username@0.0.2...@type-ddd/username@0.0.4-alpha.0) (2024-12-16)\n\n\n\n## 4.0.5 (2024-11-28)\n\n\n### Bug Fixes\n\n* change type create method return null [#194](https://github.com/4lessandrodev/type-ddd/issues/194) ([2cd03bf](https://github.com/4lessandrodev/type-ddd/commit/2cd03bf34387f4889a0a292ba350f2c0cfc753b7))\n\n\n\n## 4.0.3 (2024-07-26)\n\n\n\n\n\n# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n## Unreleased\n\n---\n\n## Released\n\n---\n\n### [0.0.3] - 2024-11-28\n\n### Fix\n\n- update rich-domain lib to check nullish type: now 'create' return a possibly null value in Result instance.\n\n### [0.0.2] - 2024-05-31\n\n### Docs\n\n- Doc: update documentation\n\n---\n\n### [0.0.1] - 2024-05-31\n\n### Base\n\n- Create base value object as single pack\n"
  },
  {
    "path": "packages/username/README.md",
    "content": "# `@type-ddd/username`\n\n> The @type-ddd/username library provides TypeScript type definitions for handling User Name in Domain-Driven Design contexts. It facilitates the validation and manipulation of Person Name standards.\n\n---\n\n## Installation\n\nInstall `rich-domain` and `@type-ddd/username` with your favorite package manager\n\n```sh\n\nnpm i rich-domain @type-ddd/username\n\n# OR\n\nyarn add rich-domain @type-ddd/username\n\n```\n\n## Usage\n\n```ts\n\nimport { UserName } from '@type-ddd/username'\n\n// Instance of name or throws an error if provide an invalid value\nconst name = UserName.init('jane doe');\n\n// OR\n\n// Result of name (Check Result pattern docs)\nconst result = UserName.create('jane doe');\n\nresult.isOk(); // true\n\n// userName instance or null if provide an invalid value\nconst name = result.value();\n\n```\n\n## Check string is valid name\n\n```ts\n\nconst result = UserName.isValid('jane doe');\n\n// Output: true\n\n```\n\n## Utils\n\nsome utils methods\n\n```ts\n\nconst fullName = UserName.init('jane doe spencer')\n\nconst initials = fullName.initials();\n// JDS\n\nconst middle = fullName.middleName();\n// Doe\n\nconst first = fullName.firstName();\n// Jane\n\nconst firstWithTitle = fullName.title('Sra.').firstName();\n// Sra. Jane\n\nconst last = fullName.lastName();\n// Spencer\n\nconst upper = fullName.upperCase();\n// JANE DOE SPENCER\n\n```\n"
  },
  {
    "path": "packages/username/__tests__/user-name-value-object.util.spec.ts",
    "content": "import UserName from '../index'\n\ndescribe('user-name.value-object', () => {\n\tit('should be defined', () => {\n\t\tconst username = UserName.create;\n\t\texpect(username).toBeDefined();\n\t});\n\n\tit('should create a valid user name', () => {\n\t\tconst username = UserName.create('valid username');\n\t\texpect(username.isOk()).toBeTruthy();\n\t});\n\n\tit('should get value', () => {\n\t\tconst username = UserName.create('valid username').value();\n\t\texpect(username?.value()).toBe('Valid Username');\n\t});\n\n\tit('should fail if provide a long name (41) chars', () => {\n\t\tconst username = UserName.create(\n\t\t\t'invalid_username'.repeat(10),\n\t\t);\n\t\texpect(username.isFail()).toBe(true);\n\t});\n\n\tit('should fail if provide a small name (1) char', () => {\n\t\tconst username = UserName.create('i');\n\t\texpect(username.isFail()).toBe(true);\n\t});\n\n\tit('should get first name with success', () => {\n\t\tconst username =\n\t\t\tUserName.create('first middle last').value();\n\t\texpect(username?.firstName()).toBe('First');\n\t});\n\n\tit('should check if has last name [false]', () => {\n\t\tconst username = UserName.create('first').value();\n\t\texpect(username?.hasLastName()).toBe(false);\n\t});\n\n\tit('should check if has last name [true]', () => {\n\t\tconst username =\n\t\t\tUserName.create('first middle last').value();\n\t\texpect(username?.hasLastName()).toBe(true);\n\t});\n\n\tit('should check if has last name [true]', () => {\n\t\tconst username = UserName.create('first last').value();\n\t\texpect(username?.hasLastName()).toBe(true);\n\t});\n\n\tit('should check if has middle name [false]', () => {\n\t\tconst username = UserName.create('first').value();\n\t\texpect(username?.hasMiddleName()).toBe(false);\n\t});\n\n\tit('should check if has middle name [true]', () => {\n\t\tconst username =\n\t\t\tUserName.create('first middle last').value();\n\t\texpect(username?.hasMiddleName()).toBe(true);\n\t});\n\n\tit('should get first name', () => {\n\t\tconst username = UserName.create('first middle last').value();\n\t\texpect(username?.firstName()).toBe('First');\n\t});\n\n\tit('should get first name', () => {\n\t\tconst username = UserName.create('first middle').value();\n\t\texpect(username?.firstName()).toBe('First');\n\t});\n\n\tit('should get first name', () => {\n\t\tconst username = UserName.create('first').value();\n\t\texpect(username?.firstName()).toBe('First');\n\t});\n\n\tit('should get middle name', () => {\n\t\tconst username = UserName.create('first middle last').value();\n\t\texpect(username?.middleName()).toBe('Middle');\n\t});\n\n\tit('should NOT get middle name', () => {\n\t\tconst username = UserName.create('first last').value();\n\t\texpect(username?.middleName()).toBe('');\n\t});\n\n\tit('should get last name', () => {\n\t\tconst username = UserName.create('first last').value();\n\t\texpect(username?.lastName()).toBe('Last');\n\t});\n\n\tit('should return the first if does not exist last name', () => {\n\t\tconst username = UserName.create('FIRST').value();\n\t\texpect(username?.lastName()).toBe('First');\n\t});\n\n\tit('should capitalize names', () => {\n\t\tconst username = UserName.create('first middle last').value();\n\t\texpect(username?.value()).toBe('First Middle Last');\n\t});\n\n\tit('should capitalize names', () => {\n\t\tconst username = UserName.create('FIRST MIDDLE LAST').value();\n\t\texpect(username?.value()).toBe('First Middle Last');\n\t\texpect(username?.get('value')).toBe('First Middle Last');\n\t});\n\n\tit('should get initials', () => {\n\t\tconst username = UserName.create('FIRST MIDDLE LAST').value();\n\t\texpect(username?.initials()).toBe('FML');\n\t});\n\n\tit('should get initials with custom separator', () => {\n\t\tconst separator = '-';\n\t\tconst username = UserName.create('FIRST MIDDLE LAST').value();\n\t\texpect(username?.initials(separator)).toBe('F-M-L');\n\t});\n\n\tit('should get initials with none separator', () => {\n\t\tconst separator = '.';\n\t\tconst username = UserName.create('FIRST MIDDLE LAST').value();\n\t\texpect(username?.initials(separator)).toBe('F.M.L');\n\t});\n\n\tit('should get initials', () => {\n\t\tconst username = UserName.create('FIRSt').value();\n\t\texpect(username?.initials()).toBe('F');\n\t});\n\n\tit('should name with duple spaces', () => {\n\t\tconst username = UserName.create(\n\t\t\t'José caleb  dos Santos',\n\t\t).value();\n\t\texpect(username?.value()).toBe('José Caleb Dos Santos');\n\t});\n\n\tit('should name with duple spaces and two character \"de\" ', () => {\n\t\tconst username = UserName.create(\n\t\t\t'José caleb  de Oliveira',\n\t\t).value();\n\t\texpect(username?.value()).toBe('José Caleb De Oliveira');\n\t});\n\n\tit('should name with duple spaces and two character specials ', () => {\n\t\tconst username = UserName.create(\n\t\t\t'José caleb , de Oliveira',\n\t\t).value();\n\t\texpect(username?.value()).toBe('José Caleb De Oliveira');\n\t});\n\n\tit('should name with three spaces in name', () => {\n\t\tconst username = UserName.create(\n\t\t\t'José caleb   de Oliveira',\n\t\t).value();\n\t\texpect(username?.value()).toBe('José Caleb De Oliveira');\n\t});\n\n\tit('should init an instance with success', () => {\n\t\tconst init = () => UserName.init('lorem ipsum');\n\t\texpect(init).not.toThrowError();\n\t});\n\n\tit('should throw an error on init an instance with invalid value', () => {\n\t\tconst init = () => UserName.init('');\n\t\texpect(init).toThrowError();\n\t});\n\n\tit('should capitalize a full name', () => {\n\t\tconst value = UserName.capitalize('jane doe');\n\t\texpect(value).toBe('Jane Doe');\n\t});\n\n\tit('should uppercase value', () => {\n\t\tconst name = UserName.init('jane doe');\n\t\tconst value = name.upperCase();\n\t\texpect(value).toBe('JANE DOE');\n\t});\n\n\tit('should lowercase value', () => {\n\t\tconst name = UserName.init('JaNe DOE');\n\t\tconst value = name.lowerCase();\n\t\texpect(value).toBe('jane doe');\n\t});\n\n\tit('should validate user name', () => {\n\t\texpect(UserName.isValid('jane doe')).toBeTruthy();\n\t\texpect(UserName.isValid('')).toBeFalsy();\n\t});\n\n\tit('should add title', () => {\n\t\tconst name = UserName.init('Juliana Paes Moreira');\n\t\texpect(name.title('Sra.').firstName()).toBe('Sra. Juliana');\n\t\texpect(name.title('Sra.').fullName()).toBe('Sra. Juliana Paes Moreira');\n\t\texpect(name.title('Sra.').lastName()).toBe('Sra. Moreira');\n\t\texpect(name.title('Sra.').middleName()).toBe('Sra. Paes');\n\n\t})\n});\n"
  },
  {
    "path": "packages/username/index.ts",
    "content": "import { Result, ValueObject } from 'rich-domain';\n\nexport class UserName extends ValueObject<string> {\n\tprotected static readonly MAX_LENGTH: number = 82;\n\tprotected static readonly MIN_LENGTH: number = 2;\n\tprotected static readonly MESSAGE: string = `Invalid name length. Must has min ${UserName.MIN_LENGTH} and max ${UserName.MAX_LENGTH} chars`;\n\n\tprivate constructor(props: string) {\n\t\tsuper(props);\n\t}\n\n\t/**\n\t * @returns capitalized full name\n\t */\n\tvalue(): string {\n\t\treturn this.props.trim();\n\t}\n\n\t/**\n\t *\n\t * @returns capitalize full name as string\n\t */\n\tpublic static capitalize(fullName: string): string {\n\t\tconst names = fullName.split(' ').filter((name): boolean => {\n\t\t\treturn name.length > 1;\n\t\t});\n\n\t\tconst capitalizedName = (name: string): string => {\n\t\t\treturn name[0].toUpperCase() + name.slice?.(1)?.toLowerCase();\n\t\t};\n\n\t\tconst capitalized: string[] = [];\n\t\tfor (const name of names) {\n\t\t\tconst lowerCaseName = capitalizedName(name);\n\t\t\tcapitalized.push(lowerCaseName);\n\t\t}\n\n\t\treturn capitalized.toString().replace(/,/g, ' ');\n\t}\n\n\t/**\n\t * @description get upper case name from instance\n\t * @returns upperCase full name as string\n\t */\n\tupperCase(): string {\n\t\treturn this.props.toUpperCase();\n\t}\n\n\t/**\n\t * @description get lower case name from instance\n\t * @returns lowerCase full name as string\n\t */\n\tlowerCase(): string {\n\t\treturn this.props.toLowerCase();\n\t}\n\n\t/**\n\t *\n\t * @returns check if has a second name\n\t */\n\thasMiddleName(): boolean {\n\t\treturn this.props.split(' ').length > 2;\n\t}\n\n\ttitle(title: string) {\n\t\treturn {\n\t\t\tfirstName: (): string => title + ' ' + this.firstName(),\n\t\t\tfullName: (): string => title + ' ' + this.value(),\n\t\t\tlastName: (): string => title + ' ' + this.lastName(),\n\t\t\tmiddleName: (): string => title + ' ' + this.middleName(),\n\t\t}\n\t}\n\n\t/**\n\t *\n\t * @returns check if has last name `first middle last`\n\t */\n\thasLastName(): boolean {\n\t\treturn this.props.split(' ').length >= 2;\n\t}\n\n\t/**\n\t *\n\t * @returns first name\n\t */\n\tfirstName(title: string = ''): string {\n\t\treturn (title + ' ' + this.props.split(' ')[0])?.trim();\n\t}\n\n\t/**\n\t *\n\t * @returns middle name if it has more than 2 names, else returns a empty string\n\t */\n\tmiddleName(): string {\n\t\tif (!this.hasMiddleName()) {\n\t\t\treturn '';\n\t\t}\n\t\treturn this.props.split(' ')[1]?.trim();\n\t}\n\n\t/**\n\t *\n\t * @returns last name if exists else return the name\n\t */\n\tlastName(): string {\n\t\tconst names = this.props.split(' ');\n\t\treturn names.at(-1)?.trim();\n\t}\n\n\t/**\n\t * @returns initials as string\n\t * @param separator as string char to separate letters\n\t * @default separator (empty)\n\t * @example\n\t * for a name \"Thomas A. Anderson\" = \"TAA\"\n\t */\n\tinitials(separator = ''): string {\n\t\tconst names = this.props.split(' ');\n\t\tconst letters = names.map((name): string => name[0]);\n\t\tconst value = this.util.string(letters.toString());\n\n\t\tconst initials = value.replace(',').to(separator);\n\n\t\treturn initials;\n\t}\n\n\t/**\n\t * \n\t * @param value value as string\n\t * @returns instance of UserName or throw an error\n\t */\n\tpublic static init(value: string): UserName {\n\t\tconst isValidValue = UserName.isValidProps(value);\n\t\tif (!isValidValue) throw new Error(UserName.MESSAGE);\n\t\tconst capitalized = UserName.capitalize(value);\n\t\treturn new UserName(capitalized);\n\t}\n\n\t/**\n\t * @description check name length min(2) max(40)\n\t * @param value name as string\n\t * @returns true if provided value is valid and false if not\n\t */\n\tpublic static isValid(value: string): boolean {\n\t\treturn this.isValidProps(value);\n\t}\n\n\t/**\n\t * @description check name length min(2) max(40)\n\t * @param value name as string\n\t * @returns true if provided value is valid and false if not\n\t */\n\tpublic static isValidProps(value: string): boolean {\n\t\tconst { string } = this.validator;\n\t\treturn string(value).hasLengthBetween(\n\t\t\tUserName.MIN_LENGTH,\n\t\t\tUserName.MAX_LENGTH,\n\t\t);\n\t}\n\n\tpublic static create(value: string): Result<UserName | null> {\n\t\tconst isValidValue = UserName.isValidProps(value);\n\t\tif (!isValidValue) {\n\t\t\treturn Result.fail(UserName.MESSAGE);\n\t\t}\n\t\tconst capitalized = UserName.capitalize(value);\n\t\treturn Result.Ok(new UserName(capitalized));\n\t}\n}\n\nexport default UserName;\n"
  },
  {
    "path": "packages/username/package.json",
    "content": "{\n  \"name\": \"@type-ddd/username\",\n  \"description\": \"This package provides TypeScript type definitions for handling User Name in Domain-Driven Design contexts\",\n  \"version\": \"0.1.0\",\n  \"main\": \"index.js\",\n  \"types\": \"index.d.ts\",\n  \"author\": \"Alessandro Dev\",\n  \"license\": \"MIT\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"keywords\": [\n    \"Complexity\",\n    \"Business Logic\",\n    \"DDD\",\n    \"Domain Driving Design\",\n    \"DDD-Utils\",\n    \"Base Value Object\",\n    \"Domain Events\",\n    \"Clean Architecture\",\n    \"User Name\",\n    \"Validation\",\n    \"Formatting\",\n    \"Value Object\",\n    \"Utility\",\n    \"Security\",\n    \"Standards\"\n  ],\n  \"scripts\": {\n    \"build\": \"tsc\"\n  },\n  \"peerDependencies\": {\n    \"rich-domain\": \"^1.25.0\"\n  },\n  \"files\": [\n    \"index.js\",\n    \"index.d.ts\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/4lessandrodev/type-ddd.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/4lessandrodev/type-ddd/issues\"\n  },\n  \"homepage\": \"https://github.com/4lessandrodev/type-ddd/tree/main/packages/username\",\n  \"gitHead\": \"4cb9159bde8d6fc951e9d902feed2ad25da49fa4\"\n}\n"
  },
  {
    "path": "packages/username/tsconfig.build.json",
    "content": "{\n    \"extends\": \"../tsconfig.build.json\",\n    \"compilerOptions\": {\n        \"outDir\": \".\",\n        \"rootDir\": \".\",\n        \"paths\": {}\n    },\n    \"exclude\": [\n        \"node_modules\",\n        \"dist\",\n        \"__tests__/**/*\",\n        \"*.spec.ts\"\n    ],\n    \"references\": []\n}"
  },
  {
    "path": "packages/username/tsconfig.json",
    "content": "{\n\t\"extends\": \"../tsconfig.build.json\",\n\t\"compilerOptions\": {\n\t\t\"types\": [\n\t\t\t\"node\"\n\t\t]\n\t},\n\t\"files\": [],\n\t\"include\": [],\n\t\"references\": [\n\t\t{\n\t\t\t\"path\": \"./tsconfig.build.json\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "packages/zip-code/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.0.4-alpha.0](https://github.com/4lessandrodev/type-ddd/compare/@type-ddd/zip-code@0.0.2...@type-ddd/zip-code@0.0.4-alpha.0) (2024-12-16)\n\n\n\n## 4.0.5 (2024-11-28)\n\n\n### Bug Fixes\n\n* change type create method return null [#194](https://github.com/4lessandrodev/type-ddd/issues/194) ([2cd03bf](https://github.com/4lessandrodev/type-ddd/commit/2cd03bf34387f4889a0a292ba350f2c0cfc753b7))\n\n\n\n## 4.0.3 (2024-07-26)\n\n\n\n\n\n# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n## Unreleased\n\n---\n\n## Released\n\n---\n\n### [0.0.3] - 2024-11-28\n\n### Fix\n\n- update rich-domain lib to check nullish type: now 'create' return a possibly null value in Result instance.\n\n### [0.0.2] - 2024-05-31\n\n### Docs\n\n- Doc: update documentation\n\n---\n\n### [0.0.1] - 2024-05-31\n\n### Base\n\n- Create base value object as single pack\n"
  },
  {
    "path": "packages/zip-code/README.md",
    "content": "# `@type-ddd/zip-code`\n\n> The @type-ddd/cpf library provides TypeScript type definitions for handling ZipCode in Domain-Driven Design contexts. It facilitates the validation and manipulation of ZipCode numbers, ensuring they adhere to the Brazilian legal standards.\n\n---\n\n## Installation\n\nInstall `rich-domain` and `@type-ddd/zip-code` with your favorite package manager\n\n```sh\n\nnpm i rich-domain @type-ddd/zip-code\n\n# OR\n\nyarn add rich-domain @type-ddd/zip-code\n\n```\n\n## Usage\n\nDon't worry about removing special characters; they are automatically stripped from all instances.\n\n```ts\n\nimport { ZipCode } from '@type-ddd/zip-code'\n\n// Instance of zipCode or throws an error if provide an invalid value\nconst zipCode = ZipCode.init('75520140');\n\n// OR\n\n// Result of zipCode (Check Result pattern docs)\nconst result = ZipCode.create('75520140');\n\nresult.isOk(); // true\n\n// zipCode instance or null if provide an invalid value\nconst zipCode = result.value();\n\n```\n\n## Check string is valid zipCode\n\nDon't worry about removing special characters; they are automatically stripped from all instances.\n\n```ts\n\nconst result = ZipCode.isValid('75520140');\n// Output: true\n\n```\n\n## Special chars\n\nIf you need the value with the mask, you can use the `toPattern` method:\n\n```ts\n\nzipCode.toPattern();\n\n// Output: 75520-140\n\n```\n\nOr if you need to apply mask from a string value you may use `addMask` method\n\n\n```ts\n\nZipCode.addMask('75520140');\n\n// Output: 75520-140\n\n```\n"
  },
  {
    "path": "packages/zip-code/__tests__/zip-code.value-object.spec.ts",
    "content": "import { ZipCode as ZipCodeValueObject } from '../index'\n\n\ndescribe('postal-code.value-object', () => {\n\tit('should be defined', () => {\n\t\tconst valueObject = ZipCodeValueObject.create;\n\t\texpect(valueObject).toBeDefined();\n\t});\n\n\tit('should create a valid zip code', () => {\n\t\tconst valueObject = ZipCodeValueObject.create('75520140');\n\t\texpect(valueObject.isOk()).toBeTruthy();\n\t});\n\n\tit('should create a valid zip code', () => {\n\t\tconst value = ZipCodeValueObject.init('75520140');\n\t\texpect(value.toPattern()).toBe('75520-140');\n\t});\n\n\tit('should create a valid zip code', () => {\n\t\tconst isValid = ZipCodeValueObject.isValid('75520140');\n\t\texpect(isValid).toBeTruthy();\n\t});\n\n\tit('should get value', () => {\n\t\tconst valueObject = ZipCodeValueObject.create('75520140').value();\n\t\texpect(valueObject?.value()).toBe('75520140');\n\t});\n\n\tit('should get value without hyphen', () => {\n\t\tconst valueObject = ZipCodeValueObject.create('75520-140').value();\n\t\texpect(valueObject?.value()).toBe('75520140');\n\t});\n\n\tit('should fail if provide an invalid postal code', () => {\n\t\tconst valueObject = ZipCodeValueObject.create('invalid');\n\t\texpect(valueObject.isOk()).toBe(false);\n\t});\n\n\n\tit('should init an instance with success', () => {\n\t\tconst init = () => ZipCodeValueObject.init('05583-000');\n\t\texpect(init).not.toThrowError();\n\t});\n\n\tit('should throw an error on init an instance with invalid value', () => {\n\t\tconst init = () => ZipCodeValueObject.init('');\n\t\texpect(init).toThrowError();\n\t});\n\n\tit('should add mask', () => {\n\t\tconst masked = ZipCodeValueObject.addMask('05583000');\n\t\texpect(masked).toBe('05583-000');\n\t});\n\n\tit('should add mask', () => {\n\t\tconst masked = ZipCodeValueObject.addMask('05583-000');\n\t\texpect(masked).toBe('05583-000');\n\t});\n\n\tit('should add mask', () => {\n\t\tconst masked = ZipCodeValueObject.addMask('05583-00000');\n\t\texpect(masked).toBe('05583-000');\n\t});\n\n\tit('should add mask', () => {\n\t\tconst masked = ZipCodeValueObject.addMask('0558300000');\n\t\texpect(masked).toBe('05583-000');\n\t});\n\n\tit('should add mask', () => {\n\t\tconst masked = ZipCodeValueObject.addMask(5 as any);\n\t\texpect(masked).toBe('');\n\t});\n});\n"
  },
  {
    "path": "packages/zip-code/index.ts",
    "content": "import { Result, ValueObject } from 'rich-domain';\n\nconst regexHash = /^[0-9]{5}-[0-9]{3}$|^[0-9]{8}$/;\n\nclass ZipCode extends ValueObject<string> {\n\tprotected static readonly REGEX = regexHash;\n\tprotected static readonly MESSAGE: string = 'Invalid zip code';\n\n\tprivate constructor(prop: string) {\n\t\tsuper(prop);\n\t}\n\n\t/**\n\t * @returns value as string. always only numbers\n\t * @example 75520140\n\t */\n\tvalue(): string {\n\t\treturn this.props;\n\t}\n\n\t/**\n\t * @description add hyphen and dot to cpf value.\n\t * @example before \"75520140\"\n\t * @example after \"75520-140\"\n\t */\n\tpublic static addMask(zipCode: string): string {\n\t\tif (typeof zipCode !== 'string') return '';\n\t\tif (zipCode.includes('-')) return zipCode.slice(0, 9);\n\t\treturn zipCode.slice(0, 5) + '-' + zipCode.slice(5, 8);\n\t}\n\n\t/**\n\t * @description remove hyphen and dot from cpf value.\n\t * @example before \"75520-140\"\n\t * @example after \"75520140\"\n\t */\n\tpublic static removeSpecialChars(zipCode: string): string {\n\t\treturn this.util.string(zipCode).removeSpecialChars();\n\t}\n\n\t/**\n\t * @description add special chars to numbers\n\t * @returns zip code as string following pattern xxxxx-xxx\n\t */\n\ttoPattern(): string {\n\t\treturn ZipCode.addMask(this.props);\n\t}\n\n\t/**\n\t *\n\t * @param value PostalCode as string\n\t * @returns true if value match with pattern and false if do not.\n\t */\n\tpublic static isValid(value: string): boolean {\n\t\treturn this.isValidProps(value);\n\t}\n\n\t/**\n\t *\n\t * @param value PostalCode as string\n\t * @returns true if value match with pattern and false if do not.\n\t */\n\tpublic static isValidProps(value: string): boolean {\n\t\treturn this.validator.string(value).match(ZipCode.REGEX);\n\t}\n\n\t/**\n\t * \n\t * @param value value as string\n\t * @returns instance of ZipCode or throw an error\n\t */\n\tpublic static init(value: string): ZipCode {\n\t\tconst isValidValue = ZipCode.isValidProps(value);\n\t\tif (!isValidValue) throw new Error(ZipCode.MESSAGE);\n\t\tconst numbers = ZipCode.removeSpecialChars(value);\n\t\treturn new ZipCode(numbers);\n\t}\n\n\n\tpublic static create(value: string): Result<ZipCode | null> {\n\t\tif (!ZipCode.isValidProps(value)) {\n\t\t\treturn Result.fail(ZipCode.MESSAGE);\n\t\t}\n\t\tconst numbers = ZipCode.removeSpecialChars(value);\n\t\treturn Result.Ok(new ZipCode(numbers));\n\t}\n}\n\nexport { ZipCode };\nexport default ZipCode;\n"
  },
  {
    "path": "packages/zip-code/package.json",
    "content": "{\n  \"name\": \"@type-ddd/zip-code\",\n  \"description\": \"This package provides TypeScript type definitions for handling Brazilian Zip Code in Domain-Driven Design contexts\",\n  \"version\": \"0.1.0\",\n  \"main\": \"index.js\",\n  \"types\": \"index.d.ts\",\n  \"author\": \"Alessandro Dev\",\n  \"license\": \"MIT\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"keywords\": [\n    \"Complexity\",\n    \"Business Logic\",\n    \"DDD\",\n    \"Domain Driving Design\",\n    \"DDD-Utils\",\n    \"Base Value Object\",\n    \"Domain Events\",\n    \"Clean Architecture\",\n    \"ZipCode\",\n    \"Validation\",\n    \"Formatting\",\n    \"Value Object\",\n    \"Utility\",\n    \"Security\",\n    \"Standards\",\n    \"Brazil\"\n  ],\n  \"scripts\": {\n    \"build\": \"tsc\"\n  },\n  \"peerDependencies\": {\n    \"rich-domain\": \"^1.25.0\"\n  },\n  \"files\": [\n    \"index.js\",\n    \"index.d.ts\",\n    \"util.js\",\n    \"util.d.ts\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/4lessandrodev/type-ddd.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/4lessandrodev/type-ddd/issues\"\n  },\n  \"homepage\": \"https://github.com/4lessandrodev/type-ddd/tree/main/packages/zip-code\",\n  \"gitHead\": \"4cb9159bde8d6fc951e9d902feed2ad25da49fa4\"\n}\n"
  },
  {
    "path": "packages/zip-code/tsconfig.build.json",
    "content": "{\n    \"extends\": \"../tsconfig.build.json\",\n    \"compilerOptions\": {\n        \"outDir\": \".\",\n        \"rootDir\": \".\",\n        \"paths\": {}\n    },\n    \"exclude\": [\n        \"node_modules\",\n        \"dist\",\n        \"__tests__/**/*\",\n        \"*.spec.ts\"\n    ],\n    \"references\": []\n}"
  },
  {
    "path": "packages/zip-code/tsconfig.json",
    "content": "{\n\t\"extends\": \"../tsconfig.build.json\",\n\t\"compilerOptions\": {\n\t\t\"types\": [\n\t\t\t\"node\"\n\t\t]\n\t},\n\t\"files\": [],\n\t\"include\": [],\n\t\"references\": [\n\t\t{\n\t\t\t\"path\": \"./tsconfig.build.json\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "packages/zip-code/util.ts",
    "content": "interface CpfDigits {\n\tpenultimateDigit: number;\n\tultimateDigit: number;\n}\n\nconst removeSpecialCharsFromCpfRegex = /[\\.]|[-]/g;\n\nexport const formatValueToCpfPattern = (cpf: string): string => {\n\tconst cpfValue = removeSpecialCharsFromCpf(cpf);\n\tlet formattedValue: string = '';\n\tlet index: number = 0;\n\n\twhile (formattedValue.length < 14 && index < 11) {\n\t\tif (index === 3 || index === 6) {\n\t\t\tformattedValue += '.';\n\t\t} else if (index === 9) {\n\t\t\tformattedValue += '-';\n\t\t}\n\t\tformattedValue += cpfValue[index];\n\t\tindex++;\n\t}\n\n\treturn formattedValue;\n};\n\nexport const removeSpecialCharsFromCpf = (cpf: string): string => {\n\treturn cpf.replace(removeSpecialCharsFromCpfRegex, '');\n};\n\nconst getCpfDigitsNumbers = (cpf: string): CpfDigits => {\n\tconst lastTwoNumbers = cpf.slice(cpf.length - 2);\n\tconst penultimateDigit = parseInt(lastTwoNumbers[0]);\n\tconst ultimateDigit = parseInt(lastTwoNumbers[1]);\n\n\treturn {\n\t\tpenultimateDigit,\n\t\tultimateDigit,\n\t};\n};\n\nconst transformCpfInArrNumber = (cpf: string): number[] => {\n\tvar arr: number[] = [];\n\n\tlet index = 0;\n\twhile (index < 9) {\n\t\tarr.push(parseInt(cpf[index]));\n\t\tindex++;\n\t}\n\n\treturn arr;\n};\n\nexport const calculateCpfDigits = (cpfNumbers: number[]): CpfDigits => {\n\tconst factor = 11;\n\tlet index = 0;\n\tlet startAuxValue = 10;\n\tlet totalForDigit = 0;\n\n\twhile (index < 9) {\n\t\ttotalForDigit = totalForDigit + cpfNumbers[index] * startAuxValue;\n\t\tstartAuxValue--;\n\t\tindex++;\n\t}\n\n\tconst calcPDigit = totalForDigit % factor;\n\tconst resultPDigit = factor - calcPDigit;\n\tconst zeroIfPGreaterThanNine = resultPDigit > 9 ? 0 : resultPDigit;\n\tconst penultimateDigit = zeroIfPGreaterThanNine;\n\n\tindex = 0;\n\tstartAuxValue = 11;\n\ttotalForDigit = 0;\n\n\tcpfNumbers.push(penultimateDigit);\n\n\twhile (index < 10) {\n\t\ttotalForDigit = totalForDigit + cpfNumbers[index] * startAuxValue;\n\t\tstartAuxValue--;\n\t\tindex++;\n\t}\n\n\tconst calcUDigit = totalForDigit % factor;\n\tconst resultUDigit = factor - calcUDigit;\n\tconst zeroIfGreaterThanNine = resultUDigit > 9 ? 0 : resultUDigit;\n\tconst ultimateDigit = zeroIfGreaterThanNine;\n\n\treturn {\n\t\tpenultimateDigit,\n\t\tultimateDigit,\n\t};\n};\n\nexport const isValidCpfDigit = (cpf: string): boolean => {\n\tconst onlyNumbers = removeSpecialCharsFromCpf(cpf);\n\n\tif (onlyNumbers.length !== 11) {\n\t\treturn false;\n\t}\n\n\tconst digits = getCpfDigitsNumbers(onlyNumbers);\n\tconst arrNumbers = transformCpfInArrNumber(onlyNumbers);\n\tconst validDigits = calculateCpfDigits(arrNumbers);\n\n\treturn (\n\t\tdigits.penultimateDigit === validDigits.penultimateDigit &&\n\t\tdigits.ultimateDigit === validDigits.ultimateDigit\n\t);\n};\n\nexport default isValidCpfDigit;\n"
  },
  {
    "path": "scripts/login.sh",
    "content": "#!/usr/bin/expect -f\n\nset admin_user \"admin\"\nset admin_password \"admin\"\nset admin_email \"dev@localhost.com\"\nset registry_url \"http://localhost:4873/\"\nset specific_config \"config=local\"\n\nspawn npm login --registry=$registry_url\n\nexpect \"Username: \"\nsend \"$admin_user\\r\"\n\nexpect \"Password: \"\nsend \"$admin_password\\r\"\n\nsend \"$admin_email\\r\"\n\nexpect eof\n"
  },
  {
    "path": "scripts/make-user.sh",
    "content": "#!/bin/bash\n\nurl='http://localhost:4873/-/user/org.couchdb.user:admin'\n\nargs=(\n    \"//localhost:4873/:_auth=YWRtaW46YWRtaW4=\"\n    \"strict-ssl=false\"\n    \"email=dev@localhost.com\"\n    \"always-auth=true\"\n    \"init-author-name=dev\"\n    \"init-author-email=dev@localhost.com\"\n)\n\nresponse=$(curl -XPUT -H \"Content-type: application/json\" -d '{\"name\": \"admin\", \"password\": \"admin\"}' \"$url\")\n\ntoken=$(echo \"$response\" | grep -o '\"token\": \".*\"' | awk -F'\"' '{print $4}')\n\nif [[ $token ]]; then\n\n    for item in \"${args[@]}\"; do\n        echo \"$item\" >>.npmrc\n    done\n\n    echo \"//http://localhost:4873/:_authToken=$token\" >>.npmrc\n    echo \"\" >>.npmrc\n\n    echo \"Configurações salvas em .npmrc.\"\nelse\n    echo \"Erro na requisição. Resposta: $response\"\nfi\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n\t\"compilerOptions\": {\n\t\t\"module\": \"commonjs\",\n\t\t\"noImplicitAny\": false,\n\t\t\"noUnusedLocals\": false,\n\t\t\"removeComments\": true,\n\t\t\"noLib\": false,\n\t\t\"emitDecoratorMetadata\": true,\n\t\t\"experimentalDecorators\": true,\n\t\t\"useUnknownInCatchVariables\": false,\n\t\t\"target\": \"ES2021\",\n\t\t\"sourceMap\": true,\n\t\t\"allowJs\": false,\n\t\t\"outDir\": \"dist\",\n\t\t\"baseUrl\": \".\",\n\t\t\"paths\": {\n\t\t\t\"@type-ddd/cnpj\": [\"./packages/cnpj\"],\n\t\t\t\"@type-ddd/cpf\": [\"./packages/cpf\"],\n\t\t\t\"@type-ddd/date\": [\"./packages/date\"],\n\t\t\t\"@type-ddd/email\": [\"./packages/email\"],\n\t\t\t\"@type-ddd/logger\": [\"./packages/logger\"],\n\t\t\t\"@type-ddd/money\": [\"./packages/money\"],\n\t\t\t\"@type-ddd/password\": [\"./packages/password\"],\n\t\t\t\"@type-ddd/patterns\": [\"./packages/patterns\"],\n\t\t\t\"@type-ddd/phone\": [\"./packages/phone\"],\n\t\t\t\"@type-ddd/core\": [\"./packages/type-ddd\"],\n\t\t\t\"@type-ddd/username\": [\"./packages/username\"],\n\t\t\t\"@type-ddd/zip-code\": [\"./packages/zip-code\"]\n\t\t}\n\t},\n\t\"include\": [\"packages/**/*\"],\n\t\"exclude\": [\"node_modules\", \"**/*.spec.ts\", \"__tests__\"]\n}\n"
  },
  {
    "path": "update-peer-dependency.sh",
    "content": "#!/bin/bash\n\n# Update a specific peer dependency across all packages in the monorepo\n\n# Usage example:\n# in root folder execute:\n# ./update-peer-dependency.sh <lib-name> <version>\n# ./update-peer-dependency.sh rich-domain 1.25.0\n\n# Check if jq is installed\nif ! command -v jq &> /dev/null; then\n    echo \"Error: jq is not installed. Please install jq to proceed.\"\n    exit 1\nfi\n\n# Check if the correct number of arguments is provided\n# The script expects two arguments: the name of the dependency and the desired version.\nif [ \"$#\" -ne 2 ]; then\n    echo \"Usage: $0 <dependency> <version>\"\n    echo \"Example: $0 rich-domain 1.25.0-beta\"\n    exit 1\nfi\n\n# Assign the arguments to variables\nDEPENDENCY=$1   # The name of the dependency to be updated\nVERSION=$2      # The version to be set for the dependency\n\n# Directory where the packages are located. The script will look inside this directory.\nPACKAGES_DIR=\"./packages\"\n\n# Check if the /packages directory exists\nif [ ! -d \"$PACKAGES_DIR\" ]; then\n    echo \"The /packages directory does not exist! Please ensure the path is correct.\"\n    exit 1\nfi\n\n# Start the loop to iterate over all folders inside the /packages directory\nfor PACKAGE in $PACKAGES_DIR/*/; do\n    # Check if the current path is a directory\n    if [ -d \"$PACKAGE\" ]; then\n        # Build the path for the package.json file inside the package\n        PACKAGE_JSON=\"${PACKAGE}package.json\"\n        \n        # Check if the package.json file exists in the current directory\n        if [ -f \"$PACKAGE_JSON\" ]; then\n            # Check if the package.json contains the specific dependency under peerDependencies\n            if jq -e \".peerDependencies | has(\\\"$DEPENDENCY\\\")\" \"$PACKAGE_JSON\" > /dev/null; then\n                # Update the version of the dependency in the package.json file\n                echo \"Updating '$DEPENDENCY' to version ^$VERSION in $PACKAGE_JSON\"\n                \n                # Use jq to modify the version of the dependency\n                # The result is written to a temporary file and then replaces the original file\n                jq \".peerDependencies[\\\"$DEPENDENCY\\\"] = \\\"^$VERSION\\\"\" \"$PACKAGE_JSON\" > \"$PACKAGE_JSON.tmp\" && mv \"$PACKAGE_JSON.tmp\" \"$PACKAGE_JSON\"\n            fi\n        fi\n    fi\ndone\n\n# Message indicating the script has finished successfully\necho \"Update completed.\"\n"
  }
]