[
  {
    "path": ".babelrc.js",
    "content": "module.exports = (api) => ({\n  presets: [\n    [\n      'babel-preset-env-modules',\n      api.env() !== 'test'\n        ? {\n            ignoreBrowserslistConfig: true,\n            modules: api.env() === 'esm' ? false : 'commonjs',\n          }\n        : {\n            target: 'node',\n            targets: { node: 'current' },\n          },\n    ],\n    ['@babel/preset-typescript', { allowDeclareFields: true }],\n  ],\n});\n"
  },
  {
    "path": ".eslintignore",
    "content": ".eslintrc\n.eslintrc.js\n"
  },
  {
    "path": ".eslintrc",
    "content": "{\n  \"extends\": [\"jason\", \"prettier\"],\n  \"env\": {\n    \"browser\": true\n  },\n  \"parserOptions\": {\n    \"requireConfigFile\": false\n  },\n  \"rules\": {\n    \"@typescript-eslint/no-shadow\": \"off\",\n    \"@typescript-eslint/no-empty-interface\": \"off\"\n  },\n  \"overrides\": [\n    {\n      \"files\": [\"test/**\"],\n      \"plugins\": [\"jest\"],\n      \"env\": {\n        \"jest/globals\": true\n      },\n      \"rules\": {\n        \"global-require\": \"off\",\n        \"no-await-in-loop\": \"off\",\n        \"jest/no-disabled-tests\": \"warn\",\n        \"jest/no-focused-tests\": \"error\",\n        \"jest/no-identical-title\": \"error\",\n        \"jest/prefer-to-have-length\": \"warn\",\n        \"@typescript-eslint/no-empty-function\": \"off\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": ".gitattributes",
    "content": "# Auto detect text files and perform LF normalization\n* text=auto\n\n# Custom for Visual Studio\n*.cs     diff=csharp\n*.sln    merge=union\n*.csproj merge=union\n*.vbproj merge=union\n*.fsproj merge=union\n*.dbproj merge=union\n\n# Standard to msysgit\n*.doc\t diff=astextplain\n*.DOC\t diff=astextplain\n*.docx diff=astextplain\n*.DOCX diff=astextplain\n*.dot  diff=astextplain\n*.DOT  diff=astextplain\n*.pdf  diff=astextplain\n*.PDF\t diff=astextplain\n*.rtf\t diff=astextplain\n*.RTF\t diff=astextplain\n"
  },
  {
    "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**\n\nWrite a **runnable** test case using the code sandbox template: https://codesandbox.io/s/yup-test-case-gg1g1 \nIn the `index.test.js` file change the passing test to a failing one demostrating your issue\n\n> NOTE: if you do not provide a runnable reproduction the chances of getting feedback are significantly lower\n\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Platform (please complete the following information):**\n - Browser [e.g. chrome, safari]\n - Version [e.g. 22]\n\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/question.md",
    "content": "---\nname: Question\nabout: General questions about yup or how it works\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n- Write a title that summarizes the specific problem\n- Describe what you are trying to accomplish AND what you have tried\n\n**Help Others Reproduce**\n\nWrite a **runnable** test case using the code sandbox template: https://codesandbox.io/s/yup-test-case-gg1g1 \n\n> NOTE: if you do not provide a runnable reproduction the chances of getting feedback are significantly lower\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: Test\non:\n  push:\n    branches: [master, next]\n  pull_request:\n    branches: [master, next]\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - name: Setup Node\n        uses: actions/setup-node@v3\n        with:\n          node-version: 'lts/*'\n      - run: |\n          corepack enable\n      - run: yarn install --frozen-lockfile\n      - run: yarn test\n"
  },
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\ndts/\n# Runtime data\npids\n*.pid\n*.seed\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Compiled binary addons (http://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directory\n# Commenting this out is preferred by some people, see\n# https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git\nnode_modules\n\n# Users Environment Variables\n.lock-wscript\n\n# =========================\n# Operating System Files\n# =========================\n\n# OSX\n# =========================\n\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n\n\n# Thumbnails\n._*\n\n# Files that might appear on external disk\n.Spotlight-V100\n.Trashes\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n# Windows\n# =========================\n\n# Windows image file caches\nThumbs.db\nehthumbs.db\n\n# Folder config file\nDesktop.ini\n\n# Recycle Bin used on file shares\n$RECYCLE.BIN/\n\n# Windows Installer files\n*.cab\n*.msi\n*.msm\n*.msp\n\n# Ignore build files\nlib/\nes/\n"
  },
  {
    "path": ".nvmrc",
    "content": "22.19.0\n"
  },
  {
    "path": ".yarn/patches/@4c-rollout-npm-4.0.2-ab2b6d0bab.patch",
    "content": "diff --git a/command.js b/command.js\nindex 9608bffb4a52e5b8066e263d1286420ae92988bb..86ca58d70f315dae45fc739707dcff07a99a2be4 100644\n--- a/command.js\n+++ b/command.js\n@@ -292,8 +292,7 @@ const handlerImpl = async (argv) => {\n                 task: () =>\n                   exec('yarn', [\n                     'install',\n-                    '--frozen-lockfile',\n-                    '--production=false',\n+                    '--immutable',\n                   ]),\n               }\n             : {\n"
  },
  {
    "path": ".yarnrc.yml",
    "content": "nodeLinker: node-modules\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## [1.7.1](https://github.com/jquense/yup/compare/v1.7.0...v1.7.1) (2025-09-21)\n\n\n\n\n\n# [1.7.0](https://github.com/jquense/yup/compare/v1.6.1...v1.7.0) (2025-08-01)\n\n\n### Features\n\n* Implement standard schema interface ([#2258](https://github.com/jquense/yup/issues/2258)) ([ced5f51](https://github.com/jquense/yup/commit/ced5f514a6033a96f5de3b4ae9c17fe0de86d68f))\n* resolve ref params if present when describing ([ef53030](https://github.com/jquense/yup/commit/ef5303025c38e6e0dc0de53c990e7277cc74164e)), closes [#2276](https://github.com/jquense/yup/issues/2276)\n\n\n\n\n\n## [1.6.1](https://github.com/jquense/yup/compare/v1.6.0...v1.6.1) (2024-12-17)\n\n\n### Bug Fixes\n\n* lazy validation errors thrown in builders should resolve async like other validations ([c7d7f97](https://github.com/jquense/yup/commit/c7d7f977e02a7e578950dff192057e0b200999bd))\n\n\n\n\n\n# [1.6.0](https://github.com/jquense/yup/compare/v1.5.0...v1.6.0) (2024-12-16)\n\n\n### Features\n\n* expose LazySchema ([2b0f126](https://github.com/jquense/yup/commit/2b0f1264083fccb646f7f6bd43adfbff2caaf295))\n\n\n\n\n\n# [1.5.0](https://github.com/jquense/yup/compare/v1.4.0...v1.5.0) (2024-12-03)\n\n\n### Bug Fixes\n\n* **readme:** some typos and update CustomizingErrors doc ([#2163](https://github.com/jquense/yup/issues/2163)) ([5c77e0d](https://github.com/jquense/yup/commit/5c77e0d4f9373151bcf0cd558c95986b6e4800d7))\n\n\n### Features\n\n* Add exact and stripUnknown method to object() ([adcdd8d](https://github.com/jquense/yup/commit/adcdd8dd500c627b1efbe3595b6b37dec2847ad8))\n\n\n\n\n\n# [1.4.0](https://github.com/jquense/yup/compare/v1.3.3...v1.4.0) (2024-03-06)\n\n\n### Bug Fixes\n\n* add optional message to nonNullable schema methods ([#2119](https://github.com/jquense/yup/issues/2119)) ([9e1df49](https://github.com/jquense/yup/commit/9e1df4938c1964a21e6ece0c458bb96dc5aff108))\n\n\n### Features\n\n* **string:** Create .datetime() ([#2087](https://github.com/jquense/yup/issues/2087)) ([2a9e060](https://github.com/jquense/yup/commit/2a9e060594423018f517419ef5d2f10e417c9fbd))\n\n\n\n\n\n## [1.3.3](https://github.com/jquense/yup/compare/v1.3.2...v1.3.3) (2023-12-14)\n\n\n### Bug Fixes\n\n* **addMethod:** allow Schema without making TypeScript upset ([f921fe6](https://github.com/jquense/yup/commit/f921fe69a2d6ecc6e7d0101d2bd81148dfe83e64))\n\n\n\n\n\n## [1.3.2](https://github.com/jquense/yup/compare/v1.3.1...v1.3.2) (2023-09-29)\n\n\n### Bug Fixes\n\n* pick and omit with excluded edges ([6956ee7](https://github.com/jquense/yup/commit/6956ee788369dff00e5ecadb506726af3598a87e)), closes [#2097](https://github.com/jquense/yup/issues/2097)\n\n\n\n\n\n## [1.3.1](https://github.com/jquense/yup/compare/v1.3.0...v1.3.1) (2023-09-26)\n\n\n### Bug Fixes\n\n* ValidationError extends Error ([bc5121b](https://github.com/jquense/yup/commit/bc5121b92d8e16baf8fe9b83f0247a4e90e169b8))\n\n\n\n\n\n# [1.3.0](https://github.com/jquense/yup/compare/v1.2.0...v1.3.0) (2023-09-23)\n\n\n### Bug Fixes\n\n* add tuple to locale object ([#2100](https://github.com/jquense/yup/issues/2100)) ([809b55a](https://github.com/jquense/yup/commit/809b55a9c16e0cd567f4eced9b9ab02ad8b0bffa))\n* performance improvement ([#2043](https://github.com/jquense/yup/issues/2043)) ([#2044](https://github.com/jquense/yup/issues/2044)) ([ee1b731](https://github.com/jquense/yup/commit/ee1b7317b0a9fc0e16a7d33064c3e5584bd7f2d5))\n\n\n### Features\n\n* Allow schema metadata to be strongly typed ([#2021](https://github.com/jquense/yup/issues/2021)) ([e593f8f](https://github.com/jquense/yup/commit/e593f8f72e7195cf0ac48fa8e1cd82d95c1e6bb5))\n\n\n### Reverts\n\n* Revert \"fix: performance improvement (#2043) (#2044)\" (#2071) ([b940eef](https://github.com/jquense/yup/commit/b940eef48eb7456622ae384d0ffa7363d4fbad25)), closes [#2043](https://github.com/jquense/yup/issues/2043) [#2044](https://github.com/jquense/yup/issues/2044) [#2071](https://github.com/jquense/yup/issues/2071)\n\n\n\n\n\n# [1.2.0](https://github.com/jquense/yup/compare/v1.1.1...v1.2.0) (2023-05-25)\n\n\n### Features\n\n* expose printValue ([#2002](https://github.com/jquense/yup/issues/2002)) ([#2008](https://github.com/jquense/yup/issues/2008)) ([1fadba1](https://github.com/jquense/yup/commit/1fadba10b0d1cad60f3708bd28282ab04a55eff6))\n* pass options to `default(options => value)` ([e5c5440](https://github.com/jquense/yup/commit/e5c5440767d32a8be6c4a12a5f6176924e058fd2)), closes [#1984](https://github.com/jquense/yup/issues/1984)\n\n\n\n\n\n## [1.1.1](https://github.com/jquense/yup/compare/v1.1.0...v1.1.1) (2023-04-14)\n\n\n### Bug Fixes\n\n* **docs:** Broken anchores ([#1979](https://github.com/jquense/yup/issues/1979)) ([4ed4576](https://github.com/jquense/yup/commit/4ed45762e955ac6af0dec935a91e815a5a1cf5b9))\n* make null validation errors consistent across schema ([#1982](https://github.com/jquense/yup/issues/1982)) ([f999497](https://github.com/jquense/yup/commit/f99949747456d7bf55da3dd38dcf86bbddba3169))\n* **object:** excluded edges are merged when concating schema ([c07b08f](https://github.com/jquense/yup/commit/c07b08f033be8eea00d74a5da1cf735cf97e69df)), closes [#1969](https://github.com/jquense/yup/issues/1969)\n\n\n\n\n\n# [1.1.0](https://github.com/jquense/yup/compare/v1.0.2...v1.1.0) (2023-04-12)\n\n\n### Bug Fixes\n\n* tuple describe() method ([#1947](https://github.com/jquense/yup/issues/1947)) ([297f168](https://github.com/jquense/yup/commit/297f1682296ee0b53e5e252477d5a6d7d82df707))\n\n\n### Features\n\n* only resolve \"strip()\" for schema when used as an object field ([#1977](https://github.com/jquense/yup/issues/1977)) ([2ba1104](https://github.com/jquense/yup/commit/2ba1104798dcf3b9385997e5fbaa41b4d711472d))\n* respect context for object's children ([#1971](https://github.com/jquense/yup/issues/1971)) ([edfe6ac](https://github.com/jquense/yup/commit/edfe6acde9e11ec2bfe2ad41aad867daae7041ce))\n\n\n\n\n\n## [1.0.2](https://github.com/jquense/yup/compare/v1.0.0...v1.0.2) (2023-02-27)\n\n\n### Bug Fixes\n\n* fix array describe not including conditions ([4040592](https://github.com/jquense/yup/commit/4040592ccd068ab71e06417b4d355007636cb78c)), closes [#1920](https://github.com/jquense/yup/issues/1920)\n\n\n\n\n\n## [1.0.1](https://github.com/jquense/yup/compare/v1.0.0...v1.0.1) (2023-02-25)\n\n\n\n\n\n# [1.0.0](https://github.com/jquense/yup/compare/v1.0.0-beta.8...v1.0.0) (2023-02-08)\n\n### Migrating from 0.x to 1.0.0: [#1906](https://github.com/jquense/yup/issues/1906)\n\n\n\n\n# [1.0.0-beta.8](https://github.com/jquense/yup/compare/v1.0.0-beta.7...v1.0.0-beta.8) (2022-11-10)\n\n\n### Bug Fixes\n\n* check if field exists when generating defaults ([37f686c](https://github.com/jquense/yup/commit/37f686c217a9ee5d6f21f07a812a20467ee83578))\n* correct minor typo in README ([#1760](https://github.com/jquense/yup/issues/1760)) ([62786c4](https://github.com/jquense/yup/commit/62786c42ca07a2b84b05ca8c473bc01f0c868a94))\n* don't return any for oneOf ([74c5bc5](https://github.com/jquense/yup/commit/74c5bc54220cae5ff491ed92845ecd9c1ed7fbf3)), closes [#1675](https://github.com/jquense/yup/issues/1675)\n* export more types ([f250109](https://github.com/jquense/yup/commit/f250109dbf7158f1ee31ccd11f8309d660880252))\n* string().notRequired() ([#1824](https://github.com/jquense/yup/issues/1824)) ([dcb4b63](https://github.com/jquense/yup/commit/dcb4b6381eac21f8f28297066e71920a788c8a47))\n* TS 4.8 compat ([bc74c34](https://github.com/jquense/yup/commit/bc74c340721da2ea6e65cb27b967c2970af44d35))\n* **types:** undefined defaults produce optional outputs ([1afbac0](https://github.com/jquense/yup/commit/1afbac06edfd3277a8c76bb4c8874cf16d4d346d))\n\n\n### Features\n\n* add some more type exports ([d5e9c99](https://github.com/jquense/yup/commit/d5e9c99e6ef068bff4c4f92db5ccc0835f6b84b3))\n* Export ValidateOptions, ISchema for external use ([#1812](https://github.com/jquense/yup/issues/1812)) ([584df11](https://github.com/jquense/yup/commit/584df11b60e5d47876946872973764d0e0e0c9ed))\n* respect nullable() with oneOf ([#1757](https://github.com/jquense/yup/issues/1757)) ([61ec302](https://github.com/jquense/yup/commit/61ec3027caba72cb795ee64f571ca0a7aa6bc9a6)), closes [#768](https://github.com/jquense/yup/issues/768) [#104](https://github.com/jquense/yup/issues/104)\n* simplify email validation ([440db3e](https://github.com/jquense/yup/commit/440db3e6177d25c06be76995a1deff6e25a90c10))\n\n\n### BREAKING CHANGES\n\n* previously `oneOf` required adding `null` explicitly to allowed values when using oneOf. Folks have found this confusing and unintuitive so I am deferring and adjusting the behavior\n* Use a simpler regex for email addresses that aligns with browsers, and add docs about how to override.\n\n\n\n\n\n# [1.0.0-beta.7](https://github.com/jquense/yup/compare/v1.0.0-beta.6...v1.0.0-beta.7) (2022-08-20)\n\n\n\n\n\n# [1.0.0-beta.6](https://github.com/jquense/yup/compare/v1.0.0-beta.5...v1.0.0-beta.6) (2022-08-20)\n\n\n### Bug Fixes\n\n* change mixed generic to unknown from any ([5e8e8ef](https://github.com/jquense/yup/commit/5e8e8ef132574b31056bc7c504b8ba62c9ae4d1e))\n* count stripping unknown fields as changes for object casts ([2b4773c](https://github.com/jquense/yup/commit/2b4773ca8d4dc7b1f30e3927a113eb807d254f37)), closes [#1620](https://github.com/jquense/yup/issues/1620)\n* **types:** export more types ([433a452](https://github.com/jquense/yup/commit/433a45252cac4621c00adbeb3c9320caca55cced))\n\n\n\n\n\n# [1.0.0-beta.5](https://github.com/jquense/yup/compare/v1.0.0-beta.4...v1.0.0-beta.5) (2022-08-19)\n\n\n### Bug Fixes\n\n* coarce -> coerce ([#1677](https://github.com/jquense/yup/issues/1677)) ([99aa257](https://github.com/jquense/yup/commit/99aa25787a8ff15fe42e54db88ec3ed547357302))\n* **docs:** correct typo \"coarce\" to \"coerce\" ([#1654](https://github.com/jquense/yup/issues/1654)) ([f29ff71](https://github.com/jquense/yup/commit/f29ff71e4ae04927d85a00a993a014de652ae9fe))\n\n\n### Features\n\n* add cast nullability migration path. ([#1749](https://github.com/jquense/yup/issues/1749)) ([2bb099e](https://github.com/jquense/yup/commit/2bb099e26f62dd4734fe7bd525d011ce2b1583b5))\n* better Lazy types and deepPartial fixes ([#1748](https://github.com/jquense/yup/issues/1748)) ([e4ae6ed](https://github.com/jquense/yup/commit/e4ae6edeb171f25c43ca9367038ad5f09ce9de7c))\n\n\n### BREAKING CHANGES\n\n* The types for Lazy have changes a bit, it's unlikely that this affects anyone but it is technically a breaking change.\n\n\n\n\n\n# [1.0.0-beta.4](https://github.com/jquense/yup/compare/v1.0.0-beta.3...v1.0.0-beta.4) (2022-04-10)\n\n\n### Bug Fixes\n\n* **boolean:** calling optional made it non-optional ([4ba02a1](https://github.com/jquense/yup/commit/4ba02a15b649dccaa090a2e72476c1ea448a3fc1)), closes [#1627](https://github.com/jquense/yup/issues/1627)\n\n\n\n\n\n# [1.0.0-beta.3](https://github.com/jquense/yup/compare/v1.0.0-beta.2...v1.0.0-beta.3) (2022-03-09)\n\n\n### Bug Fixes\n\n* correct minor typo in README ([#1582](https://github.com/jquense/yup/issues/1582)) ([facea53](https://github.com/jquense/yup/commit/facea53e3508d041d86076ef065fb80b8ec74286))\n* partial() ([1207261](https://github.com/jquense/yup/commit/120726175aa97a9066fb765155ae4fef15b1e0ad))\n\n\n### BREAKING CHANGES\n\n* 'required' no longer adds a test for most schema, to determine if a schema is required, check it's `spec.optional` and `spec.nullable` values, also accessible via `describe()`\n\n\n\n\n\n# [1.0.0-beta.2](https://github.com/jquense/yup/compare/v0.32.11...v1.0.0-beta.2) (2022-01-21)\n\n\n### Bug Fixes\n\n* add originalValue to TestContext type ([#1527](https://github.com/jquense/yup/issues/1527)) ([fcc5ae7](https://github.com/jquense/yup/commit/fcc5ae710a1b3ef4b799532291faf894bdbcc11b)), closes [/github.com/abnersajr/DefinitelyTyped/blob/a186d99d0c3a92424691a82130374a1b9145c7cd/types/yup/index.d.ts#L446](https://github.com//github.com/abnersajr/DefinitelyTyped/blob/a186d99d0c3a92424691a82130374a1b9145c7cd/types/yup/index.d.ts/issues/L446)\n\n\n* Merge next into master (#1547) ([366f7d8](https://github.com/jquense/yup/commit/366f7d8e280b021bbd7a4a4d3cfc8fa0cce00c8b)), closes [#1547](https://github.com/jquense/yup/issues/1547) [#1542](https://github.com/jquense/yup/issues/1542) [#1541](https://github.com/jquense/yup/issues/1541) [#1543](https://github.com/jquense/yup/issues/1543) [#1545](https://github.com/jquense/yup/issues/1545)\n\n\n### Features\n\n*  add Tuple type ([#1546](https://github.com/jquense/yup/issues/1546)) ([a8febdd](https://github.com/jquense/yup/commit/a8febddcfbe42358e63194ae8da582e66b746edf))\n\n\n### BREAKING CHANGES\n\n* The builder object version of `when()` requires `then` and `otherwise` to be\n  functions `(schema: Schema) => Schema`.\n\n* The function version of `when()` has been changed to make it easier to type. values are always passed as an array and schema, and options always the second and third argument. `this` is no longer set to the schema instance.  and all functions _must_ return a schema to be type safe\n\n```diff\n string()\n-   .when('other', function (other) => {\n-      if (other) return this.required()\n+   .when('other', ([other], schema) => {\n+     return other ? schema.required() : schema\n  })\n```\n* concat works shallowly now. Previously concat functioned like a deep merge for object, which produced confusing behavior with incompatible concat'ed schema. Now concat for objects works similar to how it works for other types, the provided schema is applied on top of the existing schema, producing a new schema that is the same as calling each builder method in order\n\n* docs: update readme\n\n* chore: update to readonly arrays and test string type narrowing\n\n* test: add boolean tests\n\n* docs: more docs\n\n* feat: allow mixed schema to specify type check\n* `mixed` schema are no longer treated as the base class for other schema types. It hasn't been for a while, but we've done some nasty prototype slinging to make it behave like it was. Now typescript types should be 1 to 1 with the actual classes yup exposes. \n\nIn general this should not affect anything unless you are extending (via `addMethod` or otherwise) `mixed` prototype. \n\n```diff\nimport {\n-  mixed,\n+  Schema,\n} from 'yup';\n\n- addMethod(mixed, 'method', impl)\n+ addMethod(Schema, 'method', impl)\n```\n\n* chore: prep work for toggling coercion\n\n* Publish v1.0.0-alpha.4\n\n* chore: docs\n\n* feat!: add json() method and remove default object/array coercion\n* object and array schema no longer parse JSON strings by default, nor do they return `null` for invalid casts.\n\n```ts\nobject().json().cast('{}')\narray().json().cast('[]')\n```\nto mimic the previous behavior\n\n* feat: Make Array generic consistent with others\n* types only, `ArraySchema`  initial generic is the array type not the type of the array element. `array<T>()` is still the inner type.\n\n* Publish v1.0.0-beta.0\n\n* docs\n\n\n# [1.0.0-beta.1](https://github.com/jquense/yup/compare/v1.0.0-beta.0...v1.0.0-beta.1) (2022-01-03)\n\n\n### Features\n\n* flat bundles and size reductions ([753abdf](https://github.com/jquense/yup/commit/753abdf329e33e43c334e405baa9c71999079480))\n\n\n\n# [1.0.0-beta.0](https://github.com/jquense/yup/compare/v1.0.0-alpha.4...v1.0.0-beta.0) (2021-12-29)\n\n\n* feat!: add json() method and remove default object/array coercion ([94b73c4](https://github.com/jquense/yup/commit/94b73c438b3d355253f488325e06c69378e71fc1))\n\n\n### Features\n\n* Make Array generic consistent with others ([a82353f](https://github.com/jquense/yup/commit/a82353f37735daec6e42d18bd4cc0efe52a20f50))\n\n\n### BREAKING CHANGES\n\n* types only, `ArraySchema`  initial generic is the array type not the type of the array element. `array<T>()` is still the inner type.\n* object and array schema no longer parse JSON strings by default, nor do they return `null` for invalid casts.\n\n```ts\nobject().json().cast('{}')\narray().json().cast('[]')\n```\nto mimic the previous behavior\n\n\n\n# [1.0.0-alpha.4](https://github.com/jquense/yup/compare/v1.0.0-alpha.3...v1.0.0-alpha.4) (2021-12-29)\n\n### Bug Fixes\n\n- add originalValue to TestContext type ([#1527](https://github.com/jquense/yup/issues/1527)) ([fcc5ae7](https://github.com/jquense/yup/commit/fcc5ae710a1b3ef4b799532291faf894bdbcc11b)), closes [/github.com/abnersajr/DefinitelyTyped/blob/a186d99d0c3a92424691a82130374a1b9145c7cd/types/yup/index.d.ts#L446](https://github.com//github.com/abnersajr/DefinitelyTyped/blob/a186d99d0c3a92424691a82130374a1b9145c7cd/types/yup/index.d.ts/issues/L446)\n\n### Features\n\n- allow mixed schema to specify type check ([3923039](https://github.com/jquense/yup/commit/3923039558733d34586df2b282d34c5b6cbc5111))\n- concat() is shallow and does not merge ([#1541](https://github.com/jquense/yup/issues/1541)) ([a2f99d9](https://github.com/jquense/yup/commit/a2f99d9e8d8ba1b285fa6f48a0dd77a77f629ee4))\n- simplify base class hierarchy ([#1543](https://github.com/jquense/yup/issues/1543)) ([c184dcf](https://github.com/jquense/yup/commit/c184dcf644c09f3c4697cd3e5c795784a5315f77))\n- stricter `when` types and API ([#1542](https://github.com/jquense/yup/issues/1542)) ([da74254](https://github.com/jquense/yup/commit/da742545a228b909fef6f7fa526ea7b459d96051))\n\n### BREAKING CHANGES\n\n- `mixed` schema are no longer treated as the base class for other schema types. It hasn't been for a while, but we've done some nasty prototype slinging to make it behave like it was. Now typescript types should be 1 to 1 with the actual classes yup exposes.\n\nIn general this should not affect anything unless you are extending (via `addMethod` or otherwise) `mixed` prototype.\n\n```diff\nimport {\n-  mixed,\n+  Schema,\n} from 'yup';\n\n- addMethod(mixed, 'method', impl)\n+ addMethod(Schema, 'method', impl)\n```\n\n- concat works shallowly now. Previously concat functioned like a deep merge for object, which produced confusing behavior with incompatible concat'ed schema. Now concat for objects works similar to how it works for other types, the provided schema is applied on top of the existing schema, producing a new schema that is the same as calling each builder method in order\n- The builder object version of `when()` requires `then` and `otherwise` to be\n  functions `(schema: Schema) => Schema`.\n- The function version of `when()` has been changed to make it easier to type. values are always passed as an array and schema, and options always the second and third argument. `this` is no longer set to the schema instance. and all functions _must_ return a schema to be type safe\n\n```diff\n string()\n-   .when('other', function (other) => {\n-      if (other) return this.required()\n+   .when('other', ([other], schema) => {\n+     return other ? schema.required() : schema\n  })\n```\n\n# [1.0.0-alpha.3](https://github.com/jquense/yup/compare/v0.32.11...v1.0.0-alpha.3) (2021-12-28)\n\n### Bug Fixes\n\n- schemaOf handles Dates ([c1fc816](https://github.com/jquense/yup/commit/c1fc816cdb03f7c9ff2e6745ff38a2b4f119d556))\n- **types:** use type import/export ([#1238](https://github.com/jquense/yup/issues/1238)) ([bc284b5](https://github.com/jquense/yup/commit/bc284b5dbd4541464eb4a4edee73cb4d50c00fa7))\n\n### Features\n\n- More intuitive Object generics, faster types ([#1540](https://github.com/jquense/yup/issues/1540)) ([912e0be](https://github.com/jquense/yup/commit/912e0bed1e0184ba9c94015dc187eb6f86bb84d5))\n\n# [1.0.0-alpha.2](https://github.com/jquense/yup/compare/v1.0.0-alpha.1...v1.0.0-alpha.2) (2020-12-18)\n\n# [1.0.0-alpha.1](https://github.com/jquense/yup/compare/v1.0.0-alpha.0...v1.0.0-alpha.1) (2020-12-18)\n\n### Bug Fixes\n\n- **types:** make properties optional ([ba107cb](https://github.com/jquense/yup/commit/ba107cb50302e5245b960ed9a33f1c2167cc5d73))\n- **types:** make properties optional ([495ae84](https://github.com/jquense/yup/commit/495ae84f8bfc22b9f4310700d4d8e9586584a4c7))\n\n### Features\n\n- remove unneeded Out type from schema ([0bf9732](https://github.com/jquense/yup/commit/0bf97327d406c9d982b2c0a93069bd047b53d5ef))\n\n# [1.0.0-alpha.0](https://github.com/jquense/yup/compare/v0.32.8...v1.0.0-alpha.0) (2020-12-14)\n\n### Features\n\n- add describe and meta to lazy, with resolve options ([e56fea3](https://github.com/jquense/yup/commit/e56fea3d09707e975fa1e3bc19fadaac4d8b065b))\n\n\n## [0.32.11](https://github.com/jquense/yup/compare/v0.32.10...v0.32.11) (2021-10-12)\n\n\n### Bug Fixes\n\n* dep ranges ([2015c0f](https://github.com/jquense/yup/commit/2015c0f717065360076d5c460a139a2fff410166))\n\n\n\n\n\n## [0.32.10](https://github.com/jquense/yup/compare/v0.32.9...v0.32.10) (2021-10-11)\n\n\n### Bug Fixes\n\n* carry over excluded edges when concating objects ([5334349](https://github.com/jquense/yup/commit/53343491f0624120812182a70919a2fc3ebe11f5)), closes [#1423](https://github.com/jquense/yup/issues/1423)\n* fix the typo for the array length validation ([#1287](https://github.com/jquense/yup/issues/1287)) ([4c17508](https://github.com/jquense/yup/commit/4c175086ce8e53df529bbdff6f215929a5a39167))\n* missing transforms on concat ([f3056f2](https://github.com/jquense/yup/commit/f3056f2cbade92eaf0427848f43df97eae010555)), closes [#1260](https://github.com/jquense/yup/issues/1260)\n* oneOf, notOneOf swallowing multiple errors ([#1434](https://github.com/jquense/yup/issues/1434)) ([7842afb](https://github.com/jquense/yup/commit/7842afbaca0a44fc2fea72b44a90c2000ca2b8f0))\n* prevent unhandled Promise rejection when returning rejected Promise inside test function ([#1327](https://github.com/jquense/yup/issues/1327)) ([5eda549](https://github.com/jquense/yup/commit/5eda549dfce95be225b0eb6dbe3cbe7bcd5d3347))\n* SchemaOf<>'s treatment of Date objects. ([#1305](https://github.com/jquense/yup/issues/1305)) ([91ace1e](https://github.com/jquense/yup/commit/91ace1e8be3fc23c775ec8117c47b406bf29da4a)), closes [#1243](https://github.com/jquense/yup/issues/1243) [#1302](https://github.com/jquense/yup/issues/1302)\n* update lodash/lodash-es to fix CVEs flagged in 4.17.20 ([#1334](https://github.com/jquense/yup/issues/1334)) ([70d0b67](https://github.com/jquense/yup/commit/70d0b67e172f695168c5d00bc9856f2f775e0957))\n* **utils:** use named functions for default exports ([#1329](https://github.com/jquense/yup/issues/1329)) ([acbb8b4](https://github.com/jquense/yup/commit/acbb8b4f3c24ceaf65eab09abaf8e086a9f11a73))\n\n\n### Features\n\n* add resolved to params ([#1437](https://github.com/jquense/yup/issues/1437)) ([03584f6](https://github.com/jquense/yup/commit/03584f6758ff43409113c41f58fd41e065aa18a3))\n* add types to setLocale ([#1427](https://github.com/jquense/yup/issues/1427)) ([7576cd8](https://github.com/jquense/yup/commit/7576cd836ce9b660c054f9117795dbd9be12f747)), closes [#1321](https://github.com/jquense/yup/issues/1321)\n* allows custom types to be passed to avoid cast to ObjectSchema ([#1358](https://github.com/jquense/yup/issues/1358)) ([94cfd11](https://github.com/jquense/yup/commit/94cfd11b3f23e10f731efac05c5525829d10ded1))\n\n\n\n\n\n## [0.32.9](https://github.com/jquense/yup/compare/v0.32.6...v0.32.9) (2021-02-17)\n\n\n### Bug Fixes\n\n* **types:** Array required() and defined() will no longer return any ([#1256](https://github.com/jquense/yup/issues/1256)) ([52e5876](https://github.com/jquense/yup/commit/52e5876))\n* export MixedSchema to fix ts with --declarations ([#1204](https://github.com/jquense/yup/issues/1204)) ([67c96ae](https://github.com/jquense/yup/commit/67c96ae))\n* **types:** add generic to Reference.create() ([#1208](https://github.com/jquense/yup/issues/1208)) ([be3d1b4](https://github.com/jquense/yup/commit/be3d1b4))\n* **types:** reach and getIn make last 2 arguments optional ([#1194](https://github.com/jquense/yup/issues/1194)) ([5cf2c48](https://github.com/jquense/yup/commit/5cf2c48))\n* do not initialize spec values with undefined ([#1177](https://github.com/jquense/yup/issues/1177)) ([e8e5b46](https://github.com/jquense/yup/commit/e8e5b46)), closes [jquense/yup#1160](https://github.com/jquense/yup/issues/1160) [jquense/yup#1160](https://github.com/jquense/yup/issues/1160)\n* **types:** meta() return type ([e41040a](https://github.com/jquense/yup/commit/e41040a))\n* array handling in SchemaOf type ([#1169](https://github.com/jquense/yup/issues/1169)) ([e785e1a](https://github.com/jquense/yup/commit/e785e1a))\n* **types:** make StringSchema.matches options optional ([#1166](https://github.com/jquense/yup/issues/1166)) ([b53e5f2](https://github.com/jquense/yup/commit/b53e5f2))\n* **types:** SchemaOf doesn't produce a union of base schema ([2d71f32](https://github.com/jquense/yup/commit/2d71f32))\n\n\n\n\n\n## [0.32.6](https://github.com/jquense/yup/compare/v0.32.5...v0.32.6) (2020-12-08)\n\n\n### Bug Fixes\n\n* mixed() is the the base class ([7f8591d](https://github.com/jquense/yup/commit/7f8591d)), closes [#1156](https://github.com/jquense/yup/issues/1156)\n\n\n\n\n\n## [0.32.5](https://github.com/jquense/yup/compare/v0.32.4...v0.32.5) (2020-12-07)\n\n\n### Bug Fixes\n\n* **types:** change base.default() to any ([01c6930](https://github.com/jquense/yup/commit/01c6930))\n\n\n\n\n\n## [0.32.4](https://github.com/jquense/yup/compare/v0.32.3...v0.32.4) (2020-12-07)\n\n\n### Bug Fixes\n\n* **types:** rm base pick/omit types as they conflict with more specific ones ([14e2c8c](https://github.com/jquense/yup/commit/14e2c8c))\n\n\n### Features\n\n* add additional functions to Lazy class ([#1148](https://github.com/jquense/yup/issues/1148)) ([ecad1a3](https://github.com/jquense/yup/commit/ecad1a3))\n\n\n\n\n\n## [0.32.3](https://github.com/jquense/yup/compare/v0.32.2...v0.32.3) (2020-12-07)\n\n\n### Bug Fixes\n\n* **types:** AnyObjectSchema anys ([1c54665](https://github.com/jquense/yup/commit/1c54665))\n\n\n\n\n\n## [0.32.2](https://github.com/jquense/yup/compare/v0.32.1...v0.32.2) (2020-12-07)\n\n\n### Bug Fixes\n\n* **types:** array type with lazy ([ba92dfc](https://github.com/jquense/yup/commit/ba92dfc)), closes [#1146](https://github.com/jquense/yup/issues/1146)\n\n\n\n\n\n## [0.32.1](https://github.com/jquense/yup/compare/v0.32.0...v0.32.1) (2020-12-04)\n\n\n### Bug Fixes\n\n* cyclical import ([d5c5391](https://github.com/jquense/yup/commit/d5c5391)), closes [#1138](https://github.com/jquense/yup/issues/1138)\n* some strict fn type improvements ([8092218](https://github.com/jquense/yup/commit/8092218))\n\n\n\n\n\n# [0.32.0](https://github.com/jquense/yup/compare/v0.31.1...v0.32.0) (2020-12-03)\n\n\n### Features\n\n* typescript support ([#1134](https://github.com/jquense/yup/issues/1134)) ([b97c39d](https://github.com/jquense/yup/commit/b97c39d))\n\n\n### BREAKING CHANGES\n\n* `concat` doesn't check for \"unset\" nullable or presence when merging meaning the nullability and presence will always be the same as the schema passed to `concat()`. They can be overridden if needed after concatenation\n* schema factory functions are no longer constructors. The classes are now also exported for extension or whatever else. e.g. `import { StringSchema, string } from 'yup'`\n\n\n\n\n\n## [0.31.1](https://github.com/jquense/yup/compare/v0.31.0...v0.31.1) (2020-12-01)\n\n\n### Bug Fixes\n\n* swallowed errors on nested schema with no tests ([5316ab9](https://github.com/jquense/yup/commit/5316ab9)), closes [#1127](https://github.com/jquense/yup/issues/1127)\n\n\n### Features\n\n* add `isTrue` and `isFalse` checks on boolean ([#910](https://github.com/jquense/yup/issues/910)) ([630a641](https://github.com/jquense/yup/commit/630a641))\n\n\n\n\n\n# [0.31.0](https://github.com/jquense/yup/compare/v0.30.0...v0.31.0) (2020-11-23)\n\n\n### Bug Fixes\n\n* path params incorrectly mutated ([ba23eb7](https://github.com/jquense/yup/commit/ba23eb7)), closes [#1122](https://github.com/jquense/yup/issues/1122)\n\n\n### Features\n\n* add array.length() and treat empty arrays as valid for required() ([fbc158d](https://github.com/jquense/yup/commit/fbc158d))\n* add object.pick and object.omit ([425705a](https://github.com/jquense/yup/commit/425705a))\n* deprecate the getter overload of `default()` ([#1119](https://github.com/jquense/yup/issues/1119)) ([5dae837](https://github.com/jquense/yup/commit/5dae837))\n* more strictly coerce strings, exclude arrays and plain objects ([963d2e8](https://github.com/jquense/yup/commit/963d2e8))\n\n\n### BREAKING CHANGES\n\n* array().required() will no longer consider an empty array missing and required checks will pass.\n\nTo maintain the old behavior change to:\n```js\narray().required().min(1)\n```\n* plain objects and arrays are no long cast to strings automatically\n\nto recreate the old behavior:\n```js\nstring().transform((_, input) => input != null && input.toString ? input.toString() : value);\n```\n\n\n\n\n\n# [0.30.0](https://github.com/jquense/yup/compare/v0.29.3...v0.30.0) (2020-11-19)\n\n\n### Bug Fixes\n\n* defined() so it doesn't mark a schema as nullable ([f08d507](https://github.com/jquense/yup/commit/f08d507))\n* IE11 clone() ([#1029](https://github.com/jquense/yup/issues/1029)) ([7fd80aa](https://github.com/jquense/yup/commit/7fd80aa))\n* security Fix for Prototype Pollution - huntr.dev ([#1088](https://github.com/jquense/yup/issues/1088)) ([15a0f43](https://github.com/jquense/yup/commit/15a0f43))\n* uuid's regexp ([#1112](https://github.com/jquense/yup/issues/1112)) ([57d42a8](https://github.com/jquense/yup/commit/57d42a8))\n\n\n### Features\n\n* exposes context on mixed.test function and add originalValue to context ([#1021](https://github.com/jquense/yup/issues/1021)) ([6096064](https://github.com/jquense/yup/commit/6096064))\n\n\n### Performance Improvements\n\n* reduce function calls for shallower stacks ([#1022](https://github.com/jquense/yup/issues/1022)) ([01da7e1](https://github.com/jquense/yup/commit/01da7e1))\n\n\n### BREAKING CHANGES\n\n* defined() now doesn't automatically allow null, this was a bug. to mimic the old behavior add nullable() to schema with defined()\n\n\n\n\n\n## [0.29.3](https://github.com/jquense/yup/compare/v0.29.2...v0.29.3) (2020-08-04)\n\n\n\n\n\n## [0.29.2](https://github.com/jquense/yup/compare/v0.29.1...v0.29.2) (2020-07-27)\n\n\n### Bug Fixes\n\n* handle sparse array positions as undefined ([#950](https://github.com/jquense/yup/issues/950)) ([4e77348](https://github.com/jquense/yup/commit/4e77348))\n\n\n### Features\n\n* string UUID validation via a regex ([#909](https://github.com/jquense/yup/issues/909)) ([8f2bd2b](https://github.com/jquense/yup/commit/8f2bd2b))\n\n\n\n\n\n## [0.29.1](https://github.com/jquense/yup/compare/v0.29.0...v0.29.1) (2020-05-27)\n\n\n### Bug Fixes\n\n* present checks for array and strings ([ecd8ebe](https://github.com/jquense/yup/commit/ecd8ebe483456805d743c888a82e180394ba8a22)), closes [#913](https://github.com/jquense/yup/issues/913)\n\n\n### Features\n\n* allow access to parent schema (and unlimited ancestors!) in test context ([#556](https://github.com/jquense/yup/issues/556)) ([db35920](https://github.com/jquense/yup/commit/db35920b1ede4ea41ea90e1204b3da2a39787635))\n\n\n\n\n\n# [0.29.0](https://github.com/jquense/yup/compare/v0.28.5...v0.29.0) (2020-05-19)\n\n\n* feat!: update docs to account for changes in types and add additional example (#891) ([e105a71](https://github.com/jquense/yup/commit/e105a71)), closes [#891](https://github.com/jquense/yup/issues/891)\n\n\n### Bug Fixes\n\n* object bug when nested object has a property with strict ([#871](https://github.com/jquense/yup/issues/871)) ([7f52b8a](https://github.com/jquense/yup/commit/7f52b8a))\n\n\n### Features\n\n* expose oneOf and notOneOf values on description ([#885](https://github.com/jquense/yup/issues/885)) ([08dad5f](https://github.com/jquense/yup/commit/08dad5f))\n\n\n### BREAKING CHANGES\n\n* For users of `@types/yup` only, no function changes but the type def change is large enough that it warranted a major bump here\n\n\n\n\n\n## [0.28.5](https://github.com/jquense/yup/compare/v0.28.4...v0.28.5) (2020-04-30)\n\n### Bug Fixes\n\n- allow passing of function to .matches() options/message param ([#850](https://github.com/jquense/yup/issues/850)) ([16efe88](https://github.com/jquense/yup/commit/16efe88a8953db60438f77f43bd5bf614079803d))\n- bug in object.noUnknown for nullish values https://github.com/jquense/yup/issues/854 ([#855](https://github.com/jquense/yup/issues/855)) ([ccb7c7d](https://github.com/jquense/yup/commit/ccb7c7d3c450537dffbb7d589e3111fc1f9a86fd))\n\n## [0.28.4](https://github.com/jquense/yup/compare/v0.28.3...v0.28.4) (2020-04-20)\n\n### Bug Fixes\n\n- array reaching ([81e4058](https://github.com/jquense/yup/commit/81e4058))\n\n### Features\n\n- make schema.type and array.innerType public API's ([8f00d50](https://github.com/jquense/yup/commit/8f00d50))\n- provide keys in default noUnknown message ([#579](https://github.com/jquense/yup/issues/579)) ([ad5d015](https://github.com/jquense/yup/commit/ad5d015))\n\n## [0.28.3](https://github.com/jquense/yup/compare/v0.28.2...v0.28.3) (2020-03-06)\n\n### Bug Fixes\n\n- array.ensure ([94659c2](https://github.com/jquense/yup/commit/94659c2)), closes [#343](https://github.com/jquense/yup/issues/343)\n- match options ([493cc61](https://github.com/jquense/yup/commit/493cc61)), closes [#802](https://github.com/jquense/yup/issues/802) [#801](https://github.com/jquense/yup/issues/801) [#799](https://github.com/jquense/yup/issues/799) [#798](https://github.com/jquense/yup/issues/798)\n\n# [0.28.0](https://github.com/jquense/yup/compare/v0.26.10...v0.28.0) (2019-12-16)\n\n### Bug Fixes\n\n- [#473](https://github.com/jquense/yup/issues/473) make concat compatible with (not)oneOf ([#492](https://github.com/jquense/yup/issues/492)) ([8d21cc9](https://github.com/jquense/yup/commit/8d21cc9))\n- array path resolve for descendants ([#669](https://github.com/jquense/yup/issues/669)) ([d31e34d](https://github.com/jquense/yup/commit/d31e34d))\n- change @babel/runtime version to be a range ([#488](https://github.com/jquense/yup/issues/488)) ([1c9b362](https://github.com/jquense/yup/commit/1c9b362)), closes [#486](https://github.com/jquense/yup/issues/486)\n- concat of mixed and subtype ([#444](https://github.com/jquense/yup/issues/444)) ([7705972](https://github.com/jquense/yup/commit/7705972))\n- default message for test with object ([#453](https://github.com/jquense/yup/issues/453)) ([f1be37f](https://github.com/jquense/yup/commit/f1be37f))\n- noUnknown() overriding ([#452](https://github.com/jquense/yup/issues/452)) ([3047b33](https://github.com/jquense/yup/commit/3047b33))\n- string.matches() and regex global flag ([#450](https://github.com/jquense/yup/issues/450)) ([a8935b7](https://github.com/jquense/yup/commit/a8935b7))\n- synchronous conditional object validation with unknown dependencies ([#598](https://github.com/jquense/yup/issues/598)) ([1081c41](https://github.com/jquense/yup/commit/1081c41))\n- typo README (about excludeEmptyString) ([#441](https://github.com/jquense/yup/issues/441)) ([d02ff5e](https://github.com/jquense/yup/commit/d02ff5e))\n- unix epoc bug in date parser ([#655](https://github.com/jquense/yup/issues/655)) ([0d14827](https://github.com/jquense/yup/commit/0d14827))\n\n### Features\n\n- add \\_isFilled as overrideable `mixed` method to control required behavior ([#459](https://github.com/jquense/yup/issues/459)) ([5b01f18](https://github.com/jquense/yup/commit/5b01f18))\n- add function test names to email and url ([#292](https://github.com/jquense/yup/issues/292)) ([7e94395](https://github.com/jquense/yup/commit/7e94395))\n- aliases `optional()` and `unknown()` ([#460](https://github.com/jquense/yup/issues/460)) ([51e8661](https://github.com/jquense/yup/commit/51e8661))\n- allow toggling strict() ([#457](https://github.com/jquense/yup/issues/457)) ([851d421](https://github.com/jquense/yup/commit/851d421))\n- allow withMutation() nesting ([#456](https://github.com/jquense/yup/issues/456)) ([e53ea8c](https://github.com/jquense/yup/commit/e53ea8c))\n- do concat in mutation mode ([#461](https://github.com/jquense/yup/issues/461)) ([02be4ca](https://github.com/jquense/yup/commit/02be4ca))\n- finalize resolve() ([#447](https://github.com/jquense/yup/issues/447)) ([afc5119](https://github.com/jquense/yup/commit/afc5119))\n- replace integer check with Number.isInteger ([#405](https://github.com/jquense/yup/issues/405)) ([1c18442](https://github.com/jquense/yup/commit/1c18442))\n- support self references ([#443](https://github.com/jquense/yup/issues/443)) ([1cac515](https://github.com/jquense/yup/commit/1cac515)), closes [/github.com/jquense/yup/blob/d02ff5e59e004b4c5189d1b9fc0055cff45c61df/src/Reference.js#L3](https://github.com//github.com/jquense/yup/blob/d02ff5e59e004b4c5189d1b9fc0055cff45c61df/src/Reference.js/issues/L3)\n- use the alternate object index path syntax if the key contains dots (fixes [#536](https://github.com/jquense/yup/issues/536)) ([#539](https://github.com/jquense/yup/issues/539)) ([13e8c76](https://github.com/jquense/yup/commit/13e8c76))\n\n### BREAKING CHANGES\n\n- use Number.isInteger. This works correctly for large numbers.\n\nRelated to https://github.com/jquense/yup/pull/147\n\n- reach() no longer resolves the returned schema meaning it's conditions have not been processed yet; prefer validateAt/castAt where it makes sense\n- required no longer shows up twice in describe() output for array and strings, which also no longer override required\n\n# [0.27.0](https://github.com/jquense/yup/compare/v0.26.10...v0.27.0) (2019-03-14)\n\n### Bug Fixes\n\n- change @babel/runtime version to be a range ([#488](https://github.com/jquense/yup/issues/488)) ([1c9b362](https://github.com/jquense/yup/commit/1c9b362)), closes [#486](https://github.com/jquense/yup/issues/486)\n- concat of mixed and subtype ([#444](https://github.com/jquense/yup/issues/444)) ([7705972](https://github.com/jquense/yup/commit/7705972))\n- default message for test with object ([#453](https://github.com/jquense/yup/issues/453)) ([f1be37f](https://github.com/jquense/yup/commit/f1be37f))\n- noUnknown() overriding ([#452](https://github.com/jquense/yup/issues/452)) ([3047b33](https://github.com/jquense/yup/commit/3047b33))\n- typo README (about excludeEmptyString) ([#441](https://github.com/jquense/yup/issues/441)) ([d02ff5e](https://github.com/jquense/yup/commit/d02ff5e))\n\n### Features\n\n- add \\_isFilled as overrideable `mixed` method to control required behavior ([#459](https://github.com/jquense/yup/issues/459)) ([5b01f18](https://github.com/jquense/yup/commit/5b01f18))\n- aliases `optional()` and `unknown()` ([#460](https://github.com/jquense/yup/issues/460)) ([51e8661](https://github.com/jquense/yup/commit/51e8661))\n- allow toggling strict() ([#457](https://github.com/jquense/yup/issues/457)) ([851d421](https://github.com/jquense/yup/commit/851d421))\n- allow withMutation() nesting ([#456](https://github.com/jquense/yup/issues/456)) ([e53ea8c](https://github.com/jquense/yup/commit/e53ea8c))\n- do concat in mutation mode ([#461](https://github.com/jquense/yup/issues/461)) ([02be4ca](https://github.com/jquense/yup/commit/02be4ca))\n- finalize resolve() ([#447](https://github.com/jquense/yup/issues/447)) ([afc5119](https://github.com/jquense/yup/commit/afc5119))\n- support self references ([#443](https://github.com/jquense/yup/issues/443)) ([1cac515](https://github.com/jquense/yup/commit/1cac515)), closes [/github.com/jquense/yup/blob/d02ff5e59e004b4c5189d1b9fc0055cff45c61df/src/Reference.js#L3](https://github.com//github.com/jquense/yup/blob/d02ff5e59e004b4c5189d1b9fc0055cff45c61df/src/Reference.js/issues/L3)\n\n### BREAKING CHANGES\n\n- reach() no longer resolves the returned schema meaning it's conditions have not been processed yet; prefer validateAt/castAt where it makes sense\n- required no longer shows up twice in describe() output for array and strings, which also no longer override required\n\n## v0.26.3 - Tue, 28 Aug 2018 15:00:04 GMT\n\n## v0.26.0 - Fri, 20 Jul 2018 15:39:03 GMT\n\n### BREAKING CHANGES\n\n- locale `number` config properties `less` and `more` are now `lessThan` and `moreThan`\n\n## v0.25.1 - Wed, 16 May 2018 23:59:14 GMT\n\n## v0.25.0 - Tue, 15 May 2018 21:43:54 GMT\n\n- remove default export, there are only named exports now!\n- fix message defaults for built-in tests, default is only used for `undefined` messages\n- fix the `describe()` method so it works with nested schemas\n\n## v0.24.1 - Fri, 09 Feb 2018 19:09:02 GMT\n\n## v0.24.0 - Tue, 16 Jan 2018 14:44:32 GMT\n\n- [f2a0b75](../../commit/f2a0b75), [061e590](../../commit/061e590) [added] number methods lessThan, moreThan\n\n## v0.23.0 - Thu, 12 Oct 2017 17:08:47 GMT\n\n** Probably not breaking but we are being safe about it **\n\n- 🎉 Add Synchronous validation! [#94](https://github.com/jquense/yup/pull/94)\n\n** Features **\n\n- Custom locales without import order [#125](https://github.com/jquense/yup/pull/125)\n\n## v0.22.1 - Thu, 12 Oct 2017 14:49:16 GMT\n\n- Fix bug in browsers without symbol [#132](https://github.com/jquense/yup/pull/132)\n\n## v0.22.0 - Sat, 26 Aug 2017 14:48:57 GMT\n\n** Breaking **\n\n- Use native Set and lodash CloneDeep: [#109](https://github.com/jquense/yup/pull/109)\n\n\\*\\* Fixes and Features\n\n- Better custom locale support: [#105](https://github.com/jquense/yup/pull/105)\n- fix some messages: [#112](https://github.com/jquense/yup/pull/112)\n- Clearer errors for common mistakes: [#108](https://github.com/jquense/yup/pull/108)\n- New string validation length: [#67](https://github.com/jquense/yup/pull/67)\n\n## v0.21.3 - Wed, 18 Jan 2017 15:39:25 GMT\n\n- [7bc01e0](../../commit/7bc01e0) [added] deep path support for `from`\n\n## v0.21.2 - Fri, 09 Sep 2016 16:52:44 GMT\n\n- [be80413](../../commit/be80413) [fixed] default in concat()\n\n## v0.21.1 - Mon, 29 Aug 2016 18:39:29 GMT\n\n## v0.21.0 - Mon, 29 Aug 2016 18:29:31 GMT\n\n- [8a8cc5b](../../commit/8a8cc5b) [changed] remove case aliases and simplify camelCase\n\n## v0.20.0 - Wed, 20 Jul 2016 02:02:08 GMT\n\n- [f7446d2](../../commit/f7446d2) [fixed] pass path correctly to cast()\n- [9b5232a](../../commit/9b5232a) [added] allow function then/otherwise bodies\n- [73858fe](../../commit/73858fe) [changed] Don't throw on undefined values in cast()\n\n## v0.19.1 - Mon, 18 Jul 2016 21:53:05 GMT\n\n- [69c0ad4](../../commit/69c0ad4) [fixed] array().concat() incorrectly cleared the sub-schema\n\n## v0.19.0 - Fri, 24 Jun 2016 15:19:48 GMT\n\n- [b0dd021](../../commit/b0dd021) [changed] Split integer(), remove transform\n- [758ac51](../../commit/758ac51) [added] string.ensure\n- [f2b0078](../../commit/f2b0078) [changed] Less aggressive type coercions\n- [ab94510](../../commit/ab94510) [fixed] boxed number allowed NaN\n\n## v0.18.3 - Mon, 09 May 2016 15:50:47 GMT\n\n## v0.18.2 - Mon, 25 Apr 2016 18:23:13 GMT\n\n## v0.18.1 - Mon, 25 Apr 2016 15:01:16 GMT\n\n- [816e607](../../commit/816e607) [added] validation params to ValidationError\n\n## v0.18.0 - Sat, 23 Apr 2016 01:20:27 GMT\n\n- [f827822](../../commit/f827822) [changed] validate() on objects won't cast nested schema with strict()\n\n## v0.17.6 - Thu, 21 Apr 2016 14:59:59 GMT\n\n- [139dd24](../../commit/139dd24) [changed] lazy qualifies as a yup schema\n\n## v0.17.5 - Thu, 21 Apr 2016 11:20:16 GMT\n\n- [c553cc0](../../commit/c553cc0) [added] options to lazy resolve\n\n## v0.17.4 - Wed, 20 Apr 2016 14:15:39 GMT\n\n## v0.17.3 - Tue, 19 Apr 2016 20:24:09 GMT\n\n- [6c309e4](../../commit/6c309e4) [fixed] array.ensure()\n\n## v0.17.2 - Tue, 19 Apr 2016 16:46:54 GMT\n\n## v0.17.1 - Thu, 14 Apr 2016 19:12:22 GMT\n\n- [ab78f54](../../commit/ab78f54) [fixed] reach with lazy()\n\n## v0.17.0 - Thu, 14 Apr 2016 17:13:50 GMT\n\n- [6e9046b](../../commit/6e9046b) [changed] clean up interface, added lazy(), and fixed object strict semantics\n\n## v0.16.5 - Tue, 12 Apr 2016 13:36:38 GMT\n\n- [c3b613b](../../commit/c3b613b) [added] strip() method for objects\n- [68fc010](../../commit/68fc010) [added] array.of shorthand\n\n## v0.16.4 - Sat, 09 Apr 2016 20:13:13 GMT\n\n- [f30d1e3](../../commit/f30d1e3) [fixed] bug in date min/max with ref\n\n## v0.16.3 - Thu, 07 Apr 2016 19:13:23 GMT\n\n## v0.16.2 - Thu, 07 Apr 2016 17:57:44 GMT\n\n- [83c0656](../../commit/83c0656) [added] meta() and describe()\n\n## v0.16.1 - Tue, 05 Apr 2016 20:56:45 GMT\n\n- [9d70a7b](../../commit/9d70a7b) [changed] doesn't throw when context is missing.\n- [594fa53](../../commit/594fa53) [changed] added reach error\n\n## v0.16.0 - Tue, 05 Apr 2016 20:17:40 GMT\n\n- [75739b8](../../commit/75739b8) [added] context sensitive reach()\n\n## v0.15.0 - Tue, 29 Mar 2016 14:56:15 GMT\n\n- [3ae5fdc](../../commit/3ae5fdc) [changed] `null` is not considered an empty value for isValid\n- [9eb42c6](../../commit/9eb42c6) [added] refs!\n\n## v0.14.2 - Tue, 29 Mar 2016 14:48:37 GMT\n\n## v0.14.1 - Tue, 16 Feb 2016 19:51:25 GMT\n\n- [ff19720](../../commit/ff19720) [fixed] noUnknown and stripUnknown work and propagate to children\n\n## v0.14.0 - Mon, 08 Feb 2016 16:17:40 GMT\n\n- [86b6446](../../commit/86b6446) [fixed] camelCase should maintain leading underscores\n\n## v0.13.0 - Mon, 01 Feb 2016 20:49:40 GMT\n\n- [335eb18](../../commit/335eb18) [fixed] pass options to array sub schema\n- [f7f631d](../../commit/f7f631d) [changed] oneOf doesn't include empty values\n- [0a7b2d4](../../commit/0a7b2d4) [fixed] type and whitelist/blacklist checks threw inconsistent errors\n- [1274a45](../../commit/1274a45) [changed] required() to non-exclusive\n\n## v0.12.0 - Tue, 12 Jan 2016 19:12:18 GMT\n\n- [5bc250f](../../commit/5bc250f) [changed] don't clone unspecified object keys\n- [069c6fd](../../commit/069c6fd) [added] withMutation() method\n- [e1d4891](../../commit/e1d4891) [fixed] don't alias non existent fields\n\n## v0.11.0 - Sun, 08 Nov 2015 17:17:09 GMT\n\n- [686f6b1](../../commit/686f6b1) [changed] concat() allows mixing \"mixed\" and other type\n\n## 0.9.0\n\n**breaking**\n\n- `test` functions are no longer passed `path` and `context` as arguments, Instead they are now values on `this` inside the test function.\n- test functions are longer called with the schema as their `this` value, use `this.schema` instead.\n\n**other changes**\n\n- test functions are call with with a new context object, including, options, parent and `createError` for dynamically altering validation errors.\n\n## 0.8.3\n\n- document `stripUnknown`\n- add `recursive` option\n- add `noUnknown()` test to objects\n\n## 0.8.2\n\n- default for objects now adds keys for all fields, not just fields with non empty defaults\n\n## 0.8.1\n\n- bug fix\n\n## 0.8.0\n\n**breaking**\n\n- `test` functions are now passed `path` and `context` values along with the field value. Only breaks if using the callback style of defining custom validations\n\n## 0.7.0\n\n**breaking**\n\n- the `validation()` method has been renamed to `test()` and has a new signature requiring a `name` argument\n- exclusive validations now trump the previous one instead of defering to it e.g: `string().max(10).max(15)` has a max of `15` instead of `10`\n\n**other changes**\n\n- expose advanced signature for custom validation tests, gives finer grained control over how tests are added\n- added the `abortEarly` (default: `true`) option\n- transforms are passed an addition parameter: 'originalValue' you allow recovering from a bad transform further up the chain (provided no one mutated the value)\n\n## 0.6.3\n\n- fix `concat()` method and add tests\n\n## 0.6.2\n\n- fix validations where nullable fields were failing due to `null` values e.g `string.max()`\n\n## 0.6.1\n\n- fix export error\n\n## 0.6.0\n\n**breaking**\n\n- Removed the `extend` and `create` methods. Use whatever javascript inheritance patterns you want instead.\n- the resolution order of defaults and coercions has changed. as well as the general handling of `null` values.\n  - Number: `null` will coerce to `false` when `nullable()` is not specified. `NaN` values will now fail `isType()` checks\n  - String: `null` will coerce to `''` when `nullable()` is not specified\n  - Date: Invalid dates will not be coerced to `null`, but left as invalid date, This is probably not a problem for anyone as invalid dates will also fail `isType()` checks\n- default values are cloned everytime they are returned, so it is impossible to share references to defaults across schemas. No one should be doing that anyway\n- stopped pretending that using schemas as conditions in `when()` actually worked (it didn't)\n\n**other changes**\n\n- `transform()` now passes the original value to each transformer. Allowing you to recover from a bad transform.\n- added the `equals()` alias for `oneOf`\n-\n\n## 0.5.0\n\n**breaking**\n\n- isValid is now async, provide a node style callback, or use the promise the method returns to read the validity. This change allows for more robust validations, specifically remote ones for client code (or db queries for server code). The cast method is still, and will remain, synchronous.\n-\n\n**other changes**\n\n- added validate method (also async) which resolves to the value, and rejects with a new ValidationError\n"
  },
  {
    "path": "LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014 Jason Quense\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."
  },
  {
    "path": "README.md",
    "content": "# Yup\n\nYup is a schema builder for runtime value parsing and validation. Define a schema, transform a value to match, assert the shape of an existing value, or both. Yup schema are extremely expressive and allow modeling complex, interdependent validations, or value transformation.\n\n> **You are viewing docs for the v1.0.0 of yup, pre-v1 docs are available: [here](https://github.com/jquense/yup/tree/pre-v1)**\n\n**Killer Features**:\n\n- Concise yet expressive schema interface, equipped to model simple to complex data models\n- Powerful TypeScript support. Infer static types from schema, or ensure schema correctly implement a type\n- Built-in async validation support. Model server-side and client-side validation equally well\n- Extensible: add your own type-safe methods and schema\n- Rich error details, make debugging a breeze\n- Compatible with [Standard Schema](https://github.com/standard-schema/standard-schema)\n\n## Getting Started\n\nSchema are comprised of parsing actions (transforms) as well as assertions (tests) about the input value.\nValidate an input value to parse it and run the configured set of assertions. Chain together methods to build a schema.\n\n```ts\nimport { object, string, number, date, InferType } from 'yup';\n\nlet userSchema = object({\n  name: string().required(),\n  age: number().required().positive().integer(),\n  email: string().email(),\n  website: string().url().nullable(),\n  createdOn: date().default(() => new Date()),\n});\n\n// parse and assert validity\nlet user = await userSchema.validate(await fetchUser());\n\ntype User = InferType<typeof userSchema>;\n/* {\n  name: string;\n  age: number;\n  email?: string | undefined\n  website?: string | null | undefined\n  createdOn: Date\n}*/\n```\n\nUse a schema to coerce or \"cast\" an input value into the correct type, and optionally\ntransform that value into more concrete and specific values, without making further assertions.\n\n```ts\n// Attempts to coerce values to the correct type\nlet parsedUser = userSchema.cast({\n  name: 'jimmy',\n  age: '24',\n  createdOn: '2014-09-23T19:25:25Z',\n});\n// ✅  { name: 'jimmy', age: 24, createdOn: Date }\n```\n\nKnow that your input value is already parsed? You can \"strictly\" validate an input, and avoid the overhead\nof running parsing logic.\n\n```ts\n// ❌  ValidationError \"age is not a number\"\nlet parsedUser = await userSchema.validate(\n  {\n    name: 'jimmy',\n    age: '24',\n  },\n  { strict: true },\n);\n```\n\n## Table of Contents\n\n<!-- START doctoc generated TOC please keep comment here to allow auto update -->\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n\n- [Schema basics](#schema-basics)\n  - [Parsing: Transforms](#parsing-transforms)\n  - [Validation: Tests](#validation-tests)\n    - [Customizing errors](#customizing-errors)\n  - [Composition and Reuse](#composition-and-reuse)\n- [TypeScript integration](#typescript-integration)\n  - [Schema defaults](#schema-defaults)\n  - [Ensuring a schema matches an existing type](#ensuring-a-schema-matches-an-existing-type)\n  - [Extending built-in schema with new methods](#extending-built-in-schema-with-new-methods)\n  - [TypeScript configuration](#typescript-configuration)\n- [Error message customization](#error-message-customization)\n  - [localization and i18n](#localization-and-i18n)\n- [Standard Schema Support](#standard-schema-support)\n- [API](#api)\n  - [`yup`](#yup)\n    - [`reach(schema: Schema, path: string, value?: object, context?: object): Schema`](#reachschema-schema-path-string-value-object-context-object-schema)\n    - [`addMethod(schemaType: Schema, name: string, method: ()=> Schema): void`](#addmethodschematype-schema-name-string-method--schema-void)\n    - [`ref(path: string, options: { contextPrefix: string }): Ref`](#refpath-string-options--contextprefix-string--ref)\n    - [`lazy((value: any) => Schema): Lazy`](#lazyvalue-any--schema-lazy)\n    - [`ValidationError(errors: string | Array<string>, value: any, path: string)`](#validationerrorerrors-string--arraystring-value-any-path-string)\n  - [`Schema`](#schema)\n    - [`Schema.clone(): Schema`](#schemaclone-schema)\n    - [`Schema.label(label: string): Schema`](#schemalabellabel-string-schema)\n    - [`Schema.meta(metadata: SchemaMetadata): Schema`](#schemametametadata-schemametadata-schema)\n    - [`Schema.describe(options?: ResolveOptions): SchemaDescription`](#schemadescribeoptions-resolveoptions-schemadescription)\n    - [`Schema.concat(schema: Schema): Schema`](#schemaconcatschema-schema-schema)\n    - [`Schema.validate(value: any, options?: object): Promise<InferType<Schema>, ValidationError>`](#schemavalidatevalue-any-options-object-promiseinfertypeschema-validationerror)\n    - [`Schema.validateSync(value: any, options?: object): InferType<Schema>`](#schemavalidatesyncvalue-any-options-object-infertypeschema)\n    - [`Schema.validateAt(path: string, value: any, options?: object): Promise<InferType<Schema>, ValidationError>`](#schemavalidateatpath-string-value-any-options-object-promiseinfertypeschema-validationerror)\n    - [`Schema.validateSyncAt(path: string, value: any, options?: object): InferType<Schema>`](#schemavalidatesyncatpath-string-value-any-options-object-infertypeschema)\n    - [`Schema.isValid(value: any, options?: object): Promise<boolean>`](#schemaisvalidvalue-any-options-object-promiseboolean)\n    - [`Schema.isValidSync(value: any, options?: object): boolean`](#schemaisvalidsyncvalue-any-options-object-boolean)\n    - [`Schema.cast(value: any, options = {}): InferType<Schema>`](#schemacastvalue-any-options---infertypeschema)\n    - [`Schema.isType(value: any): value is InferType<Schema>`](#schemaistypevalue-any-value-is-infertypeschema)\n    - [`Schema.strict(enabled: boolean = false): Schema`](#schemastrictenabled-boolean--false-schema)\n    - [`Schema.strip(enabled: boolean = true): Schema`](#schemastripenabled-boolean--true-schema)\n    - [`Schema.withMutation(builder: (current: Schema) => void): void`](#schemawithmutationbuilder-current-schema--void-void)\n    - [`Schema.default(value: any): Schema`](#schemadefaultvalue-any-schema)\n    - [`Schema.getDefault(options?: object): Any`](#schemagetdefaultoptions-object-any)\n    - [`Schema.nullable(message?: string | function): Schema`](#schemanullablemessage-string--function-schema)\n    - [`Schema.nonNullable(message?: string | function): Schema`](#schemanonnullablemessage-string--function-schema)\n    - [`Schema.defined(): Schema`](#schemadefined-schema)\n    - [`Schema.optional(): Schema`](#schemaoptional-schema)\n    - [`Schema.required(message?: string | function): Schema`](#schemarequiredmessage-string--function-schema)\n    - [`Schema.notRequired(): Schema`](#schemanotrequired-schema)\n    - [`Schema.typeError(message: string): Schema`](#schematypeerrormessage-string-schema)\n    - [`Schema.oneOf(arrayOfValues: Array<any>, message?: string | function): Schema` Alias: `equals`](#schemaoneofarrayofvalues-arrayany-message-string--function-schema-alias-equals)\n    - [`Schema.notOneOf(arrayOfValues: Array<any>, message?: string | function)`](#schemanotoneofarrayofvalues-arrayany-message-string--function)\n    - [`Schema.when(keys: string | string[], builder: object | (values: any[], schema) => Schema): Schema`](#schemawhenkeys-string--string-builder-object--values-any-schema--schema-schema)\n    - [`Schema.test(name: string, message: string | function | any, test: function): Schema`](#schematestname-string-message-string--function--any-test-function-schema)\n    - [`Schema.test(options: object): Schema`](#schematestoptions-object-schema)\n    - [`Schema.transform((currentValue: any, originalValue: any, schema: Schema,  options: object) => any): Schema`](#schematransformcurrentvalue-any-originalvalue-any-schema-schema--options-object--any-schema)\n  - [mixed](#mixed)\n  - [string](#string)\n    - [`string.required(message?: string | function): Schema`](#stringrequiredmessage-string--function-schema)\n    - [`string.length(limit: number | Ref, message?: string | function): Schema`](#stringlengthlimit-number--ref-message-string--function-schema)\n    - [`string.min(limit: number | Ref, message?: string | function): Schema`](#stringminlimit-number--ref-message-string--function-schema)\n    - [`string.max(limit: number | Ref, message?: string | function): Schema`](#stringmaxlimit-number--ref-message-string--function-schema)\n    - [`string.matches(regex: Regex, message?: string | function): Schema`](#stringmatchesregex-regex-message-string--function-schema)\n    - [`string.matches(regex: Regex, options: { message: string, excludeEmptyString: bool }): Schema`](#stringmatchesregex-regex-options--message-string-excludeemptystring-bool--schema)\n    - [`string.email(message?: string | function): Schema`](#stringemailmessage-string--function-schema)\n    - [`string.url(message?: string | function): Schema`](#stringurlmessage-string--function-schema)\n    - [`string.uuid(message?: string | function): Schema`](#stringuuidmessage-string--function-schema)\n    - [`string.datetime(options?: {message?: string | function, allowOffset?: boolean, precision?: number})`](#stringdatetimeoptions-message-string--function-allowoffset-boolean-precision-number)\n    - [`string.datetime(message?: string | function)`](#stringdatetimemessage-string--function)\n    - [`string.ensure(): Schema`](#stringensure-schema)\n    - [`string.trim(message?: string | function): Schema`](#stringtrimmessage-string--function-schema)\n    - [`string.lowercase(message?: string | function): Schema`](#stringlowercasemessage-string--function-schema)\n    - [`string.uppercase(message?: string | function): Schema`](#stringuppercasemessage-string--function-schema)\n  - [number](#number)\n    - [`number.min(limit: number | Ref, message?: string | function): Schema`](#numberminlimit-number--ref-message-string--function-schema)\n    - [`number.max(limit: number | Ref, message?: string | function): Schema`](#numbermaxlimit-number--ref-message-string--function-schema)\n    - [`number.lessThan(max: number | Ref, message?: string | function): Schema`](#numberlessthanmax-number--ref-message-string--function-schema)\n    - [`number.moreThan(min: number | Ref, message?: string | function): Schema`](#numbermorethanmin-number--ref-message-string--function-schema)\n    - [`number.positive(message?: string | function): Schema`](#numberpositivemessage-string--function-schema)\n    - [`number.negative(message?: string | function): Schema`](#numbernegativemessage-string--function-schema)\n    - [`number.integer(message?: string | function): Schema`](#numberintegermessage-string--function-schema)\n    - [`number.truncate(): Schema`](#numbertruncate-schema)\n    - [`number.round(type: 'floor' | 'ceil' | 'trunc' | 'round' = 'round'): Schema`](#numberroundtype-floor--ceil--trunc--round--round-schema)\n  - [boolean](#boolean)\n  - [date](#date)\n    - [`date.min(limit: Date | string | Ref, message?: string | function): Schema`](#dateminlimit-date--string--ref-message-string--function-schema)\n    - [`date.max(limit: Date | string | Ref, message?: string | function): Schema`](#datemaxlimit-date--string--ref-message-string--function-schema)\n  - [array](#array)\n    - [`array.of(type: Schema): this`](#arrayoftype-schema-this)\n    - [`array.json(): this`](#arrayjson-this)\n    - [`array.length(length: number | Ref, message?: string | function): this`](#arraylengthlength-number--ref-message-string--function-this)\n    - [`array.min(limit: number | Ref, message?: string | function): this`](#arrayminlimit-number--ref-message-string--function-this)\n    - [`array.max(limit: number | Ref, message?: string | function): this`](#arraymaxlimit-number--ref-message-string--function-this)\n    - [`array.ensure(): this`](#arrayensure-this)\n    - [`array.compact(rejector: (value) => boolean): Schema`](#arraycompactrejector-value--boolean-schema)\n  - [tuple](#tuple)\n  - [object](#object)\n    - [Object schema defaults](#object-schema-defaults)\n    - [`object.shape(fields: object, noSortEdges?: Array<[string, string]>): Schema`](#objectshapefields-object-nosortedges-arraystring-string-schema)\n    - [`object.json(): this`](#objectjson-this)\n    - [`object.concat(schemaB: ObjectSchema): ObjectSchema`](#objectconcatschemab-objectschema-objectschema)\n    - [`object.pick(keys: string[]): Schema`](#objectpickkeys-string-schema)\n    - [`object.omit(keys: string[]): Schema`](#objectomitkeys-string-schema)\n    - [`object.from(fromKey: string, toKey: string, alias: boolean = false): this`](#objectfromfromkey-string-tokey-string-alias-boolean--false-this)\n    - [`object.exact(message?: string | function): Schema`](#objectexactmessage-string--function-schema)\n    - [`object.stripUnknown(): Schema`](#objectstripunknown-schema)\n    - [`object.noUnknown(onlyKnownKeys: boolean = true, message?: string | function): Schema`](#objectnounknownonlyknownkeys-boolean--true-message-string--function-schema)\n    - [`object.camelCase(): Schema`](#objectcamelcase-schema)\n    - [`object.constantCase(): Schema`](#objectconstantcase-schema)\n\n<!-- END doctoc generated TOC please keep comment here to allow auto update -->\n\n## Schema basics\n\nSchema definitions, are comprised of parsing \"transforms\" which manipulate inputs into the desired shape and type, \"tests\", which make assertions over parsed data. Schema also store a bunch of \"metadata\", details about the schema itself, which can be used to improve error messages, build tools that dynamically consume schema, or serialize schema into another format.\n\nIn order to be maximally flexible yup allows running both parsing and assertions separately to match specific needs\n\n### Parsing: Transforms\n\nEach built-in type implements basic type parsing, which comes in handy when parsing serialized data, such as JSON.\nAdditionally types implement type specific transforms that can be enabled.\n\n```ts\nlet num = number().cast('1'); // 1\n\nlet obj = object({\n  firstName: string().lowercase().trim(),\n})\n  .json()\n  .camelCase()\n  .cast('{\"first_name\": \"jAnE \"}'); // { firstName: 'jane' }\n```\n\nCustom transforms can be added\n\n```ts\nlet reversedString = string()\n  .transform((currentValue) => currentValue.split('').reverse().join(''))\n  .cast('dlrow olleh'); // \"hello world\"\n```\n\nTransforms form a \"pipeline\", where the value of a previous transform is piped into the next one.\nWhen an input value is `undefined` yup will apply the schema default if it's configured.\n\n> Watch out! values are not guaranteed to be valid types in transform functions. Previous transforms\n> may have failed. For example a number transform may be receive the input value, `NaN`, or a number.\n\n### Validation: Tests\n\nYup schema run \"tests\" over input values. Tests assert that inputs conform to some\ncriteria. Tests are distinct from transforms, in that they do not change or alter the input (or its type)\nand are usually reserved for checks that are hard, if not impossible, to represent in static types.\n\n```ts\nstring()\n  .min(3, 'must be at least 3 characters long')\n  .email('must be a valid email')\n  .validate('no'); // ValidationError\n```\n\nAs with transforms, tests can be customized on the fly\n\n```ts\nlet jamesSchema = string().test(\n  'is-james',\n  (d) => `${d.path} is not James`,\n  (value) => value == null || value === 'James',\n);\n\njamesSchema.validateSync('James'); // \"James\"\n\njamesSchema.validateSync('Jane'); // ValidationError \"this is not James\"\n```\n\n> Heads up: unlike transforms, `value` in a custom test is guaranteed to be the correct type\n> (in this case an optional string). It still may be `undefined` or `null` depending on your schema\n> in those cases, you may want to return `true` for absent values unless your transform makes presence\n> related assertions. The test option `skipAbsent` will do this for you if set.\n\n#### Customizing errors\n\nIn the simplest case a test function returns `true` or `false` depending on the whether the check\npassed. In the case of a failing test, yup will throw\na [`ValidationError`](#validationerrorerrors-string--arraystring-value-any-path-string) with your (or the default)\nmessage for that test. ValidationErrors also contain a bunch of other metadata about the test,\nincluding it's name, what arguments (if any) it was called with, and the path to the failing field\nin the case of a nested validation.\n\nError messages can also be constructed on the fly to customize how the schema fails.\n\n```ts\nlet order = object({\n  no: number().required(),\n  sku: string().test({\n    name: 'is-sku',\n    skipAbsent: true,\n    test(value, ctx) {\n      if (!value.startsWith('s-')) {\n        return ctx.createError({ message: 'SKU missing correct prefix' });\n      }\n      if (!value.endsWith('-42a')) {\n        return ctx.createError({ message: 'SKU missing correct suffix' });\n      }\n      if (value.length < 10) {\n        return ctx.createError({ message: 'SKU is not the right length' });\n      }\n      return true;\n    },\n  }),\n});\n\norder.validate({ no: 1234, sku: 's-1a45-14a' });\n```\n\n### Composition and Reuse\n\nSchema are immutable, each method call returns a new schema object. Reuse and pass them around without\nfear of mutating another instance.\n\n```ts\nlet optionalString = string().optional();\n\nlet definedString = optionalString.defined();\n\nlet value = undefined;\noptionalString.isValid(value); // true\ndefinedString.isValid(value); // false\n```\n\n## TypeScript integration\n\nYup schema produce static TypeScript interfaces. Use `InferType` to extract that interface:\n\n```ts\nimport * as yup from 'yup';\n\nlet personSchema = yup.object({\n  firstName: yup.string().defined(),\n  nickName: yup.string().default('').nullable(),\n  sex: yup\n    .mixed()\n    .oneOf(['male', 'female', 'other'] as const)\n    .defined(),\n  email: yup.string().nullable().email(),\n  birthDate: yup.date().nullable().min(new Date(1900, 0, 1)),\n});\n\ninterface Person extends yup.InferType<typeof personSchema> {\n  // using interface instead of type generally gives nicer editor feedback\n}\n```\n\n### Schema defaults\n\nA schema's default is used when casting produces an `undefined` output value. Because of this,\nsetting a default affects the output type of the schema, essentially marking it as \"defined()\".\n\n```ts\nimport { string } from 'yup';\n\nlet value: string = string().default('hi').validate(undefined);\n\n// vs\n\nlet value: string | undefined = string().validate(undefined);\n```\n\n### Ensuring a schema matches an existing type\n\nIn some cases a TypeScript type already exists, and you want to ensure that\nyour schema produces a compatible type:\n\n```ts\nimport { object, number, string, ObjectSchema } from 'yup';\n\ninterface Person {\n  name: string;\n  age?: number;\n  sex: 'male' | 'female' | 'other' | null;\n}\n\n// will raise a compile-time type error if the schema does not produce a valid Person\nlet schema: ObjectSchema<Person> = object({\n  name: string().defined(),\n  age: number().optional(),\n  sex: string<'male' | 'female' | 'other'>().nullable().defined(),\n});\n\n// ❌ errors:\n// \"Type 'number | undefined' is not assignable to type 'string'.\"\nlet badSchema: ObjectSchema<Person> = object({\n  name: number(),\n});\n```\n\n### Extending built-in schema with new methods\n\nYou can use TypeScript's interface merging behavior to extend the schema types\nif needed. Type extensions should go in an \"ambient\" type definition file such as your\n`globals.d.ts`. Remember to actually extend the yup type in your application code!\n\n> Watch out! merging only works if the type definition is _exactly_ the same, including\n> generics. Consult the yup source code for each type to ensure you are defining it correctly\n\n```ts\n// globals.d.ts\ndeclare module 'yup' {\n  interface StringSchema<TType, TContext, TDefault, TFlags> {\n    append(appendStr: string): this;\n  }\n}\n\n// app.ts\nimport { addMethod, string } from 'yup';\n\naddMethod(string, 'append', function append(appendStr: string) {\n  return this.transform((value) => `${value}${appendStr}`);\n});\n\nstring().append('~~~~').cast('hi'); // 'hi~~~~'\n```\n\n### TypeScript configuration\n\nYou **must** have the `strictNullChecks` compiler option enabled for type inference to work.\n\nWe also recommend settings `strictFunctionTypes` to `false`, for functionally better types. Yes\nthis reduces overall soundness, however TypeScript already disables this check\nfor methods and constructors (note from TS docs):\n\n> During development of this feature, we discovered a large number of inherently\n> unsafe class hierarchies, including some in the DOM. Because of this,\n> the setting only applies to functions written in function syntax, not to those in method syntax:\n\nYour mileage will vary, but we've found that this check doesn't prevent many of\nreal bugs, while increasing the amount of onerous explicit type casting in apps.\n\n## Error message customization\n\nDefault error messages can be customized for when no message is provided with a validation test.\nIf any message is missing in the custom dictionary the error message will default to Yup's one.\n\n```js\nimport { setLocale } from 'yup';\n\nsetLocale({\n  mixed: {\n    default: 'Não é válido',\n  },\n  number: {\n    min: 'Deve ser maior que ${min}',\n  },\n});\n\n// now use Yup schemas AFTER you defined your custom dictionary\nlet schema = yup.object().shape({\n  name: yup.string(),\n  age: yup.number().min(18),\n});\n\ntry {\n  await schema.validate({ name: 'jimmy', age: 11 });\n} catch (err) {\n  err.name; // => 'ValidationError'\n  err.errors; // => ['Deve ser maior que 18']\n}\n```\n\n### localization and i18n\n\nIf you need multi-language support, yup has got you covered. The function `setLocale` accepts functions that can be used to\ngenerate error objects with translation keys and values. These can be fed it into your favorite i18n library.\n\n```js\nimport { setLocale } from 'yup';\n\nsetLocale({\n  // use constant translation keys for messages without values\n  mixed: {\n    default: 'field_invalid',\n  },\n  // use functions to generate an error object that includes the value from the schema\n  number: {\n    min: ({ min }) => ({ key: 'field_too_short', values: { min } }),\n    max: ({ max }) => ({ key: 'field_too_big', values: { max } }),\n  },\n});\n\n// ...\n\nlet schema = yup.object().shape({\n  name: yup.string(),\n  age: yup.number().min(18),\n});\n\ntry {\n  await schema.validate({ name: 'jimmy', age: 11 });\n} catch (err) {\n  messages = err.errors.map((err) => i18next.t(err.key));\n}\n```\n\n## Standard Schema Support\n\nYup is compatible with [Standard Schema](https://github.com/standard-schema/standard-schema).\n\n## API\n\n### `yup`\n\nThe module export.\n\n```ts\n// core schema\nimport {\n  mixed,\n  string,\n  number,\n  boolean,\n  bool,\n  date,\n  object,\n  array,\n  ref,\n  lazy,\n} from 'yup';\n\n// Classes\nimport {\n  Schema,\n  MixedSchema,\n  StringSchema,\n  NumberSchema,\n  BooleanSchema,\n  DateSchema,\n  ArraySchema,\n  ObjectSchema,\n} from 'yup';\n\n// Types\nimport type { InferType, ISchema, AnySchema, AnyObjectSchema } from 'yup';\n```\n\n#### `reach(schema: Schema, path: string, value?: object, context?: object): Schema`\n\nFor nested schemas, `reach` will retrieve an inner schema based on the provided path.\n\nFor nested schemas that need to resolve dynamically, you can provide a `value` and optionally\na `context` object.\n\n```js\nimport { reach } from 'yup';\n\nlet schema = object({\n  nested: object({\n    arr: array(object({ num: number().max(4) })),\n  }),\n});\n\nreach(schema, 'nested.arr.num');\nreach(schema, 'nested.arr[].num');\nreach(schema, 'nested.arr[1].num');\nreach(schema, 'nested[\"arr\"][1].num');\n```\n\n#### `addMethod(schemaType: Schema, name: string, method: ()=> Schema): void`\n\nAdds a new method to the core schema types. A friendlier convenience method for `schemaType.prototype[name] = method`.\n\n```ts\nimport { addMethod, date } from 'yup';\n\naddMethod(date, 'format', function format(formats, parseStrict) {\n  return this.transform((value, originalValue, ctx) => {\n    if (ctx.isType(value)) return value;\n\n    value = Moment(originalValue, formats, parseStrict);\n\n    return value.isValid() ? value.toDate() : new Date('');\n  });\n});\n```\n\nIf you want to add a method to ALL schema types, extend the abstract base class: `Schema`\n\n```ts\nimport { addMethod, Schema } from 'yup';\n\naddMethod(Schema, 'myMethod', ...)\n```\n\n#### `ref(path: string, options: { contextPrefix: string }): Ref`\n\nCreates a reference to another sibling or sibling descendant field. Refs are resolved\nat _validation/cast time_ and supported where specified. Refs are evaluated in the proper order so that\nthe ref value is resolved before the field using the ref (be careful of circular dependencies!).\n\n```js\nimport { ref, object, string } from 'yup';\n\nlet schema = object({\n  baz: ref('foo.bar'),\n  foo: object({\n    bar: string(),\n  }),\n  x: ref('$x'),\n});\n\nschema.cast({ foo: { bar: 'boom' } }, { context: { x: 5 } });\n// => { baz: 'boom',  x: 5, foo: { bar: 'boom' } }\n```\n\n#### `lazy((value: any) => Schema): Lazy`\n\nCreates a schema that is evaluated at validation/cast time. Useful for creating\nrecursive schema like Trees, for polymorphic fields and arrays.\n\n**CAUTION!** When defining parent-child recursive object schema, you want to reset the `default()`\nto `null` on the child—otherwise the object will infinitely nest itself when you cast it!\n\n```js\nlet node = object({\n  id: number(),\n  child: yup.lazy(() => node.default(undefined)),\n});\n\nlet renderable = yup.lazy((value) => {\n  switch (typeof value) {\n    case 'number':\n      return number();\n    case 'string':\n      return string();\n    default:\n      return mixed();\n  }\n});\n\nlet renderables = array().of(renderable);\n```\n\n#### `ValidationError(errors: string | Array<string>, value: any, path: string)`\n\nThrown on failed validations, with the following properties\n\n- `name`: \"ValidationError\"\n- `type`: the specific test type or test \"name\", that failed.\n- `value`: The field value that was tested;\n- `params`?: The test inputs, such as max value, regex, etc;\n- `path`: a string, indicating where there error was thrown. `path` is empty at the root level.\n- `errors`: array of error messages\n- `inner`: in the case of aggregate errors, inner is an array of `ValidationErrors` throw earlier in the\n  validation chain. When the `abortEarly` option is `false` this is where you can inspect each error thrown,\n  alternatively, `errors` will have all of the messages from each inner error.\n\n### `Schema`\n\n`Schema` is the abstract base class that all schema type inherit from. It provides a number of base methods and properties\nto all other schema types.\n\n> Note: unless you are creating a custom schema type, Schema should never be used directly. For unknown/any types use [`mixed()`](#mixed)\n\n#### `Schema.clone(): Schema`\n\nCreates a deep copy of the schema. Clone is used internally to return a new schema with every schema state change.\n\n#### `Schema.label(label: string): Schema`\n\nOverrides the key name which is used in error messages.\n\n#### `Schema.meta(metadata: SchemaMetadata): Schema`\n\nAdds to a metadata object, useful for storing data with a schema, that doesn't belong\nto the cast object itself.\n\nA custom `SchemaMetadata` interface can be defined through\n[merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces)\nwith the `CustomSchemaMetadata` interface. Start by creating a `yup.d.ts` file\nin your package and creating your desired `CustomSchemaMetadata` interface:\n\n```ts\n// yup.d.ts\nimport 'yup';\n\ndeclare module 'yup' {\n  // Define your desired `SchemaMetadata` interface by merging the\n  // `CustomSchemaMetadata` interface.\n  export interface CustomSchemaMetadata {\n    placeholderText?: string;\n    tooltipText?: string;\n    // …\n  }\n}\n```\n\n#### `Schema.describe(options?: ResolveOptions): SchemaDescription`\n\nCollects schema details (like meta, labels, and active tests) into a serializable\ndescription object.\n\n```ts\nlet schema = object({\n  name: string().required(),\n});\n\nlet description = schema.describe();\n```\n\nFor schema with dynamic components (references, lazy, or conditions), describe requires\nmore context to accurately return the schema description. In these cases provide `options`\n\n```ts\nimport { ref, object, string, boolean } from 'yup';\n\nlet schema = object({\n  isBig: boolean(),\n  count: number().when('isBig', {\n    is: true,\n    then: (schema) => schema.min(5),\n    otherwise: (schema) => schema.min(0),\n  }),\n});\n\nschema.describe({ value: { isBig: true } });\n```\n\nAnd below are the description types, which differ a bit depending on the schema type.\n\n```ts\ninterface SchemaDescription {\n  type: string;\n  label?: string;\n  meta: object | undefined;\n  oneOf: unknown[];\n  notOneOf: unknown[];\n  default?: unknown;\n  nullable: boolean;\n  optional: boolean;\n  tests: Array<{ name?: string; params: ExtraParams | undefined }>;\n\n  // Present on object schema descriptions\n  fields: Record<string, SchemaFieldDescription>;\n\n  // Present on array schema descriptions\n  innerType?: SchemaFieldDescription;\n}\n\ntype SchemaFieldDescription =\n  | SchemaDescription\n  | SchemaRefDescription\n  | SchemaLazyDescription;\n\ninterface SchemaRefDescription {\n  type: 'ref';\n  key: string;\n}\n\ninterface SchemaLazyDescription {\n  type: string;\n  label?: string;\n  meta: object | undefined;\n}\n```\n\n#### `Schema.concat(schema: Schema): Schema`\n\nCreates a new instance of the schema by combining two schemas. Only schemas of the same type can be concatenated.\n`concat` is not a \"merge\" function in the sense that all settings from the provided schema, override ones in the\nbase, including type, presence and nullability.\n\n```ts\nmixed<string>().defined().concat(mixed<number>().nullable());\n\n// produces the equivalent to:\n\nmixed<number>().defined().nullable();\n```\n\n#### `Schema.validate(value: any, options?: object): Promise<InferType<Schema>, ValidationError>`\n\nReturns the parses and validates an input value, returning the parsed value or throwing an error. This method is **asynchronous** and returns a Promise object, that is fulfilled with the value, or rejected\nwith a `ValidationError`.\n\n```js\nvalue = await schema.validate({ name: 'jimmy', age: 24 });\n```\n\nProvide `options` to more specifically control the behavior of `validate`.\n\n```js\ninterface Options {\n  // when true, parsing is skipped and the input is validated \"as-is\"\n  strict: boolean = false;\n  // Throw on the first error or collect and return all\n  abortEarly: boolean = true;\n  // Remove unspecified keys from objects\n  stripUnknown: boolean = false;\n  // when `false` validations will be performed shallowly\n  recursive: boolean = true;\n  // External values that can be provided to validations and conditionals\n  context?: object;\n}\n```\n\n#### `Schema.validateSync(value: any, options?: object): InferType<Schema>`\n\nRuns validatations synchronously _if possible_ and returns the resulting value,\nor throws a ValidationError. Accepts all the same options as `validate`.\n\nSynchronous validation only works if there are no configured async tests, e.g tests that return a Promise.\nFor instance this will work:\n\n```js\nlet schema = number().test(\n  'is-42',\n  \"this isn't the number i want\",\n  (value) => value != 42,\n);\n\nschema.validateSync(23); // throws ValidationError\n```\n\nhowever this will not:\n\n```js\nlet schema = number().test('is-42', \"this isn't the number i want\", (value) =>\n  Promise.resolve(value != 42),\n);\n\nschema.validateSync(42); // throws Error\n```\n\n#### `Schema.validateAt(path: string, value: any, options?: object): Promise<InferType<Schema>, ValidationError>`\n\nValidate a deeply nested path within the schema. Similar to how `reach` works,\nbut uses the resulting schema as the subject for validation.\n\n> Note! The `value` here is the _root_ value relative to the starting schema, not the value at the nested path.\n\n```js\nlet schema = object({\n  foo: array().of(\n    object({\n      loose: boolean(),\n      bar: string().when('loose', {\n        is: true,\n        otherwise: (schema) => schema.strict(),\n      }),\n    }),\n  ),\n});\n\nlet rootValue = {\n  foo: [{ bar: 1 }, { bar: 1, loose: true }],\n};\n\nawait schema.validateAt('foo[0].bar', rootValue); // => ValidationError: must be a string\n\nawait schema.validateAt('foo[1].bar', rootValue); // => '1'\n```\n\n#### `Schema.validateSyncAt(path: string, value: any, options?: object): InferType<Schema>`\n\nSame as `validateAt` but synchronous.\n\n#### `Schema.isValid(value: any, options?: object): Promise<boolean>`\n\nReturns `true` when the passed in value matches the schema. `isValid`\nis **asynchronous** and returns a Promise object.\n\nTakes the same options as `validate()`.\n\n#### `Schema.isValidSync(value: any, options?: object): boolean`\n\nSynchronously returns `true` when the passed in value matches the schema.\n\nTakes the same options as `validateSync()` and has the same caveats around async tests.\n\n#### `Schema.cast(value: any, options = {}): InferType<Schema>`\n\nAttempts to coerce the passed in value to a value that matches the schema. For example: `'5'` will\ncast to `5` when using the `number()` type. Failed casts generally return `null`, but may also\nreturn results like `NaN` and unexpected strings.\n\nProvide `options` to more specifically control the behavior of `validate`.\n\n```js\ninterface CastOptions<TContext extends {}> {\n  // Remove undefined properties from objects\n  stripUnknown: boolean = false;\n\n  // Throws a TypeError if casting doesn't produce a valid type\n  // note that the TS return type is inaccurate when this is `false`, use with caution\n  assert?: boolean = true;\n\n  // External values that used to resolve conditions and references\n  context?: TContext;\n}\n```\n\n#### `Schema.isType(value: any): value is InferType<Schema>`\n\nRuns a type check against the passed in `value`. It returns true if it matches,\nit does not cast the value. When `nullable()` is set `null` is considered a valid value of the type.\nYou should use `isType` for all Schema type checks.\n\n#### `Schema.strict(enabled: boolean = false): Schema`\n\nSets the `strict` option to `true`. Strict schemas skip coercion and transformation attempts,\nvalidating the value \"as is\".\n\n#### `Schema.strip(enabled: boolean = true): Schema`\n\nMarks a schema to be removed from an output object. Only works as a nested schema.\n\n```js\nlet schema = object({\n  useThis: number(),\n  notThis: string().strip(),\n});\n\nschema.cast({ notThis: 'foo', useThis: 4 }); // => { useThis: 4 }\n```\n\nSchema with `strip` enabled have an inferred type of `never`, allowing them to be\nremoved from the overall type:\n\n```ts\nlet schema = object({\n  useThis: number(),\n  notThis: string().strip(),\n});\n\nInferType<typeof schema>; /*\n{\n   useThis?: number | undefined\n}\n*/\n```\n\n#### `Schema.withMutation(builder: (current: Schema) => void): void`\n\nFirst the legally required Rich Hickey quote:\n\n> If a tree falls in the woods, does it make a sound?\n>\n> If a pure function mutates some local data in order to produce an immutable return value, is that ok?\n\n`withMutation` allows you to mutate the schema in place, instead of the default behavior which clones before each change. Generally this isn't necessary since the vast majority of schema changes happen during the initial\ndeclaration, and only happen once over the lifetime of the schema, so performance isn't an issue.\nHowever certain mutations _do_ occur at cast/validation time, (such as conditional schema using [`when()`](#schemawhenkeys-string--string-builder-object--values-any-schema--schema-schema)), or\nwhen instantiating a schema object.\n\n```js\nobject()\n  .shape({ key: string() })\n  .withMutation((schema) => {\n    return arrayOfObjectTests.forEach((test) => {\n      schema.test(test);\n    });\n  });\n```\n\n#### `Schema.default(value: any): Schema`\n\nSets a default value to use when the value is `undefined`.\nDefaults are created after transformations are executed, but before validations, to help ensure that safe\ndefaults are specified. The default value will be cloned on each use, which can incur performance penalty\nfor objects and arrays. To avoid this overhead you can also pass a function that returns a new default.\nNote that `null` is considered a separate non-empty value.\n\n```js\nyup.string.default('nothing');\n\nyup.object.default({ number: 5 }); // object will be cloned every time a default is needed\n\nyup.object.default(() => ({ number: 5 })); // this is cheaper\n\nyup.date.default(() => new Date()); // also helpful for defaults that change over time\n```\n\n#### `Schema.getDefault(options?: object): Any`\n\nRetrieve a previously set default value. `getDefault` will resolve any conditions that may alter the default. Optionally pass `options` with `context` (for more info on `context` see `Schema.validate`).\n\n#### `Schema.nullable(message?: string | function): Schema`\n\nIndicates that `null` is a valid value for the schema. Without `nullable()`\n`null` is treated as a different type and will fail `Schema.isType()` checks.\n\n```ts\nlet schema = number().nullable();\n\nschema.cast(null); // null\n\nInferType<typeof schema>; // number | null\n```\n\n#### `Schema.nonNullable(message?: string | function): Schema`\n\nThe opposite of `nullable`, removes `null` from valid type values for the schema.\n**Schema are non nullable by default**.\n\n```ts\nlet schema = number().nonNullable();\n\nschema.cast(null); // TypeError\n\nInferType<typeof schema>; // number\n```\n\n#### `Schema.defined(): Schema`\n\nRequire a value for the schema. All field values apart from `undefined` meet this requirement.\n\n```ts\nlet schema = string().defined();\n\nschema.cast(undefined); // TypeError\n\nInferType<typeof schema>; // string\n```\n\n#### `Schema.optional(): Schema`\n\nThe opposite of `defined()` allows `undefined` values for the given type.\n\n```ts\nlet schema = string().optional();\n\nschema.cast(undefined); // undefined\n\nInferType<typeof schema>; // string | undefined\n```\n\n#### `Schema.required(message?: string | function): Schema`\n\nMark the schema as required, which will not allow `undefined` or `null` as a value. `required`\nnegates the effects of calling `optional()` and `nullable()`\n\n> Watch out! [`string().required`](#stringrequiredmessage-string--function-schema)) works a little\n> different and additionally prevents empty string values (`''`) when required.\n\n#### `Schema.notRequired(): Schema`\n\nMark the schema as not required. This is a shortcut for `schema.nullable().optional()`;\n\n#### `Schema.typeError(message: string): Schema`\n\nDefine an error message for failed type checks. The `${value}` and `${type}` interpolation can\nbe used in the `message` argument.\n\n#### `Schema.oneOf(arrayOfValues: Array<any>, message?: string | function): Schema` Alias: `equals`\n\nOnly allow values from set of values. Values added are removed from any `notOneOf` values if present.\nThe `${values}` interpolation can be used in the `message` argument. If a ref or refs are provided,\nthe `${resolved}` interpolation can be used in the message argument to get the resolved values that were checked\nat validation time.\n\nNote that `undefined` does not fail this validator, even when `undefined` is not included in `arrayOfValues`.\nIf you don't want `undefined` to be a valid value, you can use `Schema.required`.\n\n```js\nlet schema = yup.mixed().oneOf(['jimmy', 42]);\n\nawait schema.isValid(42); // => true\nawait schema.isValid('jimmy'); // => true\nawait schema.isValid(new Date()); // => false\n```\n\n#### `Schema.notOneOf(arrayOfValues: Array<any>, message?: string | function)`\n\nDisallow values from a set of values. Values added are removed from `oneOf` values if present.\nThe `${values}` interpolation can be used in the `message` argument. If a ref or refs are provided,\nthe `${resolved}` interpolation can be used in the message argument to get the resolved values that were checked\nat validation time.\n\n```js\nlet schema = yup.mixed().notOneOf(['jimmy', 42]);\n\nawait schema.isValid(42); // => false\nawait schema.isValid(new Date()); // => true\n```\n\n#### `Schema.when(keys: string | string[], builder: object | (values: any[], schema) => Schema): Schema`\n\nAdjust the schema based on a sibling or sibling children fields. You can provide an object\nliteral where the key `is` is value or a matcher function, `then` provides the true schema and/or\n`otherwise` for the failure condition.\n\n`is` conditions are strictly compared (`===`) if you want to use a different form of equality you\ncan provide a function like: `is: (value) => value == true`.\n\nYou can also prefix properties with `$` to specify a property that is dependent\non `context` passed in by `validate()` or `cast` instead of the input value.\n\n`when` conditions are additive.\n\n`then` and `otherwise` are specified functions `(schema: Schema) => Schema`.\n\n```js\nlet schema = object({\n  isBig: boolean(),\n  count: number()\n    .when('isBig', {\n      is: true, // alternatively: (val) => val == true\n      then: (schema) => schema.min(5),\n      otherwise: (schema) => schema.min(0),\n    })\n    .when('$other', ([other], schema) =>\n      other === 4 ? schema.max(6) : schema,\n    ),\n});\n\nawait schema.validate(value, { context: { other: 4 } });\n```\n\nYou can also specify more than one dependent key, in which case each value will be spread as an argument.\n\n```js\nlet schema = object({\n  isSpecial: boolean(),\n  isBig: boolean(),\n  count: number().when(['isBig', 'isSpecial'], {\n    is: true, // alternatively: (isBig, isSpecial) => isBig && isSpecial\n    then: (schema) => schema.min(5),\n    otherwise: (schema) => schema.min(0),\n  }),\n});\n\nawait schema.validate({\n  isBig: true,\n  isSpecial: true,\n  count: 10,\n});\n```\n\nAlternatively you can provide a function that returns a schema, called with an array of values for each provided key the current schema.\n\n```js\nlet schema = yup.object({\n  isBig: yup.boolean(),\n  count: yup.number().when('isBig', ([isBig], schema) => {\n    return isBig ? schema.min(5) : schema.min(0);\n  }),\n});\n\nawait schema.validate({ isBig: false, count: 4 });\n```\n\n#### `Schema.test(name: string, message: string | function | any, test: function): Schema`\n\nAdds a test function to the validation chain. Tests are run after any object is cast.\nMany types have some tests built in, but you can create custom ones easily.\nIn order to allow asynchronous custom validations _all_ (or no) tests are run asynchronously.\nA consequence of this is that test execution order cannot be guaranteed.\n\nAll tests must provide a `name`, an error `message` and a validation function that must return\n`true` when the current `value` is valid and `false` or a `ValidationError` otherwise.\nTo make a test async return a promise that resolves `true` or `false` or a `ValidationError`.\n\nFor the `message` argument you can provide a string which will interpolate certain values\nif specified using the `${param}` syntax. By default all test messages are passed a `path` value\nwhich is valuable in nested schemas.\n\nThe `test` function is called with the current `value`. For more advanced validations you can\nuse the alternate signature to provide more options (see below):\n\n```js\nlet jimmySchema = string().test(\n  'is-jimmy',\n  '${path} is not Jimmy',\n  (value, context) => value === 'jimmy',\n);\n\n// or make it async by returning a promise\nlet asyncJimmySchema = string()\n  .label('First name')\n  .test(\n    'is-jimmy',\n    ({ label }) => `${label} is not Jimmy`, // a message can also be a function\n    async (value, testContext) =>\n      (await fetch('/is-jimmy/' + value)).responseText === 'true',\n  );\n\nawait schema.isValid('jimmy'); // => true\nawait schema.isValid('john'); // => false\n```\n\nTest functions are called with a special context value, as the second argument, that exposes some useful metadata\nand functions. For non arrow functions, the test context is also set as the function `this`. Watch out, if you access\nit via `this` it won't work in an arrow function.\n\n- `testContext.path`: the string path of the current validation\n- `testContext.schema`: the resolved schema object that the test is running against.\n- `testContext.options`: the `options` object that validate() or isValid() was called with\n- `testContext.parent`: in the case of nested schema, this is the value of the parent object\n- `testContext.originalValue`: the original value that is being tested\n- `testContext.createError(Object: { path: String, message: String, params: Object })`: create and return a\n  validation error. Useful for dynamically setting the `path`, `params`, or more likely, the error `message`.\n  If either option is omitted it will use the current path, or default message.\n\n#### `Schema.test(options: object): Schema`\n\nAlternative `test(..)` signature. `options` is an object containing some of the following options:\n\n```js\nOptions = {\n  // unique name identifying the test\n  name: string;\n  // test function, determines schema validity\n  test: (value: any) => boolean;\n  // the validation error message\n  message: string;\n  // values passed to message for interpolation\n  params: ?object;\n  // mark the test as exclusive, meaning only one test of the same name can be active at once\n  exclusive: boolean = false;\n}\n```\n\nIn the case of mixing exclusive and non-exclusive tests the following logic is used.\nIf a non-exclusive test is added to a schema with an exclusive test of the same name\nthe exclusive test is removed and further tests of the same name will be stacked.\n\nIf an exclusive test is added to a schema with non-exclusive tests of the same name\nthe previous tests are removed and further tests of the same name will replace each other.\n\n```js\nlet max = 64;\nlet schema = yup.string().test({\n  name: 'max',\n  exclusive: true,\n  params: { max },\n  message: '${path} must be less than ${max} characters',\n  test: (value) => value == null || value.length <= max,\n});\n```\n\n#### `Schema.transform((currentValue: any, originalValue: any, schema: Schema,  options: object) => any): Schema`\n\nAdds a transformation to the transform chain. Transformations are central to the casting process,\ndefault transforms for each type coerce values to the specific type (as verified by [`isType()`](#schemaistypevalue-any-value-is-infertypeschema)). transforms are run before validations and only applied when the schema is not marked as `strict` (the default). Some types have built in transformations.\n\nTransformations are useful for arbitrarily altering how the object is cast, **however, you should take care\nnot to mutate the passed in value.** Transforms are run sequentially so each `value` represents the\ncurrent state of the cast, you can use the `originalValue` param if you need to work on the raw initial value.\n\n```js\nlet schema = string().transform((value, originalValue) => {\n  return this.isType(value) && value !== null ? value.toUpperCase() : value;\n});\n\nschema.cast('jimmy'); // => 'JIMMY'\n```\n\nEach types will handle basic coercion of values to the proper type for you, but occasionally\nyou may want to adjust or refine the default behavior. For example, if you wanted to use a different\ndate parsing strategy than the default one you could do that with a transform.\n\n```js\nmodule.exports = function (formats = 'MMM dd, yyyy') {\n  return date().transform((value, originalValue, context) => {\n    // check to see if the previous transform already parsed the date\n    if (context.isType(value)) return value;\n\n    // the default coercion failed so let's try it with Moment.js instead\n    value = Moment(originalValue, formats);\n\n    // if it's valid return the date object, otherwise return an `InvalidDate`\n    return value.isValid() ? value.toDate() : new Date('');\n  });\n};\n```\n\n### mixed\n\nCreates a schema that matches all types, or just the ones you configure. Inherits from [`Schema`](#Schema).\nMixed types extends `{}` by default instead of `any` or `unknown`. This is because in TypeScript `{}` means\nanything that isn't `null` or `undefined` which yup treats distinctly.\n\n```ts\nimport { mixed, InferType } from 'yup';\n\nlet schema = mixed().nullable();\n\nschema.validateSync('string'); // 'string';\n\nschema.validateSync(1); // 1;\n\nschema.validateSync(new Date()); // Date;\n\nInferType<typeof schema>; // {} | undefined\n\nInferType<typeof schema.nullable().defined()>; // {} | null\n```\n\nCustom types can be implemented by passing a type `check` function. This will also\nnarrow the TypeScript type for the schema.\n\n```ts\nimport { mixed, InferType } from 'yup';\n\nlet objectIdSchema = yup\n  .mixed((input): input is ObjectId => input instanceof ObjectId)\n  .transform((value: any, input, ctx) => {\n    if (ctx.isType(value)) return value;\n    return new ObjectId(value);\n  });\n\nawait objectIdSchema.validate(ObjectId('507f1f77bcf86cd799439011')); // ObjectId(\"507f1f77bcf86cd799439011\")\n\nawait objectIdSchema.validate('507f1f77bcf86cd799439011'); // ObjectId(\"507f1f77bcf86cd799439011\")\n\nInferType<typeof objectIdSchema>; // ObjectId\n```\n\n### string\n\nDefine a string schema. Inherits from [`Schema`](#Schema).\n\n```js\nlet schema = yup.string();\n\nawait schema.isValid('hello'); // => true\n```\n\nBy default, the `cast` logic of `string` is to call `toString` on the value if it exists.\n\nempty values are not coerced (use `ensure()` to coerce empty values to empty strings).\n\nFailed casts return the input value.\n\n#### `string.required(message?: string | function): Schema`\n\nThe same as the `mixed()` schema required, **except** that empty strings are also considered 'missing' values.\n\n#### `string.length(limit: number | Ref, message?: string | function): Schema`\n\nSet a required length for the string value. The `${length}` interpolation can be used in the `message` argument\n\n#### `string.min(limit: number | Ref, message?: string | function): Schema`\n\nSet a minimum length limit for the string value. The `${min}` interpolation can be used in the `message` argument\n\n#### `string.max(limit: number | Ref, message?: string | function): Schema`\n\nSet a maximum length limit for the string value. The `${max}` interpolation can be used in the `message` argument\n\n#### `string.matches(regex: Regex, message?: string | function): Schema`\n\nProvide an arbitrary `regex` to match the value against.\n\n```js\nlet schema = string().matches(/(hi|bye)/);\n\nawait schema.isValid('hi'); // => true\nawait schema.isValid('nope'); // => false\n```\n\n#### `string.matches(regex: Regex, options: { message: string, excludeEmptyString: bool }): Schema`\n\nAn alternate signature for `string.matches` with an options object. `excludeEmptyString`, when true,\nshort circuits the regex test when the value is an empty string, making it a easier to avoid\nmatching nothing without complicating the regex.\n\n```js\nlet schema = string().matches(/(hi|bye)/, { excludeEmptyString: true });\n\nawait schema.isValid(''); // => true\n```\n\n#### `string.email(message?: string | function): Schema`\n\nValidates the value as an email address using the same regex as defined by the HTML spec.\n\nWATCH OUT: Validating email addresses is nearly impossible with just code. Different\nclients and servers accept different things and many diverge from the various specs defining\n\"valid\" emails. The ONLY real way to validate an email address is to send a verification email\nto it and check that the user got it. With that in mind, yup picks a relatively simple regex\nthat does not cover all cases, but aligns with browser input validation behavior since HTML\nforms are a common use case for yup.\n\nIf you have more specific needs please override the email method with your own logic or regex:\n\n```ts\nyup.addMethod(yup.string, 'email', function validateEmail(message) {\n  return this.matches(myEmailRegex, {\n    message,\n    name: 'email',\n    excludeEmptyString: true,\n  });\n});\n```\n\n#### `string.url(message?: string | function): Schema`\n\nValidates the value as a valid URL via a regex.\n\n#### `string.uuid(message?: string | function): Schema`\n\nValidates the value as a valid UUID via a regex.\n\n#### `string.datetime(options?: {message?: string | function, allowOffset?: boolean, precision?: number})`\n\nValidates the value as an ISO datetime via a regex. Defaults to UTC validation; timezone offsets are not permitted (see `options.allowOffset`).\n\nUnlike `.date()`, `datetime` will not convert the string to a `Date` object. `datetime` also provides greater customization over the required format of the datetime string than `date` does.\n\n`options.allowOffset`: Allow a time zone offset. False requires UTC 'Z' timezone. _(default: false)_\n`options.precision`: Require a certain sub-second precision on the date. _(default: null -- any (or no) sub-second precision)_\n\n#### `string.datetime(message?: string | function)`\n\nAn alternate signature for `string.datetime` that can be used when you don't need to pass options other than `message`.\n\n#### `string.ensure(): Schema`\n\nTransforms `undefined` and `null` values to an empty string along with\nsetting the `default` to an empty string.\n\n#### `string.trim(message?: string | function): Schema`\n\nTransforms string values by removing leading and trailing whitespace. If\n`strict()` is set it will only validate that the value is trimmed.\n\n#### `string.lowercase(message?: string | function): Schema`\n\nTransforms the string value to lowercase. If `strict()` is set it\nwill only validate that the value is lowercase.\n\n#### `string.uppercase(message?: string | function): Schema`\n\nTransforms the string value to uppercase. If `strict()` is set it\nwill only validate that the value is uppercase.\n\n### number\n\nDefine a number schema. Inherits from [`Schema`](#Schema).\n\n```js\nlet schema = yup.number();\n\nawait schema.isValid(10); // => true\n```\n\nThe default `cast` logic of `number` is: [`parseFloat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat).\n\nFailed casts return `NaN`.\n\n#### `number.min(limit: number | Ref, message?: string | function): Schema`\n\nSet the minimum value allowed. The `${min}` interpolation can be used in the\n`message` argument.\n\n#### `number.max(limit: number | Ref, message?: string | function): Schema`\n\nSet the maximum value allowed. The `${max}` interpolation can be used in the\n`message` argument.\n\n#### `number.lessThan(max: number | Ref, message?: string | function): Schema`\n\nValue must be less than `max`. The `${less}` interpolation can be used in the\n`message` argument.\n\n#### `number.moreThan(min: number | Ref, message?: string | function): Schema`\n\nValue must be strictly greater than `min`. The `${more}` interpolation can be used in the\n`message` argument.\n\n#### `number.positive(message?: string | function): Schema`\n\nValue must be a positive number.\n\n#### `number.negative(message?: string | function): Schema`\n\nValue must be a negative number.\n\n#### `number.integer(message?: string | function): Schema`\n\nValidates that a number is an integer.\n\n#### `number.truncate(): Schema`\n\nTransformation that coerces the value to an integer by stripping off the digits\nto the right of the decimal point.\n\n#### `number.round(type: 'floor' | 'ceil' | 'trunc' | 'round' = 'round'): Schema`\n\nAdjusts the value via the specified method of `Math` (defaults to 'round').\n\n### boolean\n\nDefine a boolean schema. Inherits from [`Schema`](#Schema).\n\n```js\nlet schema = yup.boolean();\n\nawait schema.isValid(true); // => true\n```\n\n### date\n\nDefine a Date schema. By default ISO date strings will parse correctly,\nfor more robust parsing options see the extending schema types at the end of the readme.\nInherits from [`Schema`](#Schema).\n\n```js\nlet schema = yup.date();\n\nawait schema.isValid(new Date()); // => true\n```\n\nThe default `cast` logic of `date` is pass the value to the `Date` constructor, failing that, it will attempt\nto parse the date as an ISO date string.\n\n> If you would like ISO strings to not be cast to a `Date` object, use `.datetime()` instead.\n\nFailed casts return an invalid Date.\n\n#### `date.min(limit: Date | string | Ref, message?: string | function): Schema`\n\nSet the minimum date allowed. When a string is provided it will attempt to cast to a date first\nand use the result as the limit.\n\n#### `date.max(limit: Date | string | Ref, message?: string | function): Schema`\n\nSet the maximum date allowed, When a string is provided it will attempt to cast to a date first\nand use the result as the limit.\n\n### array\n\nDefine an array schema. Arrays can be typed or not, When specifying the element type, `cast` and `isValid`\nwill apply to the elements as well. Options passed into `isValid` are also passed to child schemas.\n\nInherits from [`Schema`](#Schema).\n\n```js\nlet schema = yup.array().of(yup.number().min(2));\n\nawait schema.isValid([2, 3]); // => true\nawait schema.isValid([1, -24]); // => false\n\nschema.cast(['2', '3']); // => [2, 3]\n```\n\nYou can also pass a subtype schema to the array constructor as a convenience.\n\n```js\narray().of(yup.number());\n// or\narray(yup.number());\n```\n\nArrays have no default casting behavior.\n\n#### `array.of(type: Schema): this`\n\nSpecify the schema of array elements. `of()` is optional and when omitted the array schema will\nnot validate its contents.\n\n#### `array.json(): this`\n\nAttempt to parse input string values as JSON using [`JSON.parse`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse).\n\n#### `array.length(length: number | Ref, message?: string | function): this`\n\nSet a specific length requirement for the array. The `${length}` interpolation can be used in the `message` argument.\n\n#### `array.min(limit: number | Ref, message?: string | function): this`\n\nSet a minimum length limit for the array. The `${min}` interpolation can be used in the `message` argument.\n\n#### `array.max(limit: number | Ref, message?: string | function): this`\n\nSet a maximum length limit for the array. The `${max}` interpolation can be used in the `message` argument.\n\n#### `array.ensure(): this`\n\nEnsures that the value is an array, by setting the default to `[]` and transforming `null` and `undefined`\nvalues to an empty array as well. Any non-empty, non-array value will be wrapped in an array.\n\n```js\narray().ensure().cast(null); // => []\narray().ensure().cast(1); // => [1]\narray().ensure().cast([1]); // => [1]\n```\n\n#### `array.compact(rejector: (value) => boolean): Schema`\n\nRemoves falsey values from the array. Providing a rejecter function lets you specify the rejection criteria yourself.\n\n```js\narray().compact().cast(['', 1, 0, 4, false, null]); // => [1, 4]\n\narray()\n  .compact(function (v) {\n    return v == null;\n  })\n  .cast(['', 1, 0, 4, false, null]); // => ['', 1, 0, 4, false]\n```\n\n### tuple\n\nTuples, are fixed length arrays where each item has a distinct type.\n\nInherits from [`Schema`](#Schema).\n\n```js\nimport { tuple, string, number, InferType } from 'yup';\n\nlet schema = tuple([\n  string().label('name'),\n  number().label('age').positive().integer(),\n]);\n\nawait schema.validate(['James', 3]); // ['James', 3]\n\nawait schema.validate(['James', -24]); // => ValidationError: age must be a positive number\n\nInferType<typeof schema> // [string, number] | undefined\n```\n\ntuples have no default casting behavior.\n\n### object\n\nDefine an object schema. Options passed into `isValid` are also passed to child schemas.\nInherits from [`Schema`](#Schema).\n\n```js\nyup.object({\n  name: string().required(),\n  age: number().required().positive().integer(),\n  email: string().email(),\n  website: string().url(),\n});\n```\n\nobject schema do not have any default transforms applied.\n\n#### Object schema defaults\n\nObject schema come with a default value already set, which \"builds\" out the object shape, a\nsets any defaults for fields:\n\n```js\nlet schema = object({\n  name: string().default(''),\n});\n\nschema.default(); // -> { name: '' }\n```\n\nThis may be a bit surprising, but is usually helpful since it allows large, nested\nschema to create default values that fill out the whole shape and not just the root object. There is\none gotcha! though. For nested object schema that are optional but include non optional fields\nmay fail in unexpected ways:\n\n```js\nlet schema = object({\n  id: string().required(),\n  names: object({\n    first: string().required(),\n  }),\n});\n\nschema.isValid({ id: 1 }); // false! names.first is required\n```\n\nThis is because yup casts the input object before running validation\nwhich will produce:\n\n> `{ id: '1', names: { first: undefined }}`\n\nDuring the validation phase `names` exists, and is validated, finding `names.first` missing.\nIf you wish to avoid this behavior do one of the following:\n\n- Set the nested default to undefined: `names.default(undefined)`\n- mark it nullable and default to null: `names.nullable().default(null)`\n\n#### `object.shape(fields: object, noSortEdges?: Array<[string, string]>): Schema`\n\nDefine the keys of the object and the schemas for said keys.\n\nNote that you can chain `shape` method, which acts like `Object.assign`.\n\n```ts\nobject({\n  a: string(),\n  b: number(),\n}).shape({\n  b: string(),\n  c: number(),\n});\n```\n\nwould be exactly the same as:\n\n```ts\nobject({\n  a: string(),\n  b: string(),\n  c: number(),\n});\n```\n\n#### `object.json(): this`\n\nAttempt to parse input string values as JSON using [`JSON.parse`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse).\n\n#### `object.concat(schemaB: ObjectSchema): ObjectSchema`\n\nCreates a object schema, by applying all settings and fields from `schemaB` to the base, producing a new schema.\nThe object shape is shallowly merged with common fields from `schemaB` taking precedence over the base\nfields.\n\n#### `object.pick(keys: string[]): Schema`\n\nCreate a new schema from a subset of the original's fields.\n\n```js\nlet person = object({\n  age: number().default(30).required(),\n  name: string().default('pat').required(),\n  color: string().default('red').required(),\n});\n\nlet nameAndAge = person.pick(['name', 'age']);\nnameAndAge.getDefault(); // => { age: 30, name: 'pat'}\n```\n\n#### `object.omit(keys: string[]): Schema`\n\nCreate a new schema with fields omitted.\n\n```js\nlet person = object({\n  age: number().default(30).required(),\n  name: string().default('pat').required(),\n  color: string().default('red').required(),\n});\n\nlet nameAndAge = person.omit(['color']);\nnameAndAge.getDefault(); // => { age: 30, name: 'pat'}\n```\n\n#### `object.from(fromKey: string, toKey: string, alias: boolean = false): this`\n\nTransforms the specified key to a new key. If `alias` is `true` then the old key will be left.\n\n```js\nlet schema = object({\n  myProp: mixed(),\n  Other: mixed(),\n})\n  .from('prop', 'myProp')\n  .from('other', 'Other', true);\n\nschema.cast({ prop: 5, other: 6 }); // => { myProp: 5, other: 6, Other: 6 }\n```\n\n#### `object.exact(message?: string | function): Schema`\n\nValidates that the object does not contain extra or unknown properties\n\n#### `object.stripUnknown(): Schema`\n\nThe same as `object().validate(value, { stripUnknown: true})`, but as a transform method. When set\nany unknown properties will be removed.\n\n#### `object.noUnknown(onlyKnownKeys: boolean = true, message?: string | function): Schema`\n\nValidate that the object value only contains keys specified in `shape`, pass `false` as the first\nargument to disable the check. Restricting keys to known, also enables `stripUnknown` option, when not in strict mode.\n\n> Watch Out!: this method performs a transform and a validation, which may produce unexpected results.\n> For more explicit behavior use `object().stripUnknown` and `object().exact()`\n\n#### `object.camelCase(): Schema`\n\nTransforms all object keys to camelCase\n\n#### `object.constantCase(): Schema`\n\nTransforms all object keys to CONSTANT_CASE.\n"
  },
  {
    "path": "docs/extending.md",
    "content": "# Extending Schema\n\nFor simple cases where you want to reuse common schema configurations, creating\nand passing around instances works great and is automatically typed correctly\n\n```js\nimport * as yup from 'yup';\n\nconst requiredString = yup.string().required().default('');\n\nconst momentDate = (parseFormats = ['MMM dd, yyy']) =>\n  yup.date().transform((value, originalValue, schema) => {\n    if (schema.isType(value)) return value;\n\n    // the default coercion transform failed so let's try it with Moment instead\n    value = Moment(originalValue, parseFormats);\n    return value.isValid() ? value.toDate() : yup.date.INVALID_DATE;\n  });\n\nexport { momentDate, requiredString };\n```\n\nSchema are immutable so each can be configured further without changing the original.\n\n## Extending Schema with new methods\n\n`yup` provides a `addMethod()` utility for extending built-in schema:\n\n```js\nfunction parseDateFromFormats(formats, parseStrict) {\n  return this.transform((value, originalValue, schema) => {\n    if (schema.isType(value)) return value;\n\n    value = Moment(originalValue, formats, parseStrict);\n\n    return value.isValid() ? value.toDate() : yup.date.INVALID_DATE;\n  });\n}\n\nyup.addMethod(yup.date, 'format', parseDateFromFormats);\n```\n\nNote that `addMethod` isn't magic, it mutates the prototype of the passed in schema.\n\n> Note: if you are using TypeScript you also need to adjust the class or interface\n> see the [typescript](./typescript.md) docs for details.\n\n## Creating new Schema types\n\nIf you're using case calls for creating an entirely new type, inheriting from\nan existing schema class may be best: Generally you should not be inheriting from\nthe abstract `Schema` unless you know what you are doing. The other types are fair game though.\n\nYou should keep in mind some basic guidelines when extending schemas:\n\n- never mutate an existing schema, always `clone()` and then mutate the new one before returning it.\n  Built-in methods like `test` and `transform` take care of this for you, so you can safely use them (see below) without worrying\n\n- transforms should never mutate the `value` passed in, and should return an invalid object when one exists\n  (`NaN`, `InvalidDate`, etc) instead of `null` for bad values.\n\n- by the time validations run, the `value` is guaranteed to be the correct type, however it still may\n  be `null` or `undefined`\n\n```js\nimport { DateSchema } from 'yup';\n\nclass MomentDateSchema extends DateSchema {\n  static create() {\n    return MomentDateSchema();\n  }\n\n  constructor() {\n    super();\n    this._validFormats = [];\n\n    this.withMutation(() => {\n      this.transform(function (value, originalValue) {\n        if (this.isType(value))\n          // we have a valid value\n          return value;\n        return Moment(originalValue, this._validFormats, true);\n      });\n    });\n  }\n\n  _typeCheck(value) {\n    return (\n      super._typeCheck(value) || (moment.isMoment(value) && value.isValid())\n    );\n  }\n\n  format(formats) {\n    if (!formats) throw new Error('must enter a valid format');\n    let next = this.clone();\n    next._validFormats = {}.concat(formats);\n  }\n}\n\nlet schema = new MomentDateSchema();\n\nschema.format('YYYY-MM-DD').cast('It is 2012-05-25'); // => Fri May 25 2012 00:00:00 GMT-0400 (Eastern Daylight Time)\n```\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"yup\",\n  \"version\": \"1.7.1\",\n  \"description\": \"Dead simple Object schema validation\",\n  \"main\": \"lib/index.js\",\n  \"module\": \"lib/index.esm.js\",\n  \"runkitExampleFilename\": \"./runkit-example.js\",\n  \"scripts\": {\n    \"test\": \"yarn lint && yarn testonly\",\n    \"testonly\": \"vitest run\",\n    \"test-sync\": \"vitest run --project sync\",\n    \"tdd\": \"vitest --project async\",\n    \"lint\": \"eslint src test\",\n    \"precommit\": \"lint-staged\",\n    \"toc\": \"doctoc README.md --github\",\n    \"release\": \"rollout\",\n    \"build:dts\": \"yarn tsc --emitDeclarationOnly -p . --outDir dts\",\n    \"build\": \"rm -rf dts && yarn build:dts && yarn rollup -c rollup.config.js  && yarn toc\",\n    \"prepublishOnly\": \"yarn build\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/jquense/yup.git\"\n  },\n  \"author\": {\n    \"name\": \"@monasticpanic Jason Quense\"\n  },\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/jquense/yup/issues\"\n  },\n  \"homepage\": \"https://github.com/jquense/yup\",\n  \"release\": {\n    \"conventionalCommits\": true,\n    \"publishDir\": \"lib\"\n  },\n  \"prettier\": {\n    \"singleQuote\": true,\n    \"trailingComma\": \"all\"\n  },\n  \"lint-staged\": {\n    \"*.{js,json,css,md}\": [\n      \"prettier --write\",\n      \"git add\"\n    ]\n  },\n  \"devDependencies\": {\n    \"@4c/cli\": \"^4.0.4\",\n    \"@4c/rollout\": \"patch:@4c/rollout@npm%3A4.0.2#~/.yarn/patches/@4c-rollout-npm-4.0.2-ab2b6d0bab.patch\",\n    \"@4c/tsconfig\": \"^0.4.1\",\n    \"@babel/cli\": \"^7.28.3\",\n    \"@babel/core\": \"^7.28.4\",\n    \"@babel/preset-typescript\": \"^7.27.1\",\n    \"@rollup/plugin-babel\": \"^5.3.1\",\n    \"@rollup/plugin-node-resolve\": \"^13.3.0\",\n    \"@standard-schema/spec\": \"^1.0.0\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.62.0\",\n    \"@typescript-eslint/parser\": \"^5.62.0\",\n    \"babel-jest\": \"^27.5.1\",\n    \"babel-preset-env-modules\": \"^1.0.1\",\n    \"doctoc\": \"^2.2.1\",\n    \"dts-bundle-generator\": \"^6.13.0\",\n    \"eslint\": \"^8.57.1\",\n    \"eslint-config-jason\": \"^8.2.2\",\n    \"eslint-config-prettier\": \"^8.10.2\",\n    \"eslint-plugin-import\": \"^2.32.0\",\n    \"eslint-plugin-jest\": \"^25.7.0\",\n    \"eslint-plugin-react\": \"^7.37.5\",\n    \"eslint-plugin-react-hooks\": \"^4.6.2\",\n    \"eslint-plugin-ts-expect\": \"^2.1.0\",\n    \"eslint-plugin-typescript\": \"^0.14.0\",\n    \"hookem\": \"^2.0.1\",\n    \"lint-staged\": \"^13.3.0\",\n    \"prettier\": \"^2.8.8\",\n    \"rollup\": \"^2.79.2\",\n    \"rollup-plugin-babel\": \"^4.4.0\",\n    \"rollup-plugin-dts\": \"^4.2.3\",\n    \"rollup-plugin-filesize\": \"^9.1.2\",\n    \"rollup-plugin-node-resolve\": \"^5.2.0\",\n    \"synchronous-promise\": \"^2.0.17\",\n    \"typescript\": \"^4.9.5\",\n    \"vitest\": \"^3.2.4\"\n  },\n  \"dependencies\": {\n    \"property-expr\": \"^2.0.5\",\n    \"tiny-case\": \"^1.0.3\",\n    \"toposort\": \"^2.0.2\",\n    \"type-fest\": \"^2.19.0\"\n  },\n  \"packageManager\": \"yarn@4.10.0+sha512.8dd111dbb1658cf17089636e5bf490795958158755f36cb75c5a2db0bda6be4d84b95447753627f3330d1457cb6f7e8c1e466eaed959073c82be0242c2cd41e7\",\n  \"resolutions\": {\n    \"@4c/rollout@npm:^4.0.2\": \"patch:@4c/rollout@npm%3A4.0.2#~/.yarn/patches/@4c-rollout-npm-4.0.2-ab2b6d0bab.patch\"\n  }\n}\n"
  },
  {
    "path": "renovate.json",
    "content": "{\n  \"extends\": [\"github>4Catalyzer/renovate-config:library\", \":automergeMinor\"]\n}\n"
  },
  {
    "path": "rollup.config.js",
    "content": "import nodeResolve from '@rollup/plugin-node-resolve';\nimport babel from '@rollup/plugin-babel';\nimport dts from 'rollup-plugin-dts';\nimport filesize from 'rollup-plugin-filesize';\n\nconst base = {\n  input: './src/index.ts',\n  plugins: [\n    nodeResolve({ extensions: ['.js', '.ts'] }),\n    babel({\n      babelrc: true,\n      envName: 'esm',\n      extensions: ['.js', '.ts'],\n    }),\n  ],\n  external: ['tiny-case', 'toposort', 'fn-name', 'property-expr'],\n};\n\nmodule.exports = [\n  {\n    input: './dts/index.d.ts',\n    output: [{ file: 'lib/index.d.ts', format: 'es' }],\n    plugins: [dts()],\n  },\n  {\n    ...base,\n    output: [\n      {\n        file: 'lib/index.js',\n        format: 'cjs',\n      },\n      {\n        file: 'lib/index.esm.js',\n        format: 'es',\n      },\n    ],\n    plugins: [...base.plugins, filesize()],\n  },\n];\n"
  },
  {
    "path": "src/Condition.ts",
    "content": "import isSchema from './util/isSchema';\nimport Reference from './Reference';\nimport type { ISchema } from './types';\n\nexport type ConditionBuilder<T extends ISchema<any, any>> = (\n  values: any[],\n  schema: T,\n  options: ResolveOptions,\n) => ISchema<any>;\n\nexport type ConditionConfig<T extends ISchema<any>> = {\n  is: any | ((...values: any[]) => boolean);\n  then?: (schema: T) => ISchema<any>;\n  otherwise?: (schema: T) => ISchema<any>;\n};\n\nexport type ResolveOptions<TContext = any> = {\n  value?: any;\n  parent?: any;\n  context?: TContext;\n};\n\nclass Condition<TIn extends ISchema<any, any> = ISchema<any, any>> {\n  fn: ConditionBuilder<TIn>;\n\n  static fromOptions<TIn extends ISchema<any, any>>(\n    refs: Reference[],\n    config: ConditionConfig<TIn>,\n  ) {\n    if (!config.then && !config.otherwise)\n      throw new TypeError(\n        'either `then:` or `otherwise:` is required for `when()` conditions',\n      );\n\n    let { is, then, otherwise } = config;\n\n    let check =\n      typeof is === 'function'\n        ? is\n        : (...values: any[]) => values.every((value) => value === is);\n\n    return new Condition<TIn>(refs, (values, schema: any) => {\n      let branch = check(...values) ? then : otherwise;\n\n      return branch?.(schema) ?? schema;\n    });\n  }\n\n  constructor(\n    public refs: readonly Reference[],\n    builder: ConditionBuilder<TIn>,\n  ) {\n    this.refs = refs;\n    this.fn = builder;\n  }\n\n  resolve(base: TIn, options: ResolveOptions) {\n    let values = this.refs.map((ref) =>\n      // TODO: ? operator here?\n      ref.getValue(options?.value, options?.parent, options?.context),\n    );\n\n    let schema = this.fn(values, base, options);\n\n    if (\n      schema === undefined ||\n      // @ts-ignore this can be base\n      schema === base\n    ) {\n      return base;\n    }\n\n    if (!isSchema(schema))\n      throw new TypeError('conditions must return a schema object');\n\n    return schema.resolve(options);\n  }\n}\n\nexport default Condition;\n"
  },
  {
    "path": "src/Lazy.ts",
    "content": "import isSchema from './util/isSchema';\nimport type {\n  AnyObject,\n  ISchema,\n  ValidateOptions,\n  NestedTestConfig,\n  InferType,\n} from './types';\nimport type { ResolveOptions } from './Condition';\n\nimport type {\n  CastOptionalityOptions,\n  CastOptions,\n  SchemaFieldDescription,\n  SchemaLazyDescription,\n} from './schema';\nimport { Flags, Maybe, ResolveFlags } from './util/types';\nimport ValidationError from './ValidationError';\nimport Schema from './schema';\nimport {\n  issuesFromValidationError,\n  StandardResult,\n  StandardSchemaProps,\n} from './standardSchema';\n\nexport type LazyBuilder<\n  TSchema extends ISchema<TContext>,\n  TContext = AnyObject,\n> = (value: any, options: ResolveOptions) => TSchema;\n\nexport function create<\n  TSchema extends ISchema<any, TContext>,\n  TContext extends Maybe<AnyObject> = AnyObject,\n>(builder: (value: any, options: ResolveOptions<TContext>) => TSchema) {\n  return new Lazy<InferType<TSchema>, TContext>(builder);\n}\n\nfunction catchValidationError(fn: () => any) {\n  try {\n    return fn();\n  } catch (err) {\n    if (ValidationError.isError(err)) return Promise.reject(err);\n    throw err;\n  }\n}\n\nexport interface LazySpec {\n  meta: Record<string, unknown> | undefined;\n  optional: boolean;\n}\n\nclass Lazy<T, TContext = AnyObject, TFlags extends Flags = any>\n  implements ISchema<T, TContext, TFlags, undefined>\n{\n  type = 'lazy' as const;\n\n  __isYupSchema__ = true;\n\n  declare readonly __outputType: T;\n  declare readonly __context: TContext;\n  declare readonly __flags: TFlags;\n  declare readonly __default: undefined;\n\n  spec: LazySpec;\n\n  constructor(private builder: any) {\n    this.spec = { meta: undefined, optional: false };\n  }\n\n  clone(spec?: Partial<LazySpec>): Lazy<T, TContext, TFlags> {\n    const next = new Lazy<T, TContext, TFlags>(this.builder);\n    next.spec = { ...this.spec, ...spec };\n    return next;\n  }\n\n  private _resolve = (\n    value: any,\n    options: ResolveOptions<TContext> = {},\n  ): Schema<T, TContext, undefined, TFlags> => {\n    let schema = this.builder(value, options) as Schema<\n      T,\n      TContext,\n      undefined,\n      TFlags\n    >;\n\n    if (!isSchema(schema))\n      throw new TypeError('lazy() functions must return a valid schema');\n\n    if (this.spec.optional) schema = schema.optional();\n\n    return schema.resolve(options);\n  };\n\n  private optionality(optional: boolean) {\n    const next = this.clone({ optional });\n    return next;\n  }\n\n  optional(): Lazy<T | undefined, TContext, TFlags> {\n    return this.optionality(true);\n  }\n\n  resolve(options: ResolveOptions<TContext>) {\n    return this._resolve(options.value, options);\n  }\n\n  cast(value: any, options?: CastOptions<TContext>): T;\n  cast(\n    value: any,\n    options?: CastOptionalityOptions<TContext>,\n  ): T | null | undefined;\n  cast(\n    value: any,\n    options?: CastOptions<TContext> | CastOptionalityOptions<TContext>,\n  ): any {\n    return this._resolve(value, options).cast(value, options as any);\n  }\n\n  asNestedTest(config: NestedTestConfig) {\n    let { key, index, parent, options } = config;\n    let value = parent[index ?? key!];\n\n    return this._resolve(value, {\n      ...options,\n      value,\n      parent,\n    }).asNestedTest(config);\n  }\n\n  validate(value: any, options?: ValidateOptions<TContext>): Promise<T> {\n    return catchValidationError(() =>\n      this._resolve(value, options).validate(value, options),\n    );\n  }\n\n  validateSync(value: any, options?: ValidateOptions<TContext>): T {\n    return this._resolve(value, options).validateSync(value, options);\n  }\n\n  validateAt(path: string, value: any, options?: ValidateOptions<TContext>) {\n    return catchValidationError(() =>\n      this._resolve(value, options).validateAt(path, value, options),\n    );\n  }\n\n  validateSyncAt(\n    path: string,\n    value: any,\n    options?: ValidateOptions<TContext>,\n  ) {\n    return this._resolve(value, options).validateSyncAt(path, value, options);\n  }\n\n  isValid(value: any, options?: ValidateOptions<TContext>) {\n    try {\n      return this._resolve(value, options).isValid(value, options);\n    } catch (err) {\n      if (ValidationError.isError(err)) {\n        return Promise.resolve(false);\n      }\n      throw err;\n    }\n  }\n\n  isValidSync(value: any, options?: ValidateOptions<TContext>) {\n    return this._resolve(value, options).isValidSync(value, options);\n  }\n\n  describe(\n    options?: ResolveOptions<TContext>,\n  ): SchemaLazyDescription | SchemaFieldDescription {\n    return options\n      ? this.resolve(options).describe(options)\n      : { type: 'lazy', meta: this.spec.meta, label: undefined };\n  }\n\n  meta(): Record<string, unknown> | undefined;\n  meta(obj: Record<string, unknown>): Lazy<T, TContext, TFlags>;\n  meta(...args: [Record<string, unknown>?]) {\n    if (args.length === 0) return this.spec.meta;\n\n    let next = this.clone();\n    next.spec.meta = Object.assign(next.spec.meta || {}, args[0]);\n    return next;\n  }\n\n  get ['~standard']() {\n    const schema = this;\n\n    const standard: StandardSchemaProps<\n      T,\n      ResolveFlags<T, TFlags, undefined>\n    > = {\n      version: 1,\n      vendor: 'yup',\n      async validate(\n        value: unknown,\n      ): Promise<StandardResult<ResolveFlags<T, TFlags, undefined>>> {\n        try {\n          const result = await schema.validate(value, {\n            abortEarly: false,\n          });\n\n          return {\n            value: result as ResolveFlags<T, TFlags, undefined>,\n          };\n        } catch (err) {\n          if (ValidationError.isError(err)) {\n            return {\n              issues: issuesFromValidationError(err),\n            };\n          }\n\n          throw err;\n        }\n      },\n    };\n\n    return standard;\n  }\n}\n\nexport default Lazy;\n"
  },
  {
    "path": "src/Reference.ts",
    "content": "import { getter } from 'property-expr';\nimport type { SchemaRefDescription } from './schema';\n\nconst prefixes = {\n  context: '$',\n  value: '.',\n} as const;\n\nexport type ReferenceOptions<TValue = unknown> = {\n  map?: (value: unknown) => TValue;\n};\n\nexport function create<TValue = unknown>(\n  key: string,\n  options?: ReferenceOptions<TValue>,\n) {\n  return new Reference<TValue>(key, options);\n}\n\nexport default class Reference<TValue = unknown> {\n  readonly key: string;\n  readonly isContext: boolean;\n  readonly isValue: boolean;\n  readonly isSibling: boolean;\n  readonly path: any;\n\n  readonly getter: (data: unknown) => unknown;\n  readonly map?: (value: unknown) => TValue;\n\n  declare readonly __isYupRef: boolean;\n\n  constructor(key: string, options: ReferenceOptions<TValue> = {}) {\n    if (typeof key !== 'string')\n      throw new TypeError('ref must be a string, got: ' + key);\n\n    this.key = key.trim();\n\n    if (key === '') throw new TypeError('ref must be a non-empty string');\n\n    this.isContext = this.key[0] === prefixes.context;\n    this.isValue = this.key[0] === prefixes.value;\n    this.isSibling = !this.isContext && !this.isValue;\n\n    let prefix = this.isContext\n      ? prefixes.context\n      : this.isValue\n      ? prefixes.value\n      : '';\n\n    this.path = this.key.slice(prefix.length);\n    this.getter = this.path && getter(this.path, true);\n    this.map = options.map;\n  }\n\n  getValue(value: any, parent?: {}, context?: {}): TValue {\n    let result = this.isContext ? context : this.isValue ? value : parent;\n\n    if (this.getter) result = this.getter(result || {});\n\n    if (this.map) result = this.map(result);\n\n    return result;\n  }\n\n  /**\n   *\n   * @param {*} value\n   * @param {Object} options\n   * @param {Object=} options.context\n   * @param {Object=} options.parent\n   */\n  cast(value: any, options?: { parent?: {}; context?: {} }) {\n    return this.getValue(value, options?.parent, options?.context);\n  }\n\n  resolve() {\n    return this;\n  }\n\n  describe(): SchemaRefDescription {\n    return {\n      type: 'ref',\n      key: this.key,\n    };\n  }\n\n  toString() {\n    return `Ref(${this.key})`;\n  }\n\n  static isRef(value: any): value is Reference {\n    return value && value.__isYupRef;\n  }\n}\n\n// @ts-ignore\nReference.prototype.__isYupRef = true;\n"
  },
  {
    "path": "src/ValidationError.ts",
    "content": "import printValue from './util/printValue';\nimport toArray from './util/toArray';\n\nlet strReg = /\\$\\{\\s*(\\w+)\\s*\\}/g;\n\ntype Params = Record<string, unknown>;\n\nclass ValidationErrorNoStack implements ValidationError {\n  name: string;\n  message: string;\n\n  value: any;\n  path?: string;\n  type?: string;\n  params?: Params;\n\n  errors: string[];\n  inner: ValidationError[];\n\n  constructor(\n    errorOrErrors: string | ValidationError | readonly ValidationError[],\n    value?: any,\n    field?: string,\n    type?: string,\n  ) {\n    this.name = 'ValidationError';\n    this.value = value;\n    this.path = field;\n    this.type = type;\n\n    this.errors = [];\n    this.inner = [];\n\n    toArray(errorOrErrors).forEach((err) => {\n      if (ValidationError.isError(err)) {\n        this.errors.push(...err.errors);\n        const innerErrors = err.inner.length ? err.inner : [err];\n        this.inner.push(...innerErrors);\n      } else {\n        this.errors.push(err);\n      }\n    });\n\n    this.message =\n      this.errors.length > 1\n        ? `${this.errors.length} errors occurred`\n        : this.errors[0];\n  }\n\n  [Symbol.toStringTag] = 'Error';\n}\n\nexport default class ValidationError extends Error {\n  value: any;\n  path?: string;\n  type?: string;\n  params?: Params;\n\n  errors: string[] = [];\n  inner: ValidationError[] = [];\n\n  static formatError(\n    message: string | ((params: Params) => string) | unknown,\n    params: Params,\n  ) {\n    // Attempt to make the path more friendly for error message interpolation.\n    const path = params.label || params.path || 'this';\n    // Store the original path under `originalPath` so it isn't lost to custom\n    // message functions; e.g., ones provided in `setLocale()` calls.\n    params = { ...params, path, originalPath: params.path };\n\n    if (typeof message === 'string')\n      return message.replace(strReg, (_, key) => printValue(params[key]));\n    if (typeof message === 'function') return message(params);\n\n    return message;\n  }\n\n  static isError(err: any): err is ValidationError {\n    return err && err.name === 'ValidationError';\n  }\n\n  constructor(\n    errorOrErrors: string | ValidationError | readonly ValidationError[],\n    value?: any,\n    field?: string,\n    type?: string,\n    disableStack?: boolean,\n  ) {\n    const errorNoStack = new ValidationErrorNoStack(\n      errorOrErrors,\n      value,\n      field,\n      type,\n    );\n\n    if (disableStack) {\n      return errorNoStack;\n    }\n\n    super();\n\n    this.name = errorNoStack.name;\n    this.message = errorNoStack.message;\n    this.type = errorNoStack.type;\n    this.value = errorNoStack.value;\n    this.path = errorNoStack.path;\n    this.errors = errorNoStack.errors;\n    this.inner = errorNoStack.inner;\n\n    if (Error.captureStackTrace) {\n      Error.captureStackTrace(this, ValidationError);\n    }\n  }\n\n  static [Symbol.hasInstance](inst: any) {\n    return (\n      ValidationErrorNoStack[Symbol.hasInstance](inst) ||\n      super[Symbol.hasInstance](inst)\n    );\n  }\n\n  [Symbol.toStringTag] = 'Error';\n}\n"
  },
  {
    "path": "src/array.ts",
    "content": "import isSchema from './util/isSchema';\nimport printValue from './util/printValue';\nimport parseJson from './util/parseJson';\nimport { array as locale } from './locale';\nimport type {\n  AnyObject,\n  InternalOptions,\n  Message,\n  ISchema,\n  DefaultThunk,\n} from './types';\nimport type Reference from './Reference';\nimport type {\n  Defined,\n  Flags,\n  NotNull,\n  SetFlag,\n  Maybe,\n  Optionals,\n  ToggleDefault,\n  UnsetFlag,\n  Concat,\n} from './util/types';\nimport Schema, {\n  RunTest,\n  SchemaInnerTypeDescription,\n  SchemaSpec,\n} from './schema';\nimport type { ResolveOptions } from './Condition';\nimport type ValidationError from './ValidationError';\n\ntype InnerType<T> = T extends Array<infer I> ? I : never;\n\nexport type RejectorFn = (\n  value: any,\n  index: number,\n  array: readonly any[],\n) => boolean;\n\nexport function create<C extends Maybe<AnyObject> = AnyObject, T = any>(\n  type?: ISchema<T, C>,\n) {\n  return new ArraySchema<T[] | undefined, C>(type as any);\n}\n\ninterface ArraySchemaSpec<TIn, TContext> extends SchemaSpec<any> {\n  types?: ISchema<InnerType<TIn>, TContext>;\n}\n\nexport default class ArraySchema<\n  TIn extends any[] | null | undefined,\n  TContext,\n  TDefault = undefined,\n  TFlags extends Flags = '',\n> extends Schema<TIn, TContext, TDefault, TFlags> {\n  declare spec: ArraySchemaSpec<TIn, TContext>;\n  readonly innerType?: ISchema<InnerType<TIn>, TContext>;\n\n  constructor(type?: ISchema<InnerType<TIn>, TContext>) {\n    super({\n      type: 'array',\n      spec: { types: type } as ArraySchemaSpec<TIn, TContext>,\n      check(v: any): v is NonNullable<TIn> {\n        return Array.isArray(v);\n      },\n    });\n\n    // `undefined` specifically means uninitialized, as opposed to \"no subtype\"\n    this.innerType = type;\n  }\n\n  protected _cast(_value: any, _opts: InternalOptions<TContext>) {\n    const value = super._cast(_value, _opts);\n\n    // should ignore nulls here\n    if (!this._typeCheck(value) || !this.innerType) {\n      return value;\n    }\n\n    let isChanged = false;\n    const castArray = value.map((v, idx) => {\n      const castElement = this.innerType!.cast(v, {\n        ..._opts,\n        path: `${_opts.path || ''}[${idx}]`,\n        parent: value,\n        originalValue: v,\n        value: v,\n        index: idx,\n\n      });\n      \n      if (castElement !== v) {\n        isChanged = true;\n      }\n\n      return castElement;\n    });\n\n    return isChanged ? castArray : value;\n  }\n\n  protected _validate(\n    _value: any,\n    options: InternalOptions<TContext> = {},\n\n    panic: (err: Error, value: unknown) => void,\n    next: (err: ValidationError[], value: unknown) => void,\n  ) {\n    // let sync = options.sync;\n    // let path = options.path;\n    let innerType = this.innerType;\n    // let endEarly = options.abortEarly ?? this.spec.abortEarly;\n    let recursive = options.recursive ?? this.spec.recursive;\n\n    let originalValue =\n      options.originalValue != null ? options.originalValue : _value;\n\n    super._validate(_value, options, panic, (arrayErrors, value) => {\n      if (!recursive || !innerType || !this._typeCheck(value)) {\n        next(arrayErrors, value);\n        return;\n      }\n\n      originalValue = originalValue || value;\n\n      // #950 Ensure that sparse array empty slots are validated\n      let tests: RunTest[] = new Array(value.length);\n      for (let index = 0; index < value.length; index++) {\n        tests[index] = innerType!.asNestedTest({\n          options,\n          index,\n          parent: value,\n          parentPath: options.path,\n          originalParent: options.originalValue ?? _value,\n        });\n      }\n\n      this.runTests(\n        {\n          value,\n          tests,\n          originalValue: options.originalValue ?? _value,\n          options,\n        },\n        panic,\n        (innerTypeErrors) => next(innerTypeErrors.concat(arrayErrors), value),\n      );\n    });\n  }\n\n  clone(spec?: SchemaSpec<any>) {\n    const next = super.clone(spec);\n    // @ts-expect-error readonly\n    next.innerType = this.innerType;\n    return next;\n  }\n\n  /** Parse an input JSON string to an object */\n  json() {\n    return this.transform(parseJson);\n  }\n\n  concat<IIn extends Maybe<any[]>, IC, ID, IF extends Flags>(\n    schema: ArraySchema<IIn, IC, ID, IF>,\n  ): ArraySchema<\n    Concat<TIn, IIn>,\n    TContext & IC,\n    Extract<IF, 'd'> extends never ? TDefault : ID,\n    TFlags | IF\n  >;\n  concat(schema: this): this;\n  concat(schema: any): any {\n    let next = super.concat(schema) as this;\n\n    // @ts-expect-error readonly\n    next.innerType = this.innerType;\n\n    if (schema.innerType)\n      // @ts-expect-error readonly\n      next.innerType = next.innerType\n        ? // @ts-expect-error Lazy doesn't have concat and will break\n          next.innerType.concat(schema.innerType)\n        : schema.innerType;\n\n    return next;\n  }\n\n  of<U>(\n    schema: ISchema<U, TContext>,\n  ): ArraySchema<U[] | Optionals<TIn>, TContext, TFlags> {\n    // FIXME: this should return a new instance of array without the default to be\n    let next = this.clone();\n\n    if (!isSchema(schema))\n      throw new TypeError(\n        '`array.of()` sub-schema must be a valid yup schema not: ' +\n          printValue(schema),\n      );\n\n    // @ts-expect-error readonly\n    next.innerType = schema;\n\n    next.spec = {\n      ...next.spec,\n      types: schema as ISchema<InnerType<TIn>, TContext>,\n    };\n\n    return next as any;\n  }\n\n  length(\n    length: number | Reference<number>,\n    message: Message<{ length: number }> = locale.length,\n  ) {\n    return this.test({\n      message,\n      name: 'length',\n      exclusive: true,\n      params: { length },\n      skipAbsent: true,\n      test(value) {\n        return value!.length === this.resolve(length);\n      },\n    });\n  }\n\n  min(min: number | Reference<number>, message?: Message<{ min: number }>) {\n    message = message || locale.min;\n\n    return this.test({\n      message,\n      name: 'min',\n      exclusive: true,\n      params: { min },\n      skipAbsent: true,\n      // FIXME(ts): Array<typeof T>\n      test(value) {\n        return value!.length >= this.resolve(min);\n      },\n    });\n  }\n\n  max(max: number | Reference<number>, message?: Message<{ max: number }>) {\n    message = message || locale.max;\n    return this.test({\n      message,\n      name: 'max',\n      exclusive: true,\n      params: { max },\n      skipAbsent: true,\n      test(value) {\n        return value!.length <= this.resolve(max);\n      },\n    });\n  }\n\n  ensure() {\n    return this.default<TIn>(() => [] as any).transform(\n      (val: TIn, original: any) => {\n        // We don't want to return `null` for nullable schema\n        if (this._typeCheck(val)) return val;\n        return original == null ? [] : [].concat(original);\n      },\n    );\n  }\n\n  compact(rejector?: RejectorFn) {\n    let reject: RejectorFn = !rejector\n      ? (v) => !!v\n      : (v, i, a) => !rejector(v, i, a);\n\n    return this.transform((values: readonly any[]) =>\n      values != null ? values.filter(reject) : values,\n    );\n  }\n\n  describe(options?: ResolveOptions<TContext>) {\n    const next = (options ? this.resolve(options) : this).clone();\n    const base = super.describe(options) as SchemaInnerTypeDescription;\n    if (next.innerType) {\n      let innerOptions = options;\n      if (innerOptions?.value) {\n        innerOptions = {\n          ...innerOptions,\n          parent: innerOptions.value,\n          value: innerOptions.value[0],\n        };\n      }\n      base.innerType = next.innerType.describe(innerOptions);\n    }\n    return base;\n  }\n}\n\ncreate.prototype = ArraySchema.prototype;\n\nexport default interface ArraySchema<\n  TIn extends any[] | null | undefined,\n  TContext,\n  TDefault = undefined,\n  TFlags extends Flags = '',\n> extends Schema<TIn, TContext, TDefault, TFlags> {\n  default<D extends Maybe<TIn>>(\n    def: DefaultThunk<D, TContext>,\n  ): ArraySchema<TIn, TContext, D, ToggleDefault<TFlags, D>>;\n\n  defined(msg?: Message): ArraySchema<Defined<TIn>, TContext, TDefault, TFlags>;\n  optional(): ArraySchema<TIn | undefined, TContext, TDefault, TFlags>;\n\n  required(\n    msg?: Message,\n  ): ArraySchema<NonNullable<TIn>, TContext, TDefault, TFlags>;\n  notRequired(): ArraySchema<Maybe<TIn>, TContext, TDefault, TFlags>;\n\n  nullable(msg?: Message): ArraySchema<TIn | null, TContext, TDefault, TFlags>;\n  nonNullable(\n    msg?: Message,\n  ): ArraySchema<NotNull<TIn>, TContext, TDefault, TFlags>;\n\n  strip(\n    enabled: false,\n  ): ArraySchema<TIn, TContext, TDefault, UnsetFlag<TFlags, 's'>>;\n  strip(\n    enabled?: true,\n  ): ArraySchema<TIn, TContext, TDefault, SetFlag<TFlags, 's'>>;\n}\n"
  },
  {
    "path": "src/boolean.ts",
    "content": "import Schema from './schema';\nimport type { AnyObject, DefaultThunk, Message } from './types';\nimport type {\n  Defined,\n  Flags,\n  NotNull,\n  SetFlag,\n  ToggleDefault,\n  UnsetFlag,\n  Maybe,\n  Optionals,\n} from './util/types';\nimport { boolean as locale } from './locale';\nimport isAbsent from './util/isAbsent';\n\nexport function create(): BooleanSchema;\nexport function create<\n  T extends boolean,\n  TContext extends Maybe<AnyObject> = AnyObject,\n>(): BooleanSchema<T | undefined, TContext>;\nexport function create() {\n  return new BooleanSchema();\n}\n\nexport default class BooleanSchema<\n  TType extends Maybe<boolean> = boolean | undefined,\n  TContext = AnyObject,\n  TDefault = undefined,\n  TFlags extends Flags = '',\n> extends Schema<TType, TContext, TDefault, TFlags> {\n  constructor() {\n    super({\n      type: 'boolean',\n      check(v: any): v is NonNullable<TType> {\n        if (v instanceof Boolean) v = v.valueOf();\n\n        return typeof v === 'boolean';\n      },\n    });\n\n    this.withMutation(() => {\n      this.transform((value, _raw) => {\n        if (this.spec.coerce && !this.isType(value)) {\n          if (/^(true|1)$/i.test(String(value))) return true;\n          if (/^(false|0)$/i.test(String(value))) return false;\n        }\n        return value;\n      });\n    });\n  }\n\n  isTrue(\n    message = locale.isValue,\n  ): BooleanSchema<true | Optionals<TType>, TContext, TFlags> {\n    return this.test({\n      message,\n      name: 'is-value',\n      exclusive: true,\n      params: { value: 'true' },\n      test(value) {\n        return isAbsent(value) || value === true;\n      },\n    }) as any;\n  }\n\n  isFalse(\n    message = locale.isValue,\n  ): BooleanSchema<false | Optionals<TType>, TContext, TFlags> {\n    return this.test({\n      message,\n      name: 'is-value',\n      exclusive: true,\n      params: { value: 'false' },\n      test(value) {\n        return isAbsent(value) || value === false;\n      },\n    }) as any;\n  }\n\n  override default<D extends Maybe<TType>>(\n    def: DefaultThunk<D, TContext>,\n  ): BooleanSchema<TType, TContext, D, ToggleDefault<TFlags, D>> {\n    return super.default(def);\n  }\n\n  defined(\n    msg?: Message,\n  ): BooleanSchema<Defined<TType>, TContext, TDefault, TFlags> {\n    return super.defined(msg);\n  }\n  optional(): BooleanSchema<TType | undefined, TContext, TDefault, TFlags> {\n    return super.optional();\n  }\n  required(\n    msg?: Message,\n  ): BooleanSchema<NonNullable<TType>, TContext, TDefault, TFlags> {\n    return super.required(msg);\n  }\n  notRequired(): BooleanSchema<Maybe<TType>, TContext, TDefault, TFlags> {\n    return super.notRequired();\n  }\n  nullable(): BooleanSchema<TType | null, TContext, TDefault, TFlags> {\n    return super.nullable();\n  }\n  nonNullable(\n    msg?: Message,\n  ): BooleanSchema<NotNull<TType>, TContext, TDefault, TFlags> {\n    return super.nonNullable(msg);\n  }\n\n  strip(\n    enabled: false,\n  ): BooleanSchema<TType, TContext, TDefault, UnsetFlag<TFlags, 's'>>;\n  strip(\n    enabled?: true,\n  ): BooleanSchema<TType, TContext, TDefault, SetFlag<TFlags, 's'>>;\n  strip(v: any) {\n    return super.strip(v);\n  }\n}\n\ncreate.prototype = BooleanSchema.prototype;\n"
  },
  {
    "path": "src/date.ts",
    "content": "import { parseIsoDate } from './util/parseIsoDate';\nimport { date as locale } from './locale';\nimport Ref from './Reference';\nimport type { AnyObject, DefaultThunk, Message } from './types';\nimport type {\n  Defined,\n  Flags,\n  NotNull,\n  SetFlag,\n  Maybe,\n  ToggleDefault,\n  UnsetFlag,\n} from './util/types';\nimport Schema from './schema';\n\nlet invalidDate = new Date('');\n\nlet isDate = (obj: any): obj is Date =>\n  Object.prototype.toString.call(obj) === '[object Date]';\n\nexport function create(): DateSchema;\nexport function create<\n  T extends Date,\n  TContext extends Maybe<AnyObject> = AnyObject,\n>(): DateSchema<T | undefined, TContext>;\nexport function create() {\n  return new DateSchema();\n}\n\nexport default class DateSchema<\n  TType extends Maybe<Date> = Date | undefined,\n  TContext = AnyObject,\n  TDefault = undefined,\n  TFlags extends Flags = '',\n> extends Schema<TType, TContext, TDefault, TFlags> {\n  static INVALID_DATE = invalidDate;\n\n  constructor() {\n    super({\n      type: 'date',\n      check(v: any): v is NonNullable<TType> {\n        return isDate(v) && !isNaN(v.getTime());\n      },\n    });\n\n    this.withMutation(() => {\n      this.transform((value, _raw) => {\n        // null -> InvalidDate isn't useful; treat all nulls as null and let it fail on\n        // nullability check vs TypeErrors\n        if (!this.spec.coerce || this.isType(value) || value === null)\n          return value;\n\n        value = parseIsoDate(value);\n\n        // 0 is a valid timestamp equivalent to 1970-01-01T00:00:00Z(unix epoch) or before.\n        return !isNaN(value) ? new Date(value) : DateSchema.INVALID_DATE;\n      });\n    });\n  }\n\n  private prepareParam(\n    ref: unknown | Ref<Date>,\n    name: string,\n  ): Date | Ref<Date> {\n    let param: Date | Ref<Date>;\n\n    if (!Ref.isRef(ref)) {\n      let cast = this.cast(ref);\n      if (!this._typeCheck(cast))\n        throw new TypeError(\n          `\\`${name}\\` must be a Date or a value that can be \\`cast()\\` to a Date`,\n        );\n      param = cast;\n    } else {\n      param = ref as Ref<Date>;\n    }\n    return param;\n  }\n\n  min(min: unknown | Ref<Date>, message = locale.min) {\n    let limit = this.prepareParam(min, 'min');\n\n    return this.test({\n      message,\n      name: 'min',\n      exclusive: true,\n      params: { min },\n      skipAbsent: true,\n      test(value) {\n        return value! >= this.resolve(limit);\n      },\n    });\n  }\n\n  max(max: unknown | Ref, message = locale.max) {\n    let limit = this.prepareParam(max, 'max');\n\n    return this.test({\n      message,\n      name: 'max',\n      exclusive: true,\n      params: { max },\n      skipAbsent: true,\n      test(value) {\n        return value! <= this.resolve(limit);\n      },\n    });\n  }\n}\n\ncreate.prototype = DateSchema.prototype;\ncreate.INVALID_DATE = invalidDate;\n\nexport default interface DateSchema<\n  TType extends Maybe<Date>,\n  TContext = AnyObject,\n  TDefault = undefined,\n  TFlags extends Flags = '',\n> extends Schema<TType, TContext, TDefault, TFlags> {\n  default<D extends Maybe<TType>>(\n    def: DefaultThunk<D, TContext>,\n  ): DateSchema<TType, TContext, D, ToggleDefault<TFlags, D>>;\n\n  concat<TOther extends DateSchema<any, any>>(schema: TOther): TOther;\n\n  defined(\n    msg?: Message,\n  ): DateSchema<Defined<TType>, TContext, TDefault, TFlags>;\n  optional(): DateSchema<TType | undefined, TContext, TDefault, TFlags>;\n\n  required(\n    msg?: Message,\n  ): DateSchema<NonNullable<TType>, TContext, TDefault, TFlags>;\n  notRequired(): DateSchema<Maybe<TType>, TContext, TDefault, TFlags>;\n\n  nullable(msg?: Message): DateSchema<TType | null, TContext, TDefault, TFlags>;\n  nonNullable(\n    msg?: Message,\n  ): DateSchema<NotNull<TType>, TContext, TDefault, TFlags>;\n\n  strip(\n    enabled: false,\n  ): DateSchema<TType, TContext, TDefault, UnsetFlag<TFlags, 's'>>;\n  strip(\n    enabled?: true,\n  ): DateSchema<TType, TContext, TDefault, SetFlag<TFlags, 's'>>;\n}\n"
  },
  {
    "path": "src/globals.d.ts",
    "content": "\n"
  },
  {
    "path": "src/index.ts",
    "content": "import MixedSchema, {\n  create as mixedCreate,\n  MixedOptions,\n  TypeGuard,\n} from './mixed';\nimport BooleanSchema, { create as boolCreate } from './boolean';\nimport StringSchema, { create as stringCreate } from './string';\nimport NumberSchema, { create as numberCreate } from './number';\nimport DateSchema, { create as dateCreate } from './date';\nimport ObjectSchema, { AnyObject, create as objectCreate } from './object';\nimport ArraySchema, { create as arrayCreate } from './array';\nimport TupleSchema, { create as tupleCreate } from './tuple';\nimport Reference, { create as refCreate } from './Reference';\nimport Lazy, { create as lazyCreate } from './Lazy';\nimport ValidationError from './ValidationError';\nimport reach, { getIn } from './util/reach';\nimport isSchema from './util/isSchema';\nimport printValue from './util/printValue';\nimport setLocale, { LocaleObject } from './setLocale';\nimport defaultLocale from './locale';\nimport Schema, {\n  AnySchema,\n  CastOptions as BaseCastOptions,\n  SchemaSpec,\n  SchemaRefDescription,\n  SchemaInnerTypeDescription,\n  SchemaObjectDescription,\n  SchemaLazyDescription,\n  SchemaFieldDescription,\n  SchemaDescription,\n  SchemaMetadata,\n  CustomSchemaMetadata,\n} from './schema';\nimport type {\n  AnyMessageParams,\n  InferType,\n  ISchema,\n  Message,\n  MessageParams,\n  ValidateOptions,\n  DefaultThunk,\n} from './types';\n\nfunction addMethod<T extends ISchema<any>>(\n  schemaType: (...arg: any[]) => T,\n  name: string,\n  fn: (this: T, ...args: any[]) => T,\n): void;\nfunction addMethod<T extends abstract new (...args: any) => ISchema<any>>(\n  schemaType: T,\n  name: string,\n  fn: (this: InstanceType<T>, ...args: any[]) => InstanceType<T>,\n): void;\nfunction addMethod(schemaType: any, name: string, fn: any) {\n  if (!schemaType || !isSchema(schemaType.prototype))\n    throw new TypeError('You must provide a yup schema constructor function');\n\n  if (typeof name !== 'string')\n    throw new TypeError('A Method name must be provided');\n  if (typeof fn !== 'function')\n    throw new TypeError('Method function must be provided');\n\n  schemaType.prototype[name] = fn;\n}\n\nexport type AnyObjectSchema = ObjectSchema<any, any, any, any>;\n\nexport type CastOptions = Omit<BaseCastOptions, 'path' | 'resolved'>;\n\nexport type {\n  AnyMessageParams,\n  AnyObject,\n  InferType,\n  InferType as Asserts,\n  ISchema,\n  Message,\n  MessageParams,\n  AnySchema,\n  MixedOptions,\n  TypeGuard as MixedTypeGuard,\n  SchemaSpec,\n  SchemaRefDescription,\n  SchemaInnerTypeDescription,\n  SchemaObjectDescription,\n  SchemaLazyDescription,\n  SchemaFieldDescription,\n  SchemaDescription,\n  SchemaMetadata,\n  CustomSchemaMetadata,\n  LocaleObject,\n  ValidateOptions,\n  DefaultThunk,\n  Lazy,\n  Reference,\n};\n\nexport {\n  mixedCreate as mixed,\n  boolCreate as bool,\n  boolCreate as boolean,\n  stringCreate as string,\n  numberCreate as number,\n  dateCreate as date,\n  objectCreate as object,\n  arrayCreate as array,\n  refCreate as ref,\n  lazyCreate as lazy,\n  tupleCreate as tuple,\n  reach,\n  getIn,\n  isSchema,\n  printValue,\n  addMethod,\n  setLocale,\n  defaultLocale,\n  ValidationError,\n};\n\nexport {\n  Schema,\n  MixedSchema,\n  BooleanSchema,\n  StringSchema,\n  NumberSchema,\n  DateSchema,\n  ObjectSchema,\n  ArraySchema,\n  TupleSchema,\n  Lazy as LazySchema,\n};\n\nexport type {\n  CreateErrorOptions,\n  TestContext,\n  TestFunction,\n  TestOptions,\n  TestConfig,\n} from './util/createValidation';\n\nexport type {\n  ObjectShape,\n  TypeFromShape,\n  DefaultFromShape,\n  MakePartial,\n} from './util/objectTypes';\n\nexport type {\n  Maybe,\n  Flags,\n  Optionals,\n  ToggleDefault,\n  Defined,\n  NotNull,\n  UnsetFlag,\n  SetFlag,\n} from './util/types';\n"
  },
  {
    "path": "src/locale.ts",
    "content": "import printValue from './util/printValue';\nimport { Message } from './types';\nimport ValidationError from './ValidationError';\n\nexport interface MixedLocale {\n  default?: Message;\n  required?: Message;\n  oneOf?: Message<{ values: any }>;\n  notOneOf?: Message<{ values: any }>;\n  notNull?: Message;\n  notType?: Message;\n  defined?: Message;\n}\n\nexport interface StringLocale {\n  length?: Message<{ length: number }>;\n  min?: Message<{ min: number }>;\n  max?: Message<{ max: number }>;\n  matches?: Message<{ regex: RegExp }>;\n  email?: Message<{ regex: RegExp }>;\n  url?: Message<{ regex: RegExp }>;\n  uuid?: Message<{ regex: RegExp }>;\n  datetime?: Message;\n  datetime_offset?: Message;\n  datetime_precision?: Message<{ precision: number }>;\n  trim?: Message;\n  lowercase?: Message;\n  uppercase?: Message;\n}\n\nexport interface NumberLocale {\n  min?: Message<{ min: number }>;\n  max?: Message<{ max: number }>;\n  lessThan?: Message<{ less: number }>;\n  moreThan?: Message<{ more: number }>;\n  positive?: Message<{ more: number }>;\n  negative?: Message<{ less: number }>;\n  integer?: Message;\n}\n\nexport interface DateLocale {\n  min?: Message<{ min: Date | string }>;\n  max?: Message<{ max: Date | string }>;\n}\n\nexport interface ObjectLocale {\n  noUnknown?: Message<{ unknown: string[] }>;\n  exact?: Message<{ properties: string[] }>;\n}\n\nexport interface ArrayLocale {\n  length?: Message<{ length: number }>;\n  min?: Message<{ min: number }>;\n  max?: Message<{ max: number }>;\n}\n\nexport interface TupleLocale {\n  notType?: Message;\n}\n\nexport interface BooleanLocale {\n  isValue?: Message;\n}\n\nexport interface LocaleObject {\n  mixed?: MixedLocale;\n  string?: StringLocale;\n  number?: NumberLocale;\n  date?: DateLocale;\n  boolean?: BooleanLocale;\n  object?: ObjectLocale;\n  array?: ArrayLocale;\n  tuple?: TupleLocale;\n}\n\nexport let mixed: Required<MixedLocale> = {\n  default: '${path} is invalid',\n  required: '${path} is a required field',\n  defined: '${path} must be defined',\n  notNull: '${path} cannot be null',\n  oneOf: '${path} must be one of the following values: ${values}',\n  notOneOf: '${path} must not be one of the following values: ${values}',\n  notType: ({ path, type, value, originalValue }) => {\n    const castMsg =\n      originalValue != null && originalValue !== value\n        ? ` (cast from the value \\`${printValue(originalValue, true)}\\`).`\n        : '.';\n\n    return type !== 'mixed'\n      ? `${path} must be a \\`${type}\\` type, ` +\n          `but the final value was: \\`${printValue(value, true)}\\`` +\n          castMsg\n      : `${path} must match the configured type. ` +\n          `The validated value was: \\`${printValue(value, true)}\\`` +\n          castMsg;\n  },\n};\n\nexport let string: Required<StringLocale> = {\n  length: '${path} must be exactly ${length} characters',\n  min: '${path} must be at least ${min} characters',\n  max: '${path} must be at most ${max} characters',\n  matches: '${path} must match the following: \"${regex}\"',\n  email: '${path} must be a valid email',\n  url: '${path} must be a valid URL',\n  uuid: '${path} must be a valid UUID',\n  datetime: '${path} must be a valid ISO date-time',\n  datetime_precision:\n    '${path} must be a valid ISO date-time with a sub-second precision of exactly ${precision} digits',\n  datetime_offset:\n    '${path} must be a valid ISO date-time with UTC \"Z\" timezone',\n  trim: '${path} must be a trimmed string',\n  lowercase: '${path} must be a lowercase string',\n  uppercase: '${path} must be a upper case string',\n};\n\nexport let number: Required<NumberLocale> = {\n  min: '${path} must be greater than or equal to ${min}',\n  max: '${path} must be less than or equal to ${max}',\n  lessThan: '${path} must be less than ${less}',\n  moreThan: '${path} must be greater than ${more}',\n  positive: '${path} must be a positive number',\n  negative: '${path} must be a negative number',\n  integer: '${path} must be an integer',\n};\n\nexport let date: Required<DateLocale> = {\n  min: '${path} field must be later than ${min}',\n  max: '${path} field must be at earlier than ${max}',\n};\n\nexport let boolean: BooleanLocale = {\n  isValue: '${path} field must be ${value}',\n};\n\nexport let object: Required<ObjectLocale> = {\n  noUnknown: '${path} field has unspecified keys: ${unknown}',\n  exact: '${path} object contains unknown properties: ${properties}',\n};\n\nexport let array: Required<ArrayLocale> = {\n  min: '${path} field must have at least ${min} items',\n  max: '${path} field must have less than or equal to ${max} items',\n  length: '${path} must have ${length} items',\n};\n\nexport let tuple: Required<TupleLocale> = {\n  notType: (params) => {\n    const { path, value, spec } = params;\n    const typeLen = spec.types.length;\n    if (Array.isArray(value)) {\n      if (value.length < typeLen)\n        return `${path} tuple value has too few items, expected a length of ${typeLen} but got ${\n          value.length\n        } for value: \\`${printValue(value, true)}\\``;\n      if (value.length > typeLen)\n        return `${path} tuple value has too many items, expected a length of ${typeLen} but got ${\n          value.length\n        } for value: \\`${printValue(value, true)}\\``;\n    }\n\n    return ValidationError.formatError(mixed.notType, params);\n  },\n};\n\nexport default Object.assign(Object.create(null), {\n  mixed,\n  string,\n  number,\n  date,\n  object,\n  array,\n  boolean,\n  tuple,\n}) as LocaleObject;\n"
  },
  {
    "path": "src/mixed.ts",
    "content": "import { AnyObject, DefaultThunk, Message } from './types';\nimport type {\n  Concat,\n  Defined,\n  Flags,\n  SetFlag,\n  Maybe,\n  ToggleDefault,\n  UnsetFlag,\n} from './util/types';\nimport Schema from './schema';\n\nconst returnsTrue: any = () => true;\n\ntype AnyPresentValue = {};\n\nexport type TypeGuard<TType> = (value: any) => value is NonNullable<TType>;\nexport interface MixedOptions<TType> {\n  type?: string;\n  check?: TypeGuard<TType>;\n}\n\nexport function create<TType extends AnyPresentValue>(\n  spec?: MixedOptions<TType> | TypeGuard<TType>,\n) {\n  return new MixedSchema<TType | undefined>(spec);\n}\n\nexport default class MixedSchema<\n  TType extends Maybe<AnyPresentValue> = AnyPresentValue | undefined,\n  TContext = AnyObject,\n  TDefault = undefined,\n  TFlags extends Flags = '',\n> extends Schema<TType, TContext, TDefault, TFlags> {\n  constructor(spec?: MixedOptions<TType> | TypeGuard<TType>) {\n    super(\n      typeof spec === 'function'\n        ? { type: 'mixed', check: spec }\n        : { type: 'mixed', check: returnsTrue as TypeGuard<TType>, ...spec },\n    );\n  }\n}\n\nexport default interface MixedSchema<\n  TType extends Maybe<AnyPresentValue> = AnyPresentValue | undefined,\n  TContext = AnyObject,\n  TDefault = undefined,\n  TFlags extends Flags = '',\n> extends Schema<TType, TContext, TDefault, TFlags> {\n  default<D extends Maybe<TType>>(\n    def: DefaultThunk<D, TContext>,\n  ): MixedSchema<TType, TContext, D, ToggleDefault<TFlags, D>>;\n\n  concat<IT, IC, ID, IF extends Flags>(\n    schema: MixedSchema<IT, IC, ID, IF>,\n  ): MixedSchema<Concat<TType, IT>, TContext & IC, ID, TFlags | IF>;\n  concat<IT, IC, ID, IF extends Flags>(\n    schema: Schema<IT, IC, ID, IF>,\n  ): MixedSchema<Concat<TType, IT>, TContext & IC, ID, TFlags | IF>;\n  concat(schema: this): this;\n\n  defined(\n    msg?: Message,\n  ): MixedSchema<Defined<TType>, TContext, TDefault, TFlags>;\n  optional(): MixedSchema<TType | undefined, TContext, TDefault, TFlags>;\n\n  required(\n    msg?: Message,\n  ): MixedSchema<NonNullable<TType>, TContext, TDefault, TFlags>;\n  notRequired(): MixedSchema<Maybe<TType>, TContext, TDefault, TFlags>;\n\n  nullable(\n    msg?: Message,\n  ): MixedSchema<TType | null, TContext, TDefault, TFlags>;\n\n  nonNullable(\n    msg?: Message,\n  ): MixedSchema<Exclude<TType, null>, TContext, TDefault, TFlags>;\n\n  strip(\n    enabled: false,\n  ): MixedSchema<TType, TContext, TDefault, UnsetFlag<TFlags, 's'>>;\n  strip(\n    enabled?: true,\n  ): MixedSchema<TType, TContext, TDefault, SetFlag<TFlags, 's'>>;\n}\n\ncreate.prototype = MixedSchema.prototype;\n"
  },
  {
    "path": "src/number.ts",
    "content": "import { number as locale } from './locale';\nimport isAbsent from './util/isAbsent';\nimport type { AnyObject, DefaultThunk, Message } from './types';\nimport type Reference from './Reference';\nimport type {\n  Concat,\n  Defined,\n  Flags,\n  NotNull,\n  SetFlag,\n  Maybe,\n  ToggleDefault,\n  UnsetFlag,\n} from './util/types';\nimport Schema from './schema';\n\nlet isNaN = (value: Maybe<number>) => value != +value!;\n\nexport function create(): NumberSchema;\nexport function create<\n  T extends number,\n  TContext extends Maybe<AnyObject> = AnyObject,\n>(): NumberSchema<T | undefined, TContext>;\nexport function create() {\n  return new NumberSchema();\n}\n\nexport default class NumberSchema<\n  TType extends Maybe<number> = number | undefined,\n  TContext = AnyObject,\n  TDefault = undefined,\n  TFlags extends Flags = '',\n> extends Schema<TType, TContext, TDefault, TFlags> {\n  constructor() {\n    super({\n      type: 'number',\n      check(value: any): value is NonNullable<TType> {\n        if (value instanceof Number) value = value.valueOf();\n\n        return typeof value === 'number' && !isNaN(value);\n      },\n    });\n\n    this.withMutation(() => {\n      this.transform((value, _raw) => {\n        if (!this.spec.coerce) return value;\n\n        let parsed = value;\n        if (typeof parsed === 'string') {\n          parsed = parsed.replace(/\\s/g, '');\n          if (parsed === '') return NaN;\n          // don't use parseFloat to avoid positives on alpha-numeric strings\n          parsed = +parsed;\n        }\n\n        // null -> NaN isn't useful; treat all nulls as null and let it fail on\n        // nullability check vs TypeErrors\n        if (this.isType(parsed) || parsed === null) return parsed;\n\n        return parseFloat(parsed);\n      });\n    });\n  }\n\n  min(min: number | Reference<number>, message = locale.min) {\n    return this.test({\n      message,\n      name: 'min',\n      exclusive: true,\n      params: { min },\n      skipAbsent: true,\n      test(value: Maybe<number>) {\n        return value! >= this.resolve(min);\n      },\n    });\n  }\n\n  max(max: number | Reference<number>, message = locale.max) {\n    return this.test({\n      message,\n      name: 'max',\n      exclusive: true,\n      params: { max },\n      skipAbsent: true,\n      test(value: Maybe<number>) {\n        return value! <= this.resolve(max);\n      },\n    });\n  }\n\n  lessThan(less: number | Reference<number>, message = locale.lessThan) {\n    return this.test({\n      message,\n      name: 'max',\n      exclusive: true,\n      params: { less },\n      skipAbsent: true,\n      test(value: Maybe<number>) {\n        return value! < this.resolve(less);\n      },\n    });\n  }\n\n  moreThan(more: number | Reference<number>, message = locale.moreThan) {\n    return this.test({\n      message,\n      name: 'min',\n      exclusive: true,\n      params: { more },\n      skipAbsent: true,\n      test(value: Maybe<number>) {\n        return value! > this.resolve(more);\n      },\n    });\n  }\n\n  positive(msg = locale.positive) {\n    return this.moreThan(0, msg);\n  }\n\n  negative(msg = locale.negative) {\n    return this.lessThan(0, msg);\n  }\n\n  integer(message = locale.integer) {\n    return this.test({\n      name: 'integer',\n      message,\n      skipAbsent: true,\n      test: (val) => Number.isInteger(val),\n    });\n  }\n\n  truncate() {\n    return this.transform((value) => (!isAbsent(value) ? value | 0 : value));\n  }\n\n  round(method?: 'ceil' | 'floor' | 'round' | 'trunc') {\n    let avail = ['ceil', 'floor', 'round', 'trunc'];\n    method = (method?.toLowerCase() as any) || ('round' as const);\n\n    // this exists for symemtry with the new Math.trunc\n    if (method === 'trunc') return this.truncate();\n\n    if (avail.indexOf(method!.toLowerCase()) === -1)\n      throw new TypeError(\n        'Only valid options for round() are: ' + avail.join(', '),\n      );\n\n    return this.transform((value) =>\n      !isAbsent(value) ? Math[method!](value) : value,\n    );\n  }\n}\n\ncreate.prototype = NumberSchema.prototype;\n\n//\n// Number Interfaces\n//\n\nexport default interface NumberSchema<\n  TType extends Maybe<number> = number | undefined,\n  TContext = AnyObject,\n  TDefault = undefined,\n  TFlags extends Flags = '',\n> extends Schema<TType, TContext, TDefault, TFlags> {\n  default<D extends Maybe<TType>>(\n    def: DefaultThunk<D, TContext>,\n  ): NumberSchema<TType, TContext, D, ToggleDefault<TFlags, D>>;\n\n  concat<UType extends Maybe<number>, UContext, UFlags extends Flags, UDefault>(\n    schema: NumberSchema<UType, UContext, UDefault, UFlags>,\n  ): NumberSchema<\n    Concat<TType, UType>,\n    TContext & UContext,\n    UDefault,\n    TFlags | UFlags\n  >;\n  concat(schema: this): this;\n\n  defined(\n    msg?: Message,\n  ): NumberSchema<Defined<TType>, TContext, TDefault, TFlags>;\n  optional(): NumberSchema<TType | undefined, TContext, TDefault, TFlags>;\n\n  required(\n    msg?: Message,\n  ): NumberSchema<NonNullable<TType>, TContext, TDefault, TFlags>;\n  notRequired(): NumberSchema<Maybe<TType>, TContext, TDefault, TFlags>;\n\n  nullable(\n    msg?: Message,\n  ): NumberSchema<TType | null, TContext, TDefault, TFlags>;\n  nonNullable(\n    msg?: Message,\n  ): NumberSchema<NotNull<TType>, TContext, TDefault, TFlags>;\n\n  strip(\n    enabled: false,\n  ): NumberSchema<TType, TContext, TDefault, UnsetFlag<TFlags, 's'>>;\n  strip(\n    enabled?: true,\n  ): NumberSchema<TType, TContext, TDefault, SetFlag<TFlags, 's'>>;\n}\n"
  },
  {
    "path": "src/object.ts",
    "content": "// @ts-ignore\nimport { getter, normalizePath, join } from 'property-expr';\nimport { camelCase, snakeCase } from 'tiny-case';\n\nimport { Flags, Maybe, SetFlag, ToggleDefault, UnsetFlag } from './util/types';\nimport { object as locale } from './locale';\nimport sortFields from './util/sortFields';\nimport sortByKeyOrder from './util/sortByKeyOrder';\nimport { DefaultThunk, InternalOptions, ISchema, Message } from './types';\nimport type { Defined, NotNull, _ } from './util/types';\nimport Reference from './Reference';\nimport Schema, { SchemaObjectDescription, SchemaSpec } from './schema';\nimport { ResolveOptions } from './Condition';\nimport type {\n  AnyObject,\n  ConcatObjectTypes,\n  DefaultFromShape,\n  MakePartial,\n  MergeObjectTypes,\n  ObjectShape,\n  PartialDeep,\n  TypeFromShape,\n} from './util/objectTypes';\nimport parseJson from './util/parseJson';\nimport type { Test } from './util/createValidation';\nimport type ValidationError from './ValidationError';\nexport type { AnyObject };\n\ntype MakeKeysOptional<T> = T extends AnyObject ? _<MakePartial<T>> : T;\n\nexport type Shape<T extends Maybe<AnyObject>, C = any> = {\n  [field in keyof T]-?: ISchema<T[field], C> | Reference;\n};\n\nexport type ObjectSchemaSpec = SchemaSpec<any> & {\n  noUnknown?: boolean;\n};\n\nfunction deepPartial(schema: any) {\n  if ('fields' in schema) {\n    const partial: any = {};\n    for (const [key, fieldSchema] of Object.entries(schema.fields)) {\n      partial[key] = deepPartial(fieldSchema);\n    }\n    return schema.setFields(partial);\n  }\n  if (schema.type === 'array') {\n    const nextArray = schema.optional();\n    if (nextArray.innerType)\n      nextArray.innerType = deepPartial(nextArray.innerType);\n    return nextArray;\n  }\n  if (schema.type === 'tuple') {\n    return schema\n      .optional()\n      .clone({ types: schema.spec.types.map(deepPartial) });\n  }\n  if ('optional' in schema) {\n    return schema.optional();\n  }\n  return schema;\n}\n\nconst deepHas = (obj: any, p: string) => {\n  const path = [...normalizePath(p)];\n  if (path.length === 1) return path[0] in obj;\n  let last = path.pop()!;\n  let parent = getter(join(path), true)(obj);\n  return !!(parent && last in parent);\n};\n\nlet isObject = (obj: any): obj is Record<PropertyKey, unknown> =>\n  Object.prototype.toString.call(obj) === '[object Object]';\n\nfunction unknown(ctx: ObjectSchema<any, any, any>, value: any) {\n  let known = Object.keys(ctx.fields);\n  return Object.keys(value).filter((key) => known.indexOf(key) === -1);\n}\n\nconst defaultSort = sortByKeyOrder([]);\n\nexport function create<\n  C extends Maybe<AnyObject> = AnyObject,\n  S extends ObjectShape = {},\n>(spec?: S) {\n  type TIn = _<TypeFromShape<S, C>>;\n  type TDefault = _<DefaultFromShape<S>>;\n\n  return new ObjectSchema<TIn, C, TDefault>(spec as any);\n}\n\nexport default interface ObjectSchema<\n  TIn extends Maybe<AnyObject>,\n  TContext = AnyObject,\n  // important that this is `any` so that using `ObjectSchema<MyType>`'s default\n  // will match object schema regardless of defaults\n  TDefault = any,\n  TFlags extends Flags = '',\n> extends Schema<MakeKeysOptional<TIn>, TContext, TDefault, TFlags> {\n  default<D extends Maybe<AnyObject>>(\n    def: DefaultThunk<D, TContext>,\n  ): ObjectSchema<TIn, TContext, D, ToggleDefault<TFlags, 'd'>>;\n\n  defined(\n    msg?: Message,\n  ): ObjectSchema<Defined<TIn>, TContext, TDefault, TFlags>;\n  optional(): ObjectSchema<TIn | undefined, TContext, TDefault, TFlags>;\n\n  required(\n    msg?: Message,\n  ): ObjectSchema<NonNullable<TIn>, TContext, TDefault, TFlags>;\n  notRequired(): ObjectSchema<Maybe<TIn>, TContext, TDefault, TFlags>;\n\n  nullable(msg?: Message): ObjectSchema<TIn | null, TContext, TDefault, TFlags>;\n  nonNullable(\n    msg?: Message,\n  ): ObjectSchema<NotNull<TIn>, TContext, TDefault, TFlags>;\n\n  strip(\n    enabled: false,\n  ): ObjectSchema<TIn, TContext, TDefault, UnsetFlag<TFlags, 's'>>;\n  strip(\n    enabled?: true,\n  ): ObjectSchema<TIn, TContext, TDefault, SetFlag<TFlags, 's'>>;\n}\n\nexport default class ObjectSchema<\n  TIn extends Maybe<AnyObject>,\n  TContext = AnyObject,\n  TDefault = any,\n  TFlags extends Flags = '',\n> extends Schema<MakeKeysOptional<TIn>, TContext, TDefault, TFlags> {\n  fields: Shape<NonNullable<TIn>, TContext> = Object.create(null);\n\n  declare spec: ObjectSchemaSpec;\n\n  private _sortErrors = defaultSort;\n  private _nodes: string[] = [];\n\n  private _excludedEdges: readonly [nodeA: string, nodeB: string][] = [];\n\n  constructor(spec?: Shape<TIn, TContext>) {\n    super({\n      type: 'object',\n      check(value): value is NonNullable<MakeKeysOptional<TIn>> {\n        return isObject(value) || typeof value === 'function';\n      },\n    });\n\n    this.withMutation(() => {\n      if (spec) {\n        this.shape(spec as any);\n      }\n    });\n  }\n\n  protected _cast(_value: any, options: InternalOptions<TContext> = {}) {\n    let value = super._cast(_value, options);\n\n    //should ignore nulls here\n    if (value === undefined) return this.getDefault(options);\n\n    if (!this._typeCheck(value)) return value;\n\n    let fields = this.fields;\n\n    let strip = options.stripUnknown ?? this.spec.noUnknown;\n    let props = ([] as string[]).concat(\n      this._nodes,\n      Object.keys(value).filter((v) => !this._nodes.includes(v)),\n    );\n\n    let intermediateValue: Record<string, unknown> = {}; // is filled during the transform below\n    let innerOptions: InternalOptions<TContext> = {\n      ...options,\n      parent: intermediateValue,\n      __validating: options.__validating || false,\n    };\n\n    let isChanged = false;\n    for (const prop of props) {\n      let field = fields[prop];\n      let exists = prop in (value as {})!;\n      let inputValue = value[prop];\n\n      if (field) {\n        let fieldValue;\n\n        // safe to mutate since this is fired in sequence\n        innerOptions.path = (options.path ? `${options.path}.` : '') + prop;\n\n        field = field.resolve({\n          value: inputValue,\n          context: options.context,\n          parent: intermediateValue,\n        });\n\n        let fieldSpec = field instanceof Schema ? field.spec : undefined;\n        let strict = fieldSpec?.strict;\n\n        if (fieldSpec?.strip) {\n          isChanged = isChanged || prop in (value as {});\n          continue;\n        }\n\n        fieldValue =\n          !options.__validating || !strict\n            ? (field as ISchema<any>).cast(inputValue, innerOptions)\n            : inputValue;\n\n        if (fieldValue !== undefined) {\n          intermediateValue[prop] = fieldValue;\n        }\n      } else if (exists && !strip) {\n        intermediateValue[prop] = inputValue;\n      }\n\n      if (\n        exists !== prop in intermediateValue ||\n        intermediateValue[prop] !== inputValue\n      ) {\n        isChanged = true;\n      }\n    }\n\n    return isChanged ? intermediateValue : value;\n  }\n\n  protected _validate(\n    _value: any,\n    options: InternalOptions<TContext> = {},\n    panic: (err: Error, value: unknown) => void,\n    next: (err: ValidationError[], value: unknown) => void,\n  ) {\n    let {\n      from = [],\n      originalValue = _value,\n      recursive = this.spec.recursive,\n    } = options;\n\n    options.from = [{ schema: this, value: originalValue }, ...from];\n    // this flag is needed for handling `strict` correctly in the context of\n    // validation vs just casting. e.g strict() on a field is only used when validating\n    options.__validating = true;\n    options.originalValue = originalValue;\n\n    super._validate(_value, options, panic, (objectErrors, value) => {\n      if (!recursive || !isObject(value)) {\n        next(objectErrors, value);\n        return;\n      }\n\n      originalValue = originalValue || value;\n\n      let tests = [] as Test[];\n      for (let key of this._nodes) {\n        let field = this.fields[key];\n\n        if (!field || Reference.isRef(field)) {\n          continue;\n        }\n\n        tests.push(\n          field.asNestedTest({\n            options,\n            key,\n            parent: value,\n            parentPath: options.path,\n            originalParent: originalValue,\n          }),\n        );\n      }\n\n      this.runTests(\n        { tests, value, originalValue, options },\n        panic,\n        (fieldErrors) => {\n          next(fieldErrors.sort(this._sortErrors).concat(objectErrors), value);\n        },\n      );\n    });\n  }\n\n  clone(spec?: Partial<ObjectSchemaSpec>): this {\n    const next = super.clone(spec);\n    next.fields = { ...this.fields };\n    next._nodes = this._nodes;\n    next._excludedEdges = this._excludedEdges;\n    next._sortErrors = this._sortErrors;\n\n    return next;\n  }\n\n  concat<IIn extends Maybe<AnyObject>, IC, ID, IF extends Flags>(\n    schema: ObjectSchema<IIn, IC, ID, IF>,\n  ): ObjectSchema<\n    ConcatObjectTypes<TIn, IIn>,\n    TContext & IC,\n    Extract<IF, 'd'> extends never\n      ? // this _attempts_ to cover the default from shape case\n        TDefault extends AnyObject\n        ? ID extends AnyObject\n          ? _<ConcatObjectTypes<TDefault, ID>>\n          : ID\n        : ID\n      : ID,\n    TFlags | IF\n  >;\n  concat(schema: this): this;\n  concat(schema: any): any {\n    let next = super.concat(schema) as any;\n\n    let nextFields = next.fields;\n    for (let [field, schemaOrRef] of Object.entries(this.fields)) {\n      const target = nextFields[field];\n      nextFields[field] = target === undefined ? schemaOrRef : target;\n    }\n\n    return next.withMutation((s: any) =>\n      // XXX: excludes here is wrong\n      s.setFields(nextFields, [\n        ...this._excludedEdges,\n        ...schema._excludedEdges,\n      ]),\n    );\n  }\n\n  protected _getDefault(options?: ResolveOptions<TContext>) {\n    if ('default' in this.spec) {\n      return super._getDefault(options);\n    }\n\n    // if there is no default set invent one\n    if (!this._nodes.length) {\n      return undefined;\n    }\n\n    let dft: any = {};\n    this._nodes.forEach((key) => {\n      const field = this.fields[key] as any;\n\n      let innerOptions = options;\n      if (innerOptions?.value) {\n        innerOptions = {\n          ...innerOptions,\n          parent: innerOptions.value,\n          value: innerOptions.value[key],\n        };\n      }\n\n      dft[key] =\n        field && 'getDefault' in field\n          ? field.getDefault(innerOptions)\n          : undefined;\n    });\n\n    return dft;\n  }\n\n  private setFields<TInNext extends Maybe<AnyObject>, TDefaultNext>(\n    shape: Shape<TInNext, TContext>,\n    excludedEdges?: readonly [string, string][],\n  ): ObjectSchema<TInNext, TContext, TDefaultNext, TFlags> {\n    let next = this.clone() as any;\n    next.fields = shape;\n\n    next._nodes = sortFields(shape, excludedEdges);\n    next._sortErrors = sortByKeyOrder(Object.keys(shape));\n    // XXX: this carries over edges which may not be what you want\n    if (excludedEdges) next._excludedEdges = excludedEdges;\n    return next;\n  }\n\n  shape<U extends ObjectShape>(\n    additions: U,\n    excludes: readonly [string, string][] = [],\n  ) {\n    type UIn = TypeFromShape<U, TContext>;\n    type UDefault = Extract<TFlags, 'd'> extends never\n      ? // not defaulted then assume the default is derived and should be merged\n        _<TDefault & DefaultFromShape<U>>\n      : TDefault;\n\n    return this.clone().withMutation((next) => {\n      let edges = next._excludedEdges;\n      if (excludes.length) {\n        if (!Array.isArray(excludes[0])) excludes = [excludes as any];\n\n        edges = [...next._excludedEdges, ...excludes];\n      }\n\n      // XXX: excludes here is wrong\n      return next.setFields<_<MergeObjectTypes<TIn, UIn>>, UDefault>(\n        Object.assign(next.fields, additions) as any,\n        edges,\n      );\n    });\n  }\n\n  partial() {\n    const partial: any = {};\n    for (const [key, schema] of Object.entries(this.fields)) {\n      partial[key] =\n        'optional' in schema && schema.optional instanceof Function\n          ? schema.optional()\n          : schema;\n    }\n\n    return this.setFields<Partial<TIn>, TDefault>(partial);\n  }\n\n  deepPartial(): ObjectSchema<PartialDeep<TIn>, TContext, TDefault, TFlags> {\n    const next = deepPartial(this);\n    return next;\n  }\n\n  pick<TKey extends keyof TIn>(keys: readonly TKey[]) {\n    const picked: any = {};\n    for (const key of keys) {\n      if (this.fields[key]) picked[key] = this.fields[key];\n    }\n\n    return this.setFields<{ [K in TKey]: TIn[K] }, TDefault>(\n      picked,\n      this._excludedEdges.filter(\n        ([a, b]) => keys.includes(a as TKey) && keys.includes(b as TKey),\n      ),\n    );\n  }\n\n  omit<TKey extends keyof TIn>(keys: readonly TKey[]) {\n    const remaining: TKey[] = [];\n\n    for (const key of Object.keys(this.fields) as TKey[]) {\n      if (keys.includes(key)) continue;\n      remaining.push(key);\n    }\n\n    return this.pick<keyof Omit<TIn, TKey>>(remaining as any);\n  }\n\n  from(from: string, to: keyof TIn, alias?: boolean) {\n    let fromGetter = getter(from, true);\n\n    return this.transform((obj) => {\n      if (!obj) return obj;\n      let newObj = obj;\n      if (deepHas(obj, from)) {\n        newObj = { ...obj };\n        if (!alias) delete newObj[from];\n\n        newObj[to] = fromGetter(obj);\n      }\n\n      return newObj;\n    });\n  }\n\n  /** Parse an input JSON string to an object */\n  json() {\n    return this.transform(parseJson);\n  }\n\n  /**\n   * Similar to `noUnknown` but only validates that an object is the right shape without stripping the unknown keys\n   */\n  exact(message?: Message): this {\n    return this.test({\n      name: 'exact',\n      exclusive: true,\n      message: message || locale.exact,\n      test(value) {\n        if (value == null) return true;\n\n        const unknownKeys = unknown(this.schema, value);\n\n        return (\n          unknownKeys.length === 0 ||\n          this.createError({ params: { properties: unknownKeys.join(', ') } })\n        );\n      },\n    });\n  }\n\n  stripUnknown(): this {\n    return this.clone({ noUnknown: true });\n  }\n\n  noUnknown(message?: Message): this;\n  noUnknown(noAllow: boolean, message?: Message): this;\n  noUnknown(noAllow: Message | boolean = true, message = locale.noUnknown) {\n    if (typeof noAllow !== 'boolean') {\n      message = noAllow;\n      noAllow = true;\n    }\n\n    let next = this.test({\n      name: 'noUnknown',\n      exclusive: true,\n      message: message,\n      test(value) {\n        if (value == null) return true;\n        const unknownKeys = unknown(this.schema, value);\n        return (\n          !noAllow ||\n          unknownKeys.length === 0 ||\n          this.createError({ params: { unknown: unknownKeys.join(', ') } })\n        );\n      },\n    });\n\n    next.spec.noUnknown = noAllow;\n\n    return next;\n  }\n\n  unknown(allow = true, message = locale.noUnknown) {\n    return this.noUnknown(!allow, message);\n  }\n\n  transformKeys(fn: (key: string) => string) {\n    return this.transform((obj) => {\n      if (!obj) return obj;\n      const result: AnyObject = {};\n      for (const key of Object.keys(obj)) result[fn(key)] = obj[key];\n      return result;\n    });\n  }\n\n  camelCase() {\n    return this.transformKeys(camelCase);\n  }\n\n  snakeCase() {\n    return this.transformKeys(snakeCase);\n  }\n\n  constantCase() {\n    return this.transformKeys((key) => snakeCase(key).toUpperCase());\n  }\n\n  describe(options?: ResolveOptions<TContext>) {\n    const next = (options ? this.resolve(options) : this).clone();\n    const base = super.describe(options) as SchemaObjectDescription;\n    base.fields = {};\n    for (const [key, value] of Object.entries(next.fields)) {\n      let innerOptions = options;\n      if (innerOptions?.value) {\n        innerOptions = {\n          ...innerOptions,\n          parent: innerOptions.value,\n          value: innerOptions.value[key],\n        };\n      }\n      base.fields[key] = value.describe(innerOptions);\n    }\n    return base;\n  }\n}\n\ncreate.prototype = ObjectSchema.prototype;\n"
  },
  {
    "path": "src/schema.ts",
    "content": "import { mixed as locale } from './locale';\nimport Condition, {\n  ConditionBuilder,\n  ConditionConfig,\n  ResolveOptions,\n} from './Condition';\nimport createValidation, {\n  TestFunction,\n  Test,\n  TestConfig,\n  NextCallback,\n  PanicCallback,\n  TestOptions,\n  resolveParams,\n} from './util/createValidation';\nimport printValue from './util/printValue';\nimport Ref from './Reference';\nimport { getIn } from './util/reach';\nimport {\n  ValidateOptions,\n  TransformFunction,\n  Message,\n  InternalOptions,\n  ExtraParams,\n  ISchema,\n  NestedTestConfig,\n  DefaultThunk,\n} from './types';\n\nimport ValidationError from './ValidationError';\nimport ReferenceSet from './util/ReferenceSet';\nimport Reference from './Reference';\nimport isAbsent from './util/isAbsent';\nimport type { Flags, Maybe, ResolveFlags, _ } from './util/types';\nimport toArray from './util/toArray';\nimport cloneDeep from './util/cloneDeep';\nimport {\n  issuesFromValidationError,\n  StandardResult,\n  type StandardSchema,\n  type StandardSchemaProps,\n} from './standardSchema';\n\nexport type SchemaSpec<TDefault> = {\n  coerce: boolean;\n  nullable: boolean;\n  optional: boolean;\n  default?: TDefault | (() => TDefault);\n  abortEarly?: boolean;\n  strip?: boolean;\n  strict?: boolean;\n  recursive?: boolean;\n  disableStackTrace?: boolean;\n  label?: string | undefined;\n  meta?: SchemaMetadata;\n};\n\nexport interface CustomSchemaMetadata {}\n\n// If `CustomSchemaMeta` isn't extended with any keys, we'll fall back to a\n// loose Record definition allowing free form usage.\nexport type SchemaMetadata = keyof CustomSchemaMetadata extends never\n  ? Record<PropertyKey, any>\n  : CustomSchemaMetadata;\n\nexport type SchemaOptions<TType, TDefault> = {\n  type: string;\n  spec?: Partial<SchemaSpec<TDefault>>;\n  check: (value: any) => value is NonNullable<TType>;\n};\n\nexport type AnySchema<\n  TType = any,\n  C = any,\n  D = any,\n  F extends Flags = Flags,\n> = Schema<TType, C, D, F>;\n\nexport interface CastOptions<C = {}> {\n  parent?: any;\n  context?: C;\n  assert?: boolean;\n  stripUnknown?: boolean;\n  // XXX: should be private?\n  path?: string;\n  index?: number;\n  key?: string;\n  originalValue?: any;\n  value?: any;\n  resolved?: boolean;\n}\n\nexport interface CastOptionalityOptions<C = {}>\n  extends Omit<CastOptions<C>, 'assert'> {\n  /**\n   * Whether or not to throw TypeErrors if casting fails to produce a valid type.\n   * defaults to `true`. The `'ignore-optionality'` options is provided as a migration\n   * path from pre-v1 where `schema.nullable().required()` was allowed. When provided\n   * cast will only throw for values that are the wrong type *not* including `null` and `undefined`\n   */\n  assert: 'ignore-optionality';\n}\n\nexport type RunTest = (\n  opts: TestOptions,\n  panic: PanicCallback,\n  next: NextCallback,\n) => void;\n\nexport type TestRunOptions = {\n  tests: RunTest[];\n  path?: string | undefined;\n  options: InternalOptions;\n  originalValue: any;\n  value: any;\n};\n\nexport interface SchemaRefDescription {\n  type: 'ref';\n  key: string;\n}\n\nexport interface SchemaInnerTypeDescription extends SchemaDescription {\n  innerType?: SchemaFieldDescription | SchemaFieldDescription[];\n}\n\nexport interface SchemaObjectDescription extends SchemaDescription {\n  fields: Record<string, SchemaFieldDescription>;\n}\n\nexport interface SchemaLazyDescription {\n  type: string;\n  label?: string;\n  meta?: SchemaMetadata;\n}\n\nexport type SchemaFieldDescription =\n  | SchemaDescription\n  | SchemaRefDescription\n  | SchemaObjectDescription\n  | SchemaInnerTypeDescription\n  | SchemaLazyDescription;\n\nexport interface SchemaDescription {\n  type: string;\n  label?: string;\n  meta?: SchemaMetadata;\n  oneOf: unknown[];\n  notOneOf: unknown[];\n  default?: unknown;\n  nullable: boolean;\n  optional: boolean;\n  tests: Array<{ name?: string; params: ExtraParams | undefined }>;\n}\n\nexport default abstract class Schema<\n  TType = any,\n  TContext = any,\n  TDefault = any,\n  TFlags extends Flags = '',\n> implements\n    ISchema<TType, TContext, TFlags, TDefault>,\n    StandardSchema<TType, ResolveFlags<TType, TFlags, TDefault>>\n{\n  readonly type: string;\n\n  declare readonly __outputType: ResolveFlags<TType, TFlags, TDefault>;\n  declare readonly __context: TContext;\n  declare readonly __flags: TFlags;\n  declare readonly __isYupSchema__: boolean;\n  declare readonly __default: TDefault;\n\n  readonly deps: readonly string[] = [];\n\n  tests: Test[];\n  transforms: TransformFunction<AnySchema, TContext>[];\n\n  private conditions: Condition[] = [];\n\n  private _mutate?: boolean;\n\n  private internalTests: Record<string, Test | null> = {};\n\n  protected _whitelist = new ReferenceSet();\n  protected _blacklist = new ReferenceSet();\n\n  protected exclusiveTests: Record<string, boolean> = Object.create(null);\n  protected _typeCheck: (value: any) => value is NonNullable<TType>;\n\n  spec: SchemaSpec<any>;\n\n  constructor(options: SchemaOptions<TType, any>) {\n    this.tests = [];\n    this.transforms = [];\n\n    this.withMutation(() => {\n      this.typeError(locale.notType);\n    });\n\n    this.type = options.type;\n    this._typeCheck = options.check;\n\n    this.spec = {\n      strip: false,\n      strict: false,\n      abortEarly: true,\n      recursive: true,\n      disableStackTrace: false,\n      nullable: false,\n      optional: true,\n      coerce: true,\n      ...options?.spec,\n    };\n\n    this.withMutation((s) => {\n      s.nonNullable();\n    });\n  }\n\n  // TODO: remove\n  get _type() {\n    return this.type;\n  }\n\n  clone(spec?: Partial<SchemaSpec<any>>): this {\n    if (this._mutate) {\n      if (spec) Object.assign(this.spec, spec);\n      return this;\n    }\n\n    // if the nested value is a schema we can skip cloning, since\n    // they are already immutable\n    const next: AnySchema = Object.create(Object.getPrototypeOf(this));\n\n    // @ts-expect-error this is readonly\n    next.type = this.type;\n    next._typeCheck = this._typeCheck;\n\n    next._whitelist = this._whitelist.clone();\n    next._blacklist = this._blacklist.clone();\n    next.internalTests = { ...this.internalTests };\n    next.exclusiveTests = { ...this.exclusiveTests };\n\n    // @ts-expect-error this is readonly\n    next.deps = [...this.deps];\n    next.conditions = [...this.conditions];\n    next.tests = [...this.tests];\n    next.transforms = [...this.transforms];\n    next.spec = cloneDeep({ ...this.spec, ...spec });\n\n    return next as this;\n  }\n\n  label(label: string) {\n    let next = this.clone();\n    next.spec.label = label;\n    return next;\n  }\n\n  meta(): SchemaMetadata | undefined;\n  meta(obj: SchemaMetadata): this;\n  meta(...args: [SchemaMetadata?]) {\n    if (args.length === 0) return this.spec.meta;\n\n    let next = this.clone();\n    next.spec.meta = Object.assign(next.spec.meta || {}, args[0]);\n    return next;\n  }\n\n  withMutation<T>(fn: (schema: this) => T): T {\n    let before = this._mutate;\n    this._mutate = true;\n    let result = fn(this);\n    this._mutate = before;\n    return result;\n  }\n\n  concat(schema: this): this;\n  concat(schema: AnySchema): AnySchema;\n  concat(schema: AnySchema): AnySchema {\n    if (!schema || schema === this) return this;\n\n    if (schema.type !== this.type && this.type !== 'mixed')\n      throw new TypeError(\n        `You cannot \\`concat()\\` schema's of different types: ${this.type} and ${schema.type}`,\n      );\n\n    let base = this;\n    let combined = schema.clone();\n\n    const mergedSpec = { ...base.spec, ...combined.spec };\n\n    combined.spec = mergedSpec;\n    combined.internalTests = {\n      ...base.internalTests,\n      ...combined.internalTests,\n    };\n\n    // manually merge the blacklist/whitelist (the other `schema` takes\n    // precedence in case of conflicts)\n    combined._whitelist = base._whitelist.merge(\n      schema._whitelist,\n      schema._blacklist,\n    );\n    combined._blacklist = base._blacklist.merge(\n      schema._blacklist,\n      schema._whitelist,\n    );\n\n    // start with the current tests\n    combined.tests = base.tests;\n    combined.exclusiveTests = base.exclusiveTests;\n\n    // manually add the new tests to ensure\n    // the deduping logic is consistent\n    combined.withMutation((next) => {\n      schema.tests.forEach((fn) => {\n        next.test(fn.OPTIONS!);\n      });\n    });\n\n    combined.transforms = [...base.transforms, ...combined.transforms];\n    return combined as any;\n  }\n\n  isType(v: unknown): v is TType {\n    if (v == null) {\n      if (this.spec.nullable && v === null) return true;\n      if (this.spec.optional && v === undefined) return true;\n      return false;\n    }\n\n    return this._typeCheck(v);\n  }\n\n  resolve(options: ResolveOptions<TContext>) {\n    let schema = this;\n\n    if (schema.conditions.length) {\n      let conditions = schema.conditions;\n\n      schema = schema.clone();\n      schema.conditions = [];\n      schema = conditions.reduce(\n        (prevSchema, condition) =>\n          condition.resolve(prevSchema, options) as any,\n        schema,\n      ) as any as this;\n\n      schema = schema.resolve(options);\n    }\n\n    return schema;\n  }\n\n  protected resolveOptions<T extends InternalOptions<any>>(options: T): T {\n    return {\n      ...options,\n      from: options.from || [],\n      strict: options.strict ?? this.spec.strict,\n      abortEarly: options.abortEarly ?? this.spec.abortEarly,\n      recursive: options.recursive ?? this.spec.recursive,\n      disableStackTrace:\n        options.disableStackTrace ?? this.spec.disableStackTrace,\n    };\n  }\n\n  /**\n   * Run the configured transform pipeline over an input value.\n   */\n  cast(value: any, options?: CastOptions<TContext>): this['__outputType'];\n  cast(\n    value: any,\n    options: CastOptionalityOptions<TContext>,\n  ): this['__outputType'] | null | undefined;\n  cast(\n    value: any,\n    options: CastOptions<TContext> | CastOptionalityOptions<TContext> = {},\n  ): this['__outputType'] {\n    let resolvedSchema = this.resolve({\n      ...options,\n      value,\n      // parent: options.parent,\n      // context: options.context,\n    });\n    let allowOptionality = options.assert === 'ignore-optionality';\n\n    let result = resolvedSchema._cast(value, options as any);\n\n    if (options.assert !== false && !resolvedSchema.isType(result)) {\n      if (allowOptionality && isAbsent(result)) {\n        return result as any;\n      }\n\n      let formattedValue = printValue(value);\n      let formattedResult = printValue(result);\n\n      throw new TypeError(\n        `The value of ${\n          options.path || 'field'\n        } could not be cast to a value ` +\n          `that satisfies the schema type: \"${resolvedSchema.type}\". \\n\\n` +\n          `attempted value: ${formattedValue} \\n` +\n          (formattedResult !== formattedValue\n            ? `result of cast: ${formattedResult}`\n            : ''),\n      );\n    }\n\n    return result;\n  }\n\n  protected _cast(rawValue: any, options: CastOptions<TContext>): any {\n    let value =\n      rawValue === undefined\n        ? rawValue\n        : this.transforms.reduce(\n            (prevValue, fn) => fn.call(this, prevValue, rawValue, this, options),\n            rawValue,\n          );\n\n    if (value === undefined) {\n      value = this.getDefault(options);\n    }\n\n    return value;\n  }\n\n  protected _validate(\n    _value: any,\n    options: InternalOptions<TContext> = {},\n    panic: (err: Error, value: unknown) => void,\n    next: (err: ValidationError[], value: unknown) => void,\n  ): void {\n    let { path, originalValue = _value, strict = this.spec.strict } = options;\n\n    let value = _value;\n    if (!strict) {\n      value = this._cast(value, { assert: false, ...options });\n    }\n\n    let initialTests = [];\n    for (let test of Object.values(this.internalTests)) {\n      if (test) initialTests.push(test);\n    }\n\n    this.runTests(\n      {\n        path,\n        value,\n        originalValue,\n        options,\n        tests: initialTests,\n      },\n      panic,\n      (initialErrors) => {\n        // even if we aren't ending early we can't proceed further if the types aren't correct\n        if (initialErrors.length) {\n          return next(initialErrors, value);\n        }\n\n        this.runTests(\n          {\n            path,\n            value,\n            originalValue,\n            options,\n            tests: this.tests,\n          },\n          panic,\n          next,\n        );\n      },\n    );\n  }\n\n  /**\n   * Executes a set of validations, either schema, produced Tests or a nested\n   * schema validate result.\n   */\n  protected runTests(\n    runOptions: TestRunOptions,\n    panic: (err: Error, value: unknown) => void,\n    next: (errors: ValidationError[], value: unknown) => void,\n  ): void {\n    let fired = false;\n    let { tests, value, originalValue, path, options } = runOptions;\n\n    let panicOnce = (arg: Error) => {\n      if (fired) return;\n      fired = true;\n      panic(arg, value);\n    };\n\n    let nextOnce = (arg: ValidationError[]) => {\n      if (fired) return;\n      fired = true;\n      next(arg, value);\n    };\n\n    let count = tests.length;\n    let nestedErrors = [] as ValidationError[];\n\n    if (!count) return nextOnce([]);\n\n    let args = {\n      value,\n      originalValue,\n      path,\n      options,\n      schema: this,\n    };\n\n    for (let i = 0; i < tests.length; i++) {\n      const test = tests[i];\n\n      test(args!, panicOnce, function finishTestRun(err) {\n        if (err) {\n          Array.isArray(err)\n            ? nestedErrors.push(...err)\n            : nestedErrors.push(err);\n        }\n        if (--count <= 0) {\n          nextOnce(nestedErrors);\n        }\n      });\n    }\n  }\n\n  asNestedTest({\n    key,\n    index,\n    parent,\n    parentPath,\n    originalParent,\n    options,\n  }: NestedTestConfig): RunTest {\n    const k = key ?? index;\n    if (k == null) {\n      throw TypeError('Must include `key` or `index` for nested validations');\n    }\n\n    const isIndex = typeof k === 'number';\n    let value = parent[k];\n\n    const testOptions = {\n      ...options,\n      // Nested validations fields are always strict:\n      //    1. parent isn't strict so the casting will also have cast inner values\n      //    2. parent is strict in which case the nested values weren't cast either\n      strict: true,\n      parent,\n      value,\n      originalValue: originalParent[k],\n      // FIXME: tests depend on `index` being passed around deeply,\n      //   we should not let the options.key/index bleed through\n      key: undefined,\n      // index: undefined,\n      [isIndex ? 'index' : 'key']: k,\n      path:\n        isIndex || k.includes('.')\n          ? `${parentPath || ''}[${isIndex ? k : `\"${k}\"`}]`\n          : (parentPath ? `${parentPath}.` : '') + key,\n    };\n\n    return (_: any, panic, next) =>\n      this.resolve(testOptions)._validate(value, testOptions, panic, next);\n  }\n\n  validate(\n    value: any,\n    options?: ValidateOptions<TContext>,\n  ): Promise<this['__outputType']> {\n    let schema = this.resolve({ ...options, value });\n    let disableStackTrace =\n      options?.disableStackTrace ?? schema.spec.disableStackTrace;\n\n    return new Promise((resolve, reject) =>\n      schema._validate(\n        value,\n        options,\n        (error, parsed) => {\n          if (ValidationError.isError(error)) error.value = parsed;\n          reject(error);\n        },\n        (errors, validated) => {\n          if (errors.length)\n            reject(\n              new ValidationError(\n                errors!,\n                validated,\n                undefined,\n                undefined,\n                disableStackTrace,\n              ),\n            );\n          else resolve(validated as this['__outputType']);\n        },\n      ),\n    );\n  }\n\n  validateSync(\n    value: any,\n    options?: ValidateOptions<TContext>,\n  ): this['__outputType'] {\n    let schema = this.resolve({ ...options, value });\n    let result: any;\n    let disableStackTrace =\n      options?.disableStackTrace ?? schema.spec.disableStackTrace;\n\n    schema._validate(\n      value,\n      { ...options, sync: true },\n      (error, parsed) => {\n        if (ValidationError.isError(error)) error.value = parsed;\n        throw error;\n      },\n      (errors, validated) => {\n        if (errors.length)\n          throw new ValidationError(\n            errors!,\n            value,\n            undefined,\n            undefined,\n            disableStackTrace,\n          );\n        result = validated;\n      },\n    );\n\n    return result;\n  }\n\n  isValid(value: any, options?: ValidateOptions<TContext>): Promise<boolean> {\n    return this.validate(value, options).then(\n      () => true,\n      (err) => {\n        if (ValidationError.isError(err)) return false;\n        throw err;\n      },\n    );\n  }\n\n  isValidSync(\n    value: any,\n    options?: ValidateOptions<TContext>,\n  ): value is this['__outputType'] {\n    try {\n      this.validateSync(value, options);\n      return true;\n    } catch (err) {\n      if (ValidationError.isError(err)) return false;\n      throw err;\n    }\n  }\n\n  protected _getDefault(options?: ResolveOptions<TContext>) {\n    let defaultValue = this.spec.default;\n\n    if (defaultValue == null) {\n      return defaultValue;\n    }\n\n    return typeof defaultValue === 'function'\n      ? defaultValue.call(this, options)\n      : cloneDeep(defaultValue);\n  }\n\n  getDefault(\n    options?: ResolveOptions<TContext>,\n    // If schema is defaulted we know it's at least not undefined\n  ): TDefault {\n    let schema = this.resolve(options || {});\n    return schema._getDefault(options);\n  }\n\n  default(def: DefaultThunk<any>): any {\n    if (arguments.length === 0) {\n      return this._getDefault();\n    }\n\n    let next = this.clone({ default: def });\n\n    return next as any;\n  }\n\n  strict(isStrict = true) {\n    return this.clone({ strict: isStrict });\n  }\n\n  protected nullability(nullable: boolean, message?: Message<any>) {\n    const next = this.clone({ nullable });\n    next.internalTests.nullable = createValidation({\n      message,\n      name: 'nullable',\n      test(value) {\n        return value === null ? this.schema.spec.nullable : true;\n      },\n    });\n    return next;\n  }\n\n  protected optionality(optional: boolean, message?: Message<any>) {\n    const next = this.clone({ optional });\n    next.internalTests.optionality = createValidation({\n      message,\n      name: 'optionality',\n      test(value) {\n        return value === undefined ? this.schema.spec.optional : true;\n      },\n    });\n    return next;\n  }\n\n  optional(): any {\n    return this.optionality(true);\n  }\n  defined(message = locale.defined): any {\n    return this.optionality(false, message);\n  }\n\n  nullable(): any {\n    return this.nullability(true);\n  }\n  nonNullable(message = locale.notNull): any {\n    return this.nullability(false, message);\n  }\n\n  required(message: Message<any> = locale.required): any {\n    return this.clone().withMutation((next) =>\n      next.nonNullable(message).defined(message),\n    );\n  }\n  notRequired(): any {\n    return this.clone().withMutation((next) => next.nullable().optional());\n  }\n\n  transform(fn: TransformFunction<this>) {\n    let next = this.clone();\n    next.transforms.push(fn as TransformFunction<any>);\n    return next;\n  }\n\n  /**\n   * Adds a test function to the schema's queue of tests.\n   * tests can be exclusive or non-exclusive.\n   *\n   * - exclusive tests, will replace any existing tests of the same name.\n   * - non-exclusive: can be stacked\n   *\n   * If a non-exclusive test is added to a schema with an exclusive test of the same name\n   * the exclusive test is removed and further tests of the same name will be stacked.\n   *\n   * If an exclusive test is added to a schema with non-exclusive tests of the same name\n   * the previous tests are removed and further tests of the same name will replace each other.\n   */\n  test(options: TestConfig<this['__outputType'], TContext>): this;\n  test(test: TestFunction<this['__outputType'], TContext>): this;\n  test(name: string, test: TestFunction<this['__outputType'], TContext>): this;\n  test(\n    name: string,\n    message: Message,\n    test: TestFunction<this['__outputType'], TContext>,\n  ): this;\n  test(...args: any[]) {\n    let opts: TestConfig;\n\n    if (args.length === 1) {\n      if (typeof args[0] === 'function') {\n        opts = { test: args[0] };\n      } else {\n        opts = args[0];\n      }\n    } else if (args.length === 2) {\n      opts = { name: args[0], test: args[1] };\n    } else {\n      opts = { name: args[0], message: args[1], test: args[2] };\n    }\n\n    if (opts.message === undefined) opts.message = locale.default;\n\n    if (typeof opts.test !== 'function')\n      throw new TypeError('`test` is a required parameters');\n\n    let next = this.clone();\n    let validate = createValidation(opts);\n\n    let isExclusive =\n      opts.exclusive || (opts.name && next.exclusiveTests[opts.name] === true);\n\n    if (opts.exclusive) {\n      if (!opts.name)\n        throw new TypeError(\n          'Exclusive tests must provide a unique `name` identifying the test',\n        );\n    }\n\n    if (opts.name) next.exclusiveTests[opts.name] = !!opts.exclusive;\n\n    next.tests = next.tests.filter((fn) => {\n      if (fn.OPTIONS!.name === opts.name) {\n        if (isExclusive) return false;\n        if (fn.OPTIONS!.test === validate.OPTIONS.test) return false;\n      }\n      return true;\n    });\n\n    next.tests.push(validate);\n\n    return next;\n  }\n\n  when(builder: ConditionBuilder<this>): this;\n  when(keys: string | string[], builder: ConditionBuilder<this>): this;\n  when(options: ConditionConfig<this>): this;\n  when(keys: string | string[], options: ConditionConfig<this>): this;\n  when(\n    keys: string | string[] | ConditionBuilder<this> | ConditionConfig<this>,\n    options?: ConditionBuilder<this> | ConditionConfig<this>,\n  ) {\n    if (!Array.isArray(keys) && typeof keys !== 'string') {\n      options = keys;\n      keys = '.';\n    }\n\n    let next = this.clone();\n    let deps = toArray(keys).map((key) => new Ref(key));\n\n    deps.forEach((dep) => {\n      // @ts-ignore readonly array\n      if (dep.isSibling) next.deps.push(dep.key);\n    });\n\n    next.conditions.push(\n      (typeof options === 'function'\n        ? new Condition(deps, options!)\n        : Condition.fromOptions(deps, options!)) as Condition,\n    );\n\n    return next;\n  }\n\n  typeError(message: Message) {\n    let next = this.clone();\n\n    next.internalTests.typeError = createValidation({\n      message,\n      name: 'typeError',\n      skipAbsent: true,\n      test(value) {\n        if (!this.schema._typeCheck(value))\n          return this.createError({\n            params: {\n              type: this.schema.type,\n            },\n          });\n        return true;\n      },\n    });\n    return next;\n  }\n\n  oneOf<U extends TType>(\n    enums: ReadonlyArray<U | Reference>,\n    message?: Message<{ values: any }>,\n  ): this;\n  oneOf(\n    enums: ReadonlyArray<TType | Reference>,\n    message: Message<{ values: any }>,\n  ): any;\n  oneOf<U extends TType>(\n    enums: ReadonlyArray<U | Reference>,\n    message = locale.oneOf,\n  ): any {\n    let next = this.clone();\n\n    enums.forEach((val) => {\n      next._whitelist.add(val);\n      next._blacklist.delete(val);\n    });\n\n    next.internalTests.whiteList = createValidation({\n      message,\n      name: 'oneOf',\n      skipAbsent: true,\n      test(value) {\n        let valids = (this.schema as Schema)._whitelist;\n        let resolved = valids.resolveAll(this.resolve);\n\n        return resolved.includes(value)\n          ? true\n          : this.createError({\n              params: {\n                values: Array.from(valids).join(', '),\n                resolved,\n              },\n            });\n      },\n    });\n\n    return next;\n  }\n\n  notOneOf<U extends TType>(\n    enums: ReadonlyArray<Maybe<U> | Reference>,\n    message = locale.notOneOf,\n  ): this {\n    let next = this.clone();\n    enums.forEach((val) => {\n      next._blacklist.add(val);\n      next._whitelist.delete(val);\n    });\n\n    next.internalTests.blacklist = createValidation({\n      message,\n      name: 'notOneOf',\n      test(value) {\n        let invalids = (this.schema as Schema)._blacklist;\n        let resolved = invalids.resolveAll(this.resolve);\n        if (resolved.includes(value))\n          return this.createError({\n            params: {\n              values: Array.from(invalids).join(', '),\n              resolved,\n            },\n          });\n        return true;\n      },\n    });\n\n    return next;\n  }\n\n  strip(strip = true): any {\n    let next = this.clone();\n    next.spec.strip = strip;\n    return next as any;\n  }\n\n  /**\n   * Return a serialized description of the schema including validations, flags, types etc.\n   *\n   * @param options Provide any needed context for resolving runtime schema alterations (lazy, when conditions, etc).\n   */\n  describe(options?: ResolveOptions<TContext>) {\n    const next = (options ? this.resolve(options) : this).clone();\n    const { label, meta, optional, nullable } = next.spec;\n    const description: SchemaDescription = {\n      meta,\n      label,\n      optional,\n      nullable,\n      default: next.getDefault(options),\n      type: next.type,\n      oneOf: next._whitelist.describe(),\n      notOneOf: next._blacklist.describe(),\n      tests: next.tests\n        .filter(\n          (n, idx, list) =>\n            list.findIndex((c) => c.OPTIONS!.name === n.OPTIONS!.name) === idx,\n        )\n        .map((fn) => {\n          const params =\n            fn.OPTIONS!.params && options\n              ? resolveParams({ ...fn.OPTIONS!.params }, options)\n              : fn.OPTIONS!.params;\n\n          return {\n            name: fn.OPTIONS!.name,\n            params,\n          };\n        }),\n    };\n\n    return description;\n  }\n\n  get ['~standard']() {\n    const schema = this;\n\n    const standard: StandardSchemaProps<\n      TType,\n      ResolveFlags<TType, TFlags, TDefault>\n    > = {\n      version: 1,\n      vendor: 'yup',\n      async validate(\n        value: unknown,\n      ): Promise<StandardResult<ResolveFlags<TType, TFlags, TDefault>>> {\n        try {\n          const result = await schema.validate(value, {\n            abortEarly: false,\n          });\n\n          return {\n            value: result as ResolveFlags<TType, TFlags, TDefault>,\n          };\n        } catch (err) {\n          if (err instanceof ValidationError) {\n            return {\n              issues: issuesFromValidationError(err),\n            };\n          }\n\n          throw err;\n        }\n      },\n    };\n\n    return standard;\n  }\n}\n\nexport default interface Schema<\n  /* eslint-disable @typescript-eslint/no-unused-vars */\n  TType = any,\n  TContext = any,\n  TDefault = any,\n  TFlags extends Flags = '',\n  /* eslint-enable @typescript-eslint/no-unused-vars */\n> {\n  validateAt(\n    path: string,\n    value: any,\n    options?: ValidateOptions<TContext>,\n  ): Promise<any>;\n  validateSyncAt(\n    path: string,\n    value: any,\n    options?: ValidateOptions<TContext>,\n  ): any;\n  equals: Schema['oneOf'];\n  is: Schema['oneOf'];\n  not: Schema['notOneOf'];\n  nope: Schema['notOneOf'];\n}\n\n// @ts-expect-error\nSchema.prototype.__isYupSchema__ = true;\n\nfor (const method of ['validate', 'validateSync'])\n  Schema.prototype[`${method}At` as 'validateAt' | 'validateSyncAt'] =\n    function (path: string, value: any, options: ValidateOptions = {}) {\n      const { parent, parentPath, schema } = getIn(\n        this,\n        path,\n        value,\n        options.context,\n      );\n      return (schema as any)[method](parent && parent[parentPath], {\n        ...options,\n        parent,\n        path,\n      });\n    };\n\nfor (const alias of ['equals', 'is'] as const)\n  Schema.prototype[alias] = Schema.prototype.oneOf;\n\nfor (const alias of ['not', 'nope'] as const)\n  Schema.prototype[alias] = Schema.prototype.notOneOf;\n"
  },
  {
    "path": "src/setLocale.ts",
    "content": "import locale, { LocaleObject } from './locale';\n\nexport type { LocaleObject };\n\nexport default function setLocale(custom: LocaleObject) {\n  Object.keys(custom).forEach((type) => {\n    // @ts-ignore\n    Object.keys(custom[type]!).forEach((method) => {\n      // @ts-ignore\n      locale[type][method] = custom[type][method];\n    });\n  });\n}\n"
  },
  {
    "path": "src/standardSchema.ts",
    "content": "/**\n * Copied from @standard-schema/spec to avoid having a dependency on it.\n * https://github.com/standard-schema/standard-schema/blob/main/packages/spec/src/index.ts\n */\n\nimport ValidationError from './ValidationError';\n\nexport interface StandardSchema<Input = unknown, Output = Input> {\n  readonly '~standard': StandardSchemaProps<Input, Output>;\n}\n\nexport interface StandardSchemaProps<Input = unknown, Output = Input> {\n  readonly version: 1;\n  readonly vendor: string;\n  readonly validate: (\n    value: unknown,\n  ) => StandardResult<Output> | Promise<StandardResult<Output>>;\n  readonly types?: StandardTypes<Input, Output> | undefined;\n}\n\nexport type StandardResult<Output> =\n  | StandardSuccessResult<Output>\n  | StandardFailureResult;\n\nexport interface StandardSuccessResult<Output> {\n  readonly value: Output;\n  readonly issues?: undefined;\n}\n\nexport interface StandardFailureResult {\n  readonly issues: ReadonlyArray<StandardIssue>;\n}\n\nexport interface StandardIssue {\n  readonly message: string;\n  readonly path?: ReadonlyArray<PropertyKey | StandardPathSegment> | undefined;\n}\n\nexport interface StandardPathSegment {\n  readonly key: PropertyKey;\n}\n\nexport interface StandardTypes<Input, Output> {\n  readonly input: Input;\n  readonly output: Output;\n}\n\nexport function createStandardPath(\n  path: string | undefined,\n): StandardIssue['path'] {\n  if (!path?.length) {\n    return undefined;\n  }\n\n  // Array to store the final path segments\n  const segments: string[] = [];\n  // Buffer for building the current segment\n  let currentSegment = '';\n  // Track if we're inside square brackets (array/property access)\n  let inBrackets = false;\n  // Track if we're inside quotes (for property names with special chars)\n  let inQuotes = false;\n\n  for (let i = 0; i < path.length; i++) {\n    const char = path[i];\n\n    if (char === '[' && !inQuotes) {\n      // When entering brackets, push any accumulated segment after splitting on dots\n      if (currentSegment) {\n        segments.push(...currentSegment.split('.').filter(Boolean));\n        currentSegment = '';\n      }\n      inBrackets = true;\n      continue;\n    }\n\n    if (char === ']' && !inQuotes) {\n      if (currentSegment) {\n        // Handle numeric indices (e.g. arr[0])\n        if (/^\\d+$/.test(currentSegment)) {\n          segments.push(currentSegment);\n        } else {\n          // Handle quoted property names (e.g. obj[\"foo.bar\"])\n          segments.push(currentSegment.replace(/^\"|\"$/g, ''));\n        }\n        currentSegment = '';\n      }\n      inBrackets = false;\n      continue;\n    }\n\n    if (char === '\"') {\n      // Toggle quote state for handling quoted property names\n      inQuotes = !inQuotes;\n      continue;\n    }\n\n    if (char === '.' && !inBrackets && !inQuotes) {\n      // On dots outside brackets/quotes, push current segment\n      if (currentSegment) {\n        segments.push(currentSegment);\n        currentSegment = '';\n      }\n      continue;\n    }\n\n    currentSegment += char;\n  }\n\n  // Push any remaining segment after splitting on dots\n  if (currentSegment) {\n    segments.push(...currentSegment.split('.').filter(Boolean));\n  }\n\n  return segments;\n}\n\nexport function createStandardIssues(\n  error: ValidationError,\n  parentPath?: string,\n): StandardIssue[] {\n  const path = parentPath ? `${parentPath}.${error.path}` : error.path;\n\n  return error.errors.map(\n    (err) =>\n      ({\n        message: err,\n        path: createStandardPath(path),\n      } satisfies StandardIssue),\n  );\n}\n\nexport function issuesFromValidationError(\n  error: ValidationError,\n  parentPath?: string,\n): StandardIssue[] {\n  if (!error.inner?.length && error.errors.length) {\n    return createStandardIssues(error, parentPath);\n  }\n\n  const path = parentPath ? `${parentPath}.${error.path}` : error.path;\n\n  return error.inner.flatMap((err) => issuesFromValidationError(err, path));\n}\n"
  },
  {
    "path": "src/string.ts",
    "content": "import { MixedLocale, mixed as mixedLocale, string as locale } from './locale';\nimport isAbsent from './util/isAbsent';\nimport type Reference from './Reference';\nimport type { Message, AnyObject, DefaultThunk } from './types';\nimport type {\n  Concat,\n  Defined,\n  Flags,\n  NotNull,\n  SetFlag,\n  ToggleDefault,\n  UnsetFlag,\n  Maybe,\n  Optionals,\n} from './util/types';\nimport Schema from './schema';\nimport { parseDateStruct } from './util/parseIsoDate';\n\n// Taken from HTML spec: https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address\nlet rEmail =\n  // eslint-disable-next-line\n  /^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;\n\nlet rUrl =\n  // eslint-disable-next-line\n  /^((https?|ftp):)?\\/\\/(((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:)*@)?(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]))|((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)+(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.?)(:\\d*)?)(\\/((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)+(\\/(([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)*)*)?)?(\\?((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)|[\\uE000-\\uF8FF]|\\/|\\?)*)?(\\#((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)|\\/|\\?)*)?$/i;\n\n// eslint-disable-next-line\nlet rUUID =\n  /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;\n\nlet yearMonthDay = '^\\\\d{4}-\\\\d{2}-\\\\d{2}';\nlet hourMinuteSecond = '\\\\d{2}:\\\\d{2}:\\\\d{2}';\nlet zOrOffset = '(([+-]\\\\d{2}(:?\\\\d{2})?)|Z)';\nlet rIsoDateTime = new RegExp(\n  `${yearMonthDay}T${hourMinuteSecond}(\\\\.\\\\d+)?${zOrOffset}$`,\n);\n\nlet isTrimmed = (value: Maybe<string>) =>\n  isAbsent(value) || value === value.trim();\n\nexport type MatchOptions = {\n  excludeEmptyString?: boolean;\n  message: Message<{ regex: RegExp }>;\n  name?: string;\n};\n\nexport type DateTimeOptions = {\n  message: Message<{ allowOffset?: boolean; precision?: number }>;\n  /** Allow a time zone offset. False requires UTC 'Z' timezone. (default: false) */\n  allowOffset?: boolean;\n  /** Require a certain sub-second precision on the date. (default: undefined -- any or no sub-second precision) */\n  precision?: number;\n};\n\nlet objStringTag = {}.toString();\n\nfunction create(): StringSchema;\nfunction create<\n  T extends string,\n  TContext extends Maybe<AnyObject> = AnyObject,\n>(): StringSchema<T | undefined, TContext>;\nfunction create() {\n  return new StringSchema();\n}\n\nexport { create };\n\nexport default class StringSchema<\n  TType extends Maybe<string> = string | undefined,\n  TContext = AnyObject,\n  TDefault = undefined,\n  TFlags extends Flags = '',\n> extends Schema<TType, TContext, TDefault, TFlags> {\n  constructor() {\n    super({\n      type: 'string',\n      check(value): value is NonNullable<TType> {\n        if (value instanceof String) value = value.valueOf();\n        return typeof value === 'string';\n      },\n    });\n\n    this.withMutation(() => {\n      this.transform((value, _raw) => {\n        if (!this.spec.coerce || this.isType(value)) return value;\n\n        // don't ever convert arrays\n        if (Array.isArray(value)) return value;\n\n        const strValue =\n          value != null && value.toString ? value.toString() : value;\n\n        // no one wants plain objects converted to [Object object]\n        if (strValue === objStringTag) return value;\n\n        return strValue;\n      });\n    });\n  }\n\n  required(message?: Message<any>) {\n    return super.required(message).withMutation((schema: this) =>\n      schema.test({\n        message: message || mixedLocale.required,\n        name: 'required',\n        skipAbsent: true,\n        test: (value) => !!value!.length,\n      }),\n    );\n  }\n\n  notRequired() {\n    return super.notRequired().withMutation((schema: this) => {\n      schema.tests = schema.tests.filter((t) => t.OPTIONS!.name !== 'required');\n      return schema;\n    });\n  }\n\n  length(\n    length: number | Reference<number>,\n    message: Message<{ length: number }> = locale.length,\n  ) {\n    return this.test({\n      message,\n      name: 'length',\n      exclusive: true,\n      params: { length },\n      skipAbsent: true,\n      test(value: Maybe<string>) {\n        return value!.length === this.resolve(length);\n      },\n    });\n  }\n\n  min(\n    min: number | Reference<number>,\n    message: Message<{ min: number }> = locale.min,\n  ) {\n    return this.test({\n      message,\n      name: 'min',\n      exclusive: true,\n      params: { min },\n      skipAbsent: true,\n      test(value: Maybe<string>) {\n        return value!.length >= this.resolve(min);\n      },\n    });\n  }\n\n  max(\n    max: number | Reference<number>,\n    message: Message<{ max: number }> = locale.max,\n  ) {\n    return this.test({\n      name: 'max',\n      exclusive: true,\n      message,\n      params: { max },\n      skipAbsent: true,\n      test(value: Maybe<string>) {\n        return value!.length <= this.resolve(max);\n      },\n    });\n  }\n\n  matches(regex: RegExp, options?: MatchOptions | MatchOptions['message']) {\n    let excludeEmptyString = false;\n    let message;\n    let name;\n\n    if (options) {\n      if (typeof options === 'object') {\n        ({\n          excludeEmptyString = false,\n          message,\n          name,\n        } = options as MatchOptions);\n      } else {\n        message = options;\n      }\n    }\n\n    return this.test({\n      name: name || 'matches',\n      message: message || locale.matches,\n      params: { regex },\n      skipAbsent: true,\n      test: (value: Maybe<string>) =>\n        (value === '' && excludeEmptyString) || value!.search(regex) !== -1,\n    });\n  }\n\n  email(message = locale.email) {\n    return this.matches(rEmail, {\n      name: 'email',\n      message,\n      excludeEmptyString: true,\n    });\n  }\n\n  url(message = locale.url) {\n    return this.matches(rUrl, {\n      name: 'url',\n      message,\n      excludeEmptyString: true,\n    });\n  }\n\n  uuid(message = locale.uuid) {\n    return this.matches(rUUID, {\n      name: 'uuid',\n      message,\n      excludeEmptyString: false,\n    });\n  }\n\n  datetime(options?: DateTimeOptions | DateTimeOptions['message']) {\n    let message: DateTimeOptions['message'] = '';\n    let allowOffset: DateTimeOptions['allowOffset'];\n    let precision: DateTimeOptions['precision'];\n\n    if (options) {\n      if (typeof options === 'object') {\n        ({\n          message = '',\n          allowOffset = false,\n          precision = undefined,\n        } = options as DateTimeOptions);\n      } else {\n        message = options;\n      }\n    }\n\n    return this.matches(rIsoDateTime, {\n      name: 'datetime',\n      message: message || locale.datetime,\n      excludeEmptyString: true,\n    })\n      .test({\n        name: 'datetime_offset',\n        message: message || locale.datetime_offset,\n        params: { allowOffset },\n        skipAbsent: true,\n        test: (value: Maybe<string>) => {\n          if (!value || allowOffset) return true;\n          const struct = parseDateStruct(value);\n          if (!struct) return false;\n          return !!struct.z;\n        },\n      })\n      .test({\n        name: 'datetime_precision',\n        message: message || locale.datetime_precision,\n        params: { precision },\n        skipAbsent: true,\n        test: (value: Maybe<string>) => {\n          if (!value || precision == undefined) return true;\n          const struct = parseDateStruct(value);\n          if (!struct) return false;\n          return struct.precision === precision;\n        },\n      });\n  }\n\n  //-- transforms --\n  ensure(): StringSchema<NonNullable<TType>> {\n    return this.default('' as Defined<TType>).transform((val) =>\n      val === null ? '' : val,\n    ) as any;\n  }\n\n  trim(message = locale.trim) {\n    return this.transform((val) => (val != null ? val.trim() : val)).test({\n      message,\n      name: 'trim',\n      test: isTrimmed,\n    });\n  }\n\n  lowercase(message = locale.lowercase) {\n    return this.transform((value) =>\n      !isAbsent(value) ? value.toLowerCase() : value,\n    ).test({\n      message,\n      name: 'string_case',\n      exclusive: true,\n      skipAbsent: true,\n      test: (value: Maybe<string>) =>\n        isAbsent(value) || value === value.toLowerCase(),\n    });\n  }\n\n  uppercase(message = locale.uppercase) {\n    return this.transform((value) =>\n      !isAbsent(value) ? value.toUpperCase() : value,\n    ).test({\n      message,\n      name: 'string_case',\n      exclusive: true,\n      skipAbsent: true,\n      test: (value: Maybe<string>) =>\n        isAbsent(value) || value === value.toUpperCase(),\n    });\n  }\n}\n\ncreate.prototype = StringSchema.prototype;\n\n//\n// String Interfaces\n//\n\nexport default interface StringSchema<\n  TType extends Maybe<string> = string | undefined,\n  TContext = AnyObject,\n  TDefault = undefined,\n  TFlags extends Flags = '',\n> extends Schema<TType, TContext, TDefault, TFlags> {\n  default<D extends Maybe<TType>>(\n    def: DefaultThunk<D, TContext>,\n  ): StringSchema<TType, TContext, D, ToggleDefault<TFlags, D>>;\n\n  oneOf<U extends TType>(\n    arrayOfValues: ReadonlyArray<U | Reference<U>>,\n    message?: MixedLocale['oneOf'],\n  ): StringSchema<U | Optionals<TType>, TContext, TDefault, TFlags>;\n  oneOf(\n    enums: ReadonlyArray<TType | Reference>,\n    message?: Message<{ values: any }>,\n  ): this;\n\n  concat<UType extends Maybe<string>, UContext, UDefault, UFlags extends Flags>(\n    schema: StringSchema<UType, UContext, UDefault, UFlags>,\n  ): StringSchema<\n    Concat<TType, UType>,\n    TContext & UContext,\n    UDefault,\n    TFlags | UFlags\n  >;\n  concat(schema: this): this;\n\n  defined(\n    msg?: Message,\n  ): StringSchema<Defined<TType>, TContext, TDefault, TFlags>;\n  optional(): StringSchema<TType | undefined, TContext, TDefault, TFlags>;\n\n  required(\n    msg?: Message,\n  ): StringSchema<NonNullable<TType>, TContext, TDefault, TFlags>;\n  notRequired(): StringSchema<Maybe<TType>, TContext, TDefault, TFlags>;\n\n  nullable(\n    msg?: Message,\n  ): StringSchema<TType | null, TContext, TDefault, TFlags>;\n  nonNullable(\n    msg?: Message\n  ): StringSchema<NotNull<TType>, TContext, TDefault, TFlags>;\n\n  strip(\n    enabled: false,\n  ): StringSchema<TType, TContext, TDefault, UnsetFlag<TFlags, 's'>>;\n  strip(\n    enabled?: true,\n  ): StringSchema<TType, TContext, TDefault, SetFlag<TFlags, 's'>>;\n}\n"
  },
  {
    "path": "src/tuple.ts",
    "content": "// @ts-ignore\n\nimport type {\n  AnyObject,\n  DefaultThunk,\n  InternalOptions,\n  ISchema,\n  Message,\n} from './types';\nimport type {\n  Defined,\n  Flags,\n  NotNull,\n  SetFlag,\n  ToggleDefault,\n  UnsetFlag,\n  Maybe,\n} from './util/types';\nimport type { ResolveOptions } from './Condition';\nimport Schema, {\n  RunTest,\n  SchemaInnerTypeDescription,\n  SchemaSpec,\n} from './schema';\nimport ValidationError from './ValidationError';\nimport { tuple as tupleLocale } from './locale';\n\ntype AnyTuple = [unknown, ...unknown[]];\n\nexport function create<T extends AnyTuple>(schemas: {\n  [K in keyof T]: ISchema<T[K]>;\n}) {\n  return new TupleSchema<T | undefined>(schemas);\n}\n\nexport default interface TupleSchema<\n  TType extends Maybe<AnyTuple> = AnyTuple | undefined,\n  TContext = AnyObject,\n  TDefault = undefined,\n  TFlags extends Flags = '',\n> extends Schema<TType, TContext, TDefault, TFlags> {\n  default<D extends Maybe<TType>>(\n    def: DefaultThunk<D, TContext>,\n  ): TupleSchema<TType, TContext, D, ToggleDefault<TFlags, D>>;\n\n  concat<TOther extends TupleSchema<any, any>>(schema: TOther): TOther;\n\n  defined(\n    msg?: Message,\n  ): TupleSchema<Defined<TType>, TContext, TDefault, TFlags>;\n  optional(): TupleSchema<TType | undefined, TContext, TDefault, TFlags>;\n\n  required(\n    msg?: Message,\n  ): TupleSchema<NonNullable<TType>, TContext, TDefault, TFlags>;\n  notRequired(): TupleSchema<Maybe<TType>, TContext, TDefault, TFlags>;\n\n  nullable(\n    msg?: Message,\n  ): TupleSchema<TType | null, TContext, TDefault, TFlags>;\n  nonNullable(\n    msg?: Message\n  ): TupleSchema<NotNull<TType>, TContext, TDefault, TFlags>;\n\n  strip(\n    enabled: false,\n  ): TupleSchema<TType, TContext, TDefault, UnsetFlag<TFlags, 's'>>;\n  strip(\n    enabled?: true,\n  ): TupleSchema<TType, TContext, TDefault, SetFlag<TFlags, 's'>>;\n}\n\ninterface TupleSchemaSpec<T> extends SchemaSpec<any> {\n  types: T extends any[]\n    ? {\n        [K in keyof T]: ISchema<T[K]>;\n      }\n    : never;\n}\n\nexport default class TupleSchema<\n  TType extends Maybe<AnyTuple> = AnyTuple | undefined,\n  TContext = AnyObject,\n  TDefault = undefined,\n  TFlags extends Flags = '',\n> extends Schema<TType, TContext, TDefault, TFlags> {\n  declare spec: TupleSchemaSpec<TType>;\n\n  constructor(schemas: [ISchema<any>, ...ISchema<any>[]]) {\n    super({\n      type: 'tuple',\n      spec: { types: schemas } as any,\n      check(v: any): v is NonNullable<TType> {\n        const types = (this.spec as TupleSchemaSpec<TType>).types;\n        return Array.isArray(v) && v.length === types.length;\n      },\n    });\n\n    this.withMutation(() => {\n      this.typeError(tupleLocale.notType);\n    });\n  }\n\n  protected _cast(inputValue: any, options: InternalOptions<TContext>) {\n    const { types } = this.spec;\n    const value = super._cast(inputValue, options);\n\n    if (!this._typeCheck(value)) {\n      return value;\n    }\n\n    let isChanged = false;\n    const castArray = types.map((type, idx) => {\n      const castElement = type.cast(value[idx], {\n        ...options,\n        path: `${options.path || ''}[${idx}]`,\n        parent: value,\n        originalValue: value[idx],\n        value: value[idx],\n        index: idx,\n      });\n      if (castElement !== value[idx]) isChanged = true;\n      return castElement;\n    });\n\n    return isChanged ? castArray : value;\n  }\n\n  protected _validate(\n    _value: any,\n    options: InternalOptions<TContext> = {},\n    panic: (err: Error, value: unknown) => void,\n    next: (err: ValidationError[], value: unknown) => void,\n  ) {\n    let itemTypes = this.spec.types;\n\n    super._validate(_value, options, panic, (tupleErrors, value) => {\n      // intentionally not respecting recursive\n      if (!this._typeCheck(value)) {\n        next(tupleErrors, value);\n        return;\n      }\n\n      let tests: RunTest[] = [];\n      for (let [index, itemSchema] of itemTypes.entries()) {\n        tests[index] = itemSchema!.asNestedTest({\n          options,\n          index,\n          parent: value,\n          parentPath: options.path,\n          originalParent: options.originalValue ?? _value,\n        });\n      }\n\n      this.runTests(\n        {\n          value,\n          tests,\n          originalValue: options.originalValue ?? _value,\n          options,\n        },\n        panic,\n        (innerTypeErrors) => next(innerTypeErrors.concat(tupleErrors), value),\n      );\n    });\n  }\n\n  describe(options?: ResolveOptions<TContext>) {\n    const next = (options ? this.resolve(options) : this).clone();\n    const base = super.describe(options) as SchemaInnerTypeDescription;\n    base.innerType = next.spec.types.map((schema, index) => {\n      let innerOptions = options;\n      if (innerOptions?.value) {\n        innerOptions = {\n          ...innerOptions,\n          parent: innerOptions.value,\n          value: innerOptions.value[index],\n        };\n      }\n      return schema.describe(innerOptions);\n    });\n    return base;\n  }\n}\n\ncreate.prototype = TupleSchema.prototype;\n"
  },
  {
    "path": "src/types.ts",
    "content": "import type { ResolveOptions } from './Condition';\nimport type {\n  AnySchema,\n  CastOptionalityOptions,\n  CastOptions,\n  SchemaFieldDescription,\n  SchemaSpec,\n} from './schema';\nimport type { Test } from './util/createValidation';\nimport type { AnyObject } from './util/objectTypes';\nimport type { Flags } from './util/types';\n\nexport type { AnyObject, AnySchema };\n\nexport interface ISchema<T, C = any, F extends Flags = any, D = any> {\n  __flags: F;\n  __context: C;\n  __outputType: T;\n  __default: D;\n\n  cast(value: any, options?: CastOptions<C>): T;\n  cast(value: any, options: CastOptionalityOptions<C>): T | null | undefined;\n\n  validate(value: any, options?: ValidateOptions<C>): Promise<T>;\n\n  asNestedTest(config: NestedTestConfig): Test;\n\n  describe(options?: ResolveOptions<C>): SchemaFieldDescription;\n  resolve(options: ResolveOptions<C>): ISchema<T, C, F>;\n}\n\nexport type DefaultThunk<T, C = any> = T | ((options?: ResolveOptions<C>) => T);\n\nexport type InferType<T extends ISchema<any, any>> = T['__outputType'];\n\nexport type TransformFunction<T extends AnySchema, C = any> = (\n  this: T,\n  value: any,\n  originalValue: any,\n  schema: T,\n  options: CastOptions<C>,\n) => any;\n\nexport interface Ancester<TContext> {\n  schema: ISchema<any, TContext>;\n  value: any;\n}\nexport interface ValidateOptions<TContext = {}> {\n  /**\n   * Only validate the input, skipping type casting and transformation. Default - false\n   */\n  strict?: boolean;\n  /**\n   * Return from validation methods on the first error rather than after all validations run. Default - true\n   */\n  abortEarly?: boolean;\n  /**\n   * Remove unspecified keys from objects. Default - false\n   */\n  stripUnknown?: boolean;\n  /**\n   * When false validations will not descend into nested schema (relevant for objects or arrays). Default - true\n   */\n  recursive?: boolean;\n  /**\n   * When true ValidationError instance won't include stack trace information. Default - false\n   */\n  disableStackTrace?: boolean;\n  /**\n   * Any context needed for validating schema conditions (see: when())\n   */\n  context?: TContext;\n}\n\nexport interface InternalOptions<TContext = any>\n  extends ValidateOptions<TContext> {\n  __validating?: boolean;\n  originalValue?: any;\n  index?: number;\n  key?: string;\n  parent?: any;\n  path?: string;\n  sync?: boolean;\n  from?: Ancester<TContext>[];\n}\n\nexport interface MessageParams {\n  path: string;\n  value: any;\n  originalValue: any;\n  originalPath: string;\n  label: string;\n  type: string;\n  spec: SchemaSpec<any> & Record<string, unknown>;\n}\n\nexport type Message<Extra extends Record<string, unknown> = any> =\n  | string\n  | ((params: Extra & MessageParams) => unknown)\n  | Record<PropertyKey, unknown>;\n\nexport type ExtraParams = Record<string, unknown>;\n\nexport type AnyMessageParams = MessageParams & ExtraParams;\n\nexport interface NestedTestConfig {\n  options: InternalOptions<any>;\n  parent: any;\n  originalParent: any;\n  parentPath: string | undefined;\n  key?: string;\n  index?: number;\n}\n"
  },
  {
    "path": "src/util/ReferenceSet.ts",
    "content": "import type { SchemaRefDescription } from '../schema';\nimport Reference from '../Reference';\n\nexport default class ReferenceSet extends Set<unknown | Reference> {\n  describe() {\n    const description = [] as Array<unknown | SchemaRefDescription>;\n\n    for (const item of this.values()) {\n      description.push(Reference.isRef(item) ? item.describe() : item);\n    }\n    return description;\n  }\n\n  resolveAll(resolve: (v: unknown | Reference) => unknown) {\n    let result = [] as unknown[];\n    for (const item of this.values()) {\n      result.push(resolve(item));\n    }\n    return result;\n  }\n\n  clone() {\n    return new ReferenceSet(this.values());\n  }\n\n  merge(newItems: ReferenceSet, removeItems: ReferenceSet) {\n    const next = this.clone();\n\n    newItems.forEach((value) => next.add(value));\n    removeItems.forEach((value) => next.delete(value));\n    return next;\n  }\n}\n"
  },
  {
    "path": "src/util/cloneDeep.ts",
    "content": "// tweaked from https://github.com/Kelin2025/nanoclone/blob/0abeb7635bda9b68ef2277093f76dbe3bf3948e1/src/index.js\n// MIT licensed\n\nimport isSchema from './isSchema';\n\nfunction clone(src: unknown, seen: Map<any, any> = new Map()) {\n  if (isSchema(src) || !src || typeof src !== 'object') return src;\n  if (seen.has(src)) return seen.get(src);\n\n  let copy: any;\n  if (src instanceof Date) {\n    // Date\n    copy = new Date(src.getTime());\n    seen.set(src, copy);\n  } else if (src instanceof RegExp) {\n    // RegExp\n    copy = new RegExp(src);\n    seen.set(src, copy);\n  } else if (Array.isArray(src)) {\n    // Array\n    copy = new Array(src.length);\n    seen.set(src, copy);\n    for (let i = 0; i < src.length; i++) copy[i] = clone(src[i], seen);\n  } else if (src instanceof Map) {\n    // Map\n    copy = new Map();\n    seen.set(src, copy);\n    for (const [k, v] of src.entries()) copy.set(k, clone(v, seen));\n  } else if (src instanceof Set) {\n    // Set\n    copy = new Set();\n    seen.set(src, copy);\n    for (const v of src) copy.add(clone(v, seen));\n  } else if (src instanceof Object) {\n    // Object\n    copy = {};\n    seen.set(src, copy);\n    for (const [k, v] of Object.entries(src)) copy[k] = clone(v, seen);\n  } else {\n    throw Error(`Unable to clone ${src}`);\n  }\n  return copy;\n}\n\nexport default clone;\n"
  },
  {
    "path": "src/util/createValidation.ts",
    "content": "import ValidationError from '../ValidationError';\nimport Ref from '../Reference';\nimport {\n  ValidateOptions,\n  Message,\n  InternalOptions,\n  ExtraParams,\n  ISchema,\n} from '../types';\nimport Reference from '../Reference';\nimport type { AnySchema } from '../schema';\nimport isAbsent from './isAbsent';\nimport { ResolveOptions } from '../Condition';\n\nexport type PanicCallback = (err: Error) => void;\n\nexport type NextCallback = (\n  err: ValidationError[] | ValidationError | null,\n) => void;\n\nexport type CreateErrorOptions = {\n  path?: string;\n  message?: Message<any>;\n  params?: ExtraParams;\n  type?: string;\n  disableStackTrace?: boolean;\n};\n\nexport type TestContext<TContext = {}> = {\n  path: string;\n  options: ValidateOptions<TContext>;\n  originalValue: any;\n  parent: any;\n  from?: Array<{ schema: ISchema<any, TContext>; value: any }>;\n  schema: any;\n  resolve: <T>(value: T | Reference<T>) => T;\n  createError: (params?: CreateErrorOptions) => ValidationError;\n};\n\nexport type TestFunction<T = unknown, TContext = {}> = (\n  this: TestContext<TContext>,\n  value: T,\n  context: TestContext<TContext>,\n) => void | boolean | ValidationError | Promise<boolean | ValidationError>;\n\nexport type TestOptions<TSchema extends AnySchema = AnySchema> = {\n  value: any;\n  path?: string;\n  options: InternalOptions;\n  originalValue: any;\n  schema: TSchema;\n};\n\nexport type TestConfig<TValue = unknown, TContext = {}> = {\n  name?: string;\n  message?: Message<any>;\n  test: TestFunction<TValue, TContext>;\n  params?: ExtraParams;\n  exclusive?: boolean;\n  skipAbsent?: boolean;\n};\n\nexport type Test = ((\n  opts: TestOptions,\n  panic: PanicCallback,\n  next: NextCallback,\n) => void) & {\n  OPTIONS?: TestConfig;\n};\n\nexport default function createValidation(config: {\n  name?: string;\n  test: TestFunction;\n  params?: ExtraParams;\n  message?: Message<any>;\n  skipAbsent?: boolean;\n}) {\n  function validate<TSchema extends AnySchema = AnySchema>(\n    { value, path = '', options, originalValue, schema }: TestOptions<TSchema>,\n    panic: PanicCallback,\n    next: NextCallback,\n  ) {\n    const { name, test, params, message, skipAbsent } = config;\n    let {\n      parent,\n      context,\n      abortEarly = schema.spec.abortEarly,\n      disableStackTrace = schema.spec.disableStackTrace,\n    } = options;\n    const resolveOptions = { value, parent, context };\n    function createError(overrides: CreateErrorOptions = {}) {\n      const nextParams = resolveParams(\n        {\n          value,\n          originalValue,\n          label: schema.spec.label,\n          path: overrides.path || path,\n          spec: schema.spec,\n          disableStackTrace: overrides.disableStackTrace || disableStackTrace,\n          ...params,\n          ...overrides.params,\n        },\n        resolveOptions,\n      );\n\n      const error = new ValidationError(\n        ValidationError.formatError(overrides.message || message, nextParams),\n        value,\n        nextParams.path,\n        overrides.type || name,\n        nextParams.disableStackTrace,\n      );\n      error.params = nextParams;\n      return error;\n    }\n\n    const invalid = abortEarly ? panic : next;\n\n    let ctx = {\n      path,\n      parent,\n      type: name,\n      from: options.from,\n      createError,\n      resolve<T>(item: T | Reference<T>) {\n        return resolveMaybeRef(item, resolveOptions);\n      },\n      options,\n      originalValue,\n      schema,\n    };\n\n    const handleResult = (validOrError: ReturnType<TestFunction>) => {\n      if (ValidationError.isError(validOrError)) invalid(validOrError);\n      else if (!validOrError) invalid(createError());\n      else next(null);\n    };\n\n    const handleError = (err: any) => {\n      if (ValidationError.isError(err)) invalid(err);\n      else panic(err);\n    };\n\n    const shouldSkip = skipAbsent && isAbsent(value);\n\n    if (shouldSkip) {\n      return handleResult(true);\n    }\n\n    let result: ReturnType<TestFunction>;\n    try {\n      result = test.call(ctx, value, ctx);\n      if (typeof (result as any)?.then === 'function') {\n        if (options.sync) {\n          throw new Error(\n            `Validation test of type: \"${ctx.type}\" returned a Promise during a synchronous validate. ` +\n              `This test will finish after the validate call has returned`,\n          );\n        }\n        return Promise.resolve(result).then(handleResult, handleError);\n      }\n    } catch (err: any) {\n      handleError(err);\n      return;\n    }\n\n    handleResult(result);\n  }\n\n  validate.OPTIONS = config;\n\n  return validate;\n}\n\n// Warning: mutates the input\nexport function resolveParams<T extends ExtraParams>(\n  params: T,\n  options: ResolveOptions,\n) {\n  if (!params) return params;\n\n  type Keys = (keyof typeof params)[];\n  for (const key of Object.keys(params) as Keys) {\n    params[key] = resolveMaybeRef(params[key], options);\n  }\n\n  return params;\n}\n\nfunction resolveMaybeRef<T>(item: T | Reference<T>, options: ResolveOptions) {\n  return Ref.isRef(item)\n    ? item.getValue(options.value, options.parent, options.context)\n    : item;\n}\n"
  },
  {
    "path": "src/util/isAbsent.ts",
    "content": "const isAbsent = (value: any): value is undefined | null => value == null;\n\nexport default isAbsent;\n"
  },
  {
    "path": "src/util/isSchema.ts",
    "content": "import type { ISchema } from '../types';\n\nconst isSchema = (obj: any): obj is ISchema<any> => obj && obj.__isYupSchema__;\n\nexport default isSchema;\n"
  },
  {
    "path": "src/util/objectTypes.ts",
    "content": "import type { Maybe, Optionals } from './types';\nimport type Reference from '../Reference';\nimport type { ISchema } from '../types';\n\nexport type ObjectShape = { [k: string]: ISchema<any> | Reference };\n\nexport type AnyObject = { [k: string]: any };\n\nexport type ResolveStrip<T extends ISchema<any>> = T extends ISchema<\n  any,\n  any,\n  infer F\n>\n  ? Extract<F, 's'> extends never\n    ? T['__outputType']\n    : never\n  : T['__outputType'];\n\nexport type TypeFromShape<S extends ObjectShape, _C> = {\n  [K in keyof S]: S[K] extends ISchema<any>\n    ? ResolveStrip<S[K]>\n    : S[K] extends Reference<infer T>\n    ? T\n    : unknown;\n};\n\nexport type DefaultFromShape<Shape extends ObjectShape> = {\n  [K in keyof Shape]: Shape[K] extends ISchema<any>\n    ? Shape[K]['__default']\n    : undefined;\n};\n\nexport type MergeObjectTypes<T extends Maybe<AnyObject>, U extends AnyObject> =\n  | ({ [P in keyof T]: P extends keyof U ? U[P] : T[P] } & U)\n  | Optionals<T>;\n\nexport type ConcatObjectTypes<\n  T extends Maybe<AnyObject>,\n  U extends Maybe<AnyObject>,\n> =\n  | ({\n      [P in keyof T]: P extends keyof NonNullable<U> ? NonNullable<U>[P] : T[P];\n    } & U)\n  | Optionals<U>;\n\nexport type PartialDeep<T> = T extends\n  | string\n  | number\n  | bigint\n  | boolean\n  | null\n  | undefined\n  | symbol\n  | Date\n  ? T | undefined\n  : T extends Array<infer ArrayType>\n  ? Array<PartialDeep<ArrayType>>\n  : T extends ReadonlyArray<infer ArrayType>\n  ? ReadonlyArray<ArrayType>\n  : { [K in keyof T]?: PartialDeep<T[K]> };\n\ntype OptionalKeys<T extends {}> = {\n  [k in keyof T]: undefined extends T[k] ? k : never;\n}[keyof T];\n\ntype RequiredKeys<T extends object> = Exclude<keyof T, OptionalKeys<T>>;\n\nexport type MakePartial<T extends object> = {\n  [k in OptionalKeys<T> as T[k] extends never ? never : k]?: T[k];\n} & { [k in RequiredKeys<T> as T[k] extends never ? never : k]: T[k] };\n"
  },
  {
    "path": "src/util/parseIsoDate.ts",
    "content": "/**\n * This file is a modified version of the file from the following repository:\n * Date.parse with progressive enhancement for ISO 8601 <https://github.com/csnover/js-iso8601>\n * NON-CONFORMANT EDITION.\n * © 2011 Colin Snover <http://zetafleet.com>\n * Released under MIT license.\n */\n\n// prettier-ignore\n//                1 YYYY                2 MM        3 DD              4 HH     5 mm        6 ss           7 msec         8 Z 9 ±   10 tzHH    11 tzmm\nconst isoReg = /^(\\d{4}|[+-]\\d{6})(?:-?(\\d{2})(?:-?(\\d{2}))?)?(?:[ T]?(\\d{2}):?(\\d{2})(?::?(\\d{2})(?:[,.](\\d{1,}))?)?(?:(Z)|([+-])(\\d{2})(?::?(\\d{2}))?)?)?$/;\n\nexport function parseIsoDate(date: string): number {\n  const struct = parseDateStruct(date);\n  if (!struct) return Date.parse ? Date.parse(date) : Number.NaN;\n\n  // timestamps without timezone identifiers should be considered local time\n  if (struct.z === undefined && struct.plusMinus === undefined) {\n    return new Date(\n      struct.year,\n      struct.month,\n      struct.day,\n      struct.hour,\n      struct.minute,\n      struct.second,\n      struct.millisecond,\n    ).valueOf();\n  }\n\n  let totalMinutesOffset = 0;\n  if (struct.z !== 'Z' && struct.plusMinus !== undefined) {\n    totalMinutesOffset = struct.hourOffset * 60 + struct.minuteOffset;\n    if (struct.plusMinus === '+') totalMinutesOffset = 0 - totalMinutesOffset;\n  }\n\n  return Date.UTC(\n    struct.year,\n    struct.month,\n    struct.day,\n    struct.hour,\n    struct.minute + totalMinutesOffset,\n    struct.second,\n    struct.millisecond,\n  );\n}\n\nexport function parseDateStruct(date: string) {\n  const regexResult = isoReg.exec(date);\n  if (!regexResult) return null;\n\n  // use of toNumber() avoids NaN timestamps caused by “undefined”\n  // values being passed to Date constructor\n  return {\n    year: toNumber(regexResult[1]),\n    month: toNumber(regexResult[2], 1) - 1,\n    day: toNumber(regexResult[3], 1),\n    hour: toNumber(regexResult[4]),\n    minute: toNumber(regexResult[5]),\n    second: toNumber(regexResult[6]),\n    millisecond: regexResult[7]\n      ? // allow arbitrary sub-second precision beyond milliseconds\n        toNumber(regexResult[7].substring(0, 3))\n      : 0,\n    precision: regexResult[7]?.length ?? undefined,\n    z: regexResult[8] || undefined,\n    plusMinus: regexResult[9] || undefined,\n    hourOffset: toNumber(regexResult[10]),\n    minuteOffset: toNumber(regexResult[11]),\n  };\n}\n\nfunction toNumber(str: string, defaultValue = 0) {\n  return Number(str) || defaultValue;\n}\n"
  },
  {
    "path": "src/util/parseJson.ts",
    "content": "import type { AnySchema, TransformFunction } from '../types';\n\nconst parseJson: TransformFunction<any> = (value, _, schema: AnySchema<any>) => {\n  if (typeof value !== 'string') {\n    return value;\n  }\n\n  let parsed = value;\n  try {\n    parsed = JSON.parse(value);\n  } catch (err) {\n    /* */\n  }\n  return schema.isType(parsed) ? parsed : value;\n};\n\nexport default parseJson;\n"
  },
  {
    "path": "src/util/printValue.ts",
    "content": "const toString = Object.prototype.toString;\nconst errorToString = Error.prototype.toString;\nconst regExpToString = RegExp.prototype.toString;\nconst symbolToString =\n  typeof Symbol !== 'undefined' ? Symbol.prototype.toString : () => '';\n\nconst SYMBOL_REGEXP = /^Symbol\\((.*)\\)(.*)$/;\n\nfunction printNumber(val: any) {\n  if (val != +val) return 'NaN';\n  const isNegativeZero = val === 0 && 1 / val < 0;\n  return isNegativeZero ? '-0' : '' + val;\n}\n\nfunction printSimpleValue(val: any, quoteStrings = false) {\n  if (val == null || val === true || val === false) return '' + val;\n\n  const typeOf = typeof val;\n  if (typeOf === 'number') return printNumber(val);\n  if (typeOf === 'string') return quoteStrings ? `\"${val}\"` : val;\n  if (typeOf === 'function')\n    return '[Function ' + (val.name || 'anonymous') + ']';\n  if (typeOf === 'symbol')\n    return symbolToString.call(val).replace(SYMBOL_REGEXP, 'Symbol($1)');\n\n  const tag = toString.call(val).slice(8, -1);\n  if (tag === 'Date')\n    return isNaN(val.getTime()) ? '' + val : val.toISOString(val);\n  if (tag === 'Error' || val instanceof Error)\n    return '[' + errorToString.call(val) + ']';\n  if (tag === 'RegExp') return regExpToString.call(val);\n\n  return null;\n}\n\nexport default function printValue(value: any, quoteStrings?: boolean) {\n  let result = printSimpleValue(value, quoteStrings);\n  if (result !== null) return result;\n\n  return JSON.stringify(\n    value,\n    function (key, value) {\n      let result = printSimpleValue(this[key], quoteStrings);\n      if (result !== null) return result;\n      return value;\n    },\n    2,\n  );\n}\n"
  },
  {
    "path": "src/util/reach.ts",
    "content": "import { forEach } from 'property-expr';\nimport type Reference from '../Reference';\nimport type { InferType, ISchema } from '../types';\nimport type { Get } from 'type-fest';\n\nexport function getIn<C = any>(\n  schema: any,\n  path: string,\n  value?: any,\n  context: C = value,\n): {\n  schema: ISchema<any> | Reference<any>;\n  parent: any;\n  parentPath: string;\n} {\n  let parent: any, lastPart: string, lastPartDebug: string;\n\n  // root path: ''\n  if (!path) return { parent, parentPath: path, schema };\n\n  forEach(path, (_part, isBracket, isArray) => {\n    let part = isBracket ? _part.slice(1, _part.length - 1) : _part;\n\n    schema = schema.resolve({ context, parent, value });\n\n    let isTuple = schema.type === 'tuple';\n    let idx = isArray ? parseInt(part, 10) : 0;\n\n    if (schema.innerType || isTuple) {\n      if (isTuple && !isArray)\n        throw new Error(\n          `Yup.reach cannot implicitly index into a tuple type. the path part \"${lastPartDebug}\" must contain an index to the tuple element, e.g. \"${lastPartDebug}[0]\"`,\n        );\n      if (value && idx >= value.length) {\n        throw new Error(\n          `Yup.reach cannot resolve an array item at index: ${_part}, in the path: ${path}. ` +\n            `because there is no value at that index. `,\n        );\n      }\n      parent = value;\n      value = value && value[idx];\n      schema = isTuple ? schema.spec.types[idx] : schema.innerType!;\n    }\n\n    // sometimes the array index part of a path doesn't exist: \"nested.arr.child\"\n    // in these cases the current part is the next schema and should be processed\n    // in this iteration. For cases where the index signature is included this\n    // check will fail and we'll handle the `child` part on the next iteration like normal\n    if (!isArray) {\n      if (!schema.fields || !schema.fields[part])\n        throw new Error(\n          `The schema does not contain the path: ${path}. ` +\n            `(failed at: ${lastPartDebug} which is a type: \"${schema.type}\")`,\n        );\n\n      parent = value;\n      value = value && value[part];\n      schema = schema.fields[part];\n    }\n\n    lastPart = part;\n    lastPartDebug = isBracket ? '[' + _part + ']' : '.' + _part;\n  });\n\n  return { schema, parent, parentPath: lastPart! };\n}\n\nfunction reach<P extends string, S extends ISchema<any>>(\n  obj: S,\n  path: P,\n  value?: any,\n  context?: any,\n):\n  | Reference<Get<InferType<S>, P>>\n  | ISchema<Get<InferType<S>, P>, S['__context']> {\n  return getIn(obj, path, value, context).schema as any;\n}\n\nexport default reach;\n"
  },
  {
    "path": "src/util/sortByKeyOrder.ts",
    "content": "import ValidationError from '../ValidationError';\n\nfunction findIndex(arr: readonly string[], err: ValidationError) {\n  let idx = Infinity;\n  arr.some((key, ii) => {\n    if (err.path?.includes(key)) {\n      idx = ii;\n      return true;\n    }\n  });\n  return idx;\n}\n\nexport default function sortByKeyOrder(keys: readonly string[]) {\n  return (a: ValidationError, b: ValidationError) => {\n    return findIndex(keys, a) - findIndex(keys, b);\n  };\n}\n"
  },
  {
    "path": "src/util/sortFields.ts",
    "content": "// @ts-expect-error\nimport toposort from 'toposort';\nimport { split } from 'property-expr';\n\nimport Ref from '../Reference';\nimport isSchema from './isSchema';\nimport { ObjectShape } from './objectTypes';\n\nexport default function sortFields(\n  fields: ObjectShape,\n  excludedEdges: readonly [string, string][] = [],\n) {\n  let edges = [] as Array<[string, string]>;\n  let nodes = new Set<string>();\n  let excludes = new Set(excludedEdges.map(([a, b]) => `${a}-${b}`));\n\n  function addNode(depPath: string, key: string) {\n    let node = split(depPath)[0];\n\n    nodes.add(node);\n    if (!excludes.has(`${key}-${node}`)) edges.push([key, node]);\n  }\n\n  for (const key of Object.keys(fields)) {\n    let value = fields[key];\n\n    nodes.add(key);\n\n    if (Ref.isRef(value) && value.isSibling) addNode(value.path, key);\n    else if (isSchema(value) && 'deps' in value)\n      (value as any).deps.forEach((path: string) => addNode(path, key));\n  }\n\n  return toposort.array(Array.from(nodes), edges).reverse() as string[];\n}\n"
  },
  {
    "path": "src/util/toArray.ts",
    "content": "export default function toArray<T>(value?: null | T | readonly T[]) {\n  return value == null ? [] : ([] as T[]).concat(value);\n}\n"
  },
  {
    "path": "src/util/types.ts",
    "content": "export type IfAny<T, Y, N> = 0 extends 1 & T ? Y : N;\n\nexport type Maybe<T> = T | null | undefined;\n\nexport type Preserve<T, U> = T extends U ? U : never;\n\nexport type Optionals<T> = Extract<T, null | undefined>;\n\nexport type Defined<T> = T extends undefined ? never : T;\n\nexport type NotNull<T> = T extends null ? never : T;\n\n/* this seems to force TS to show the full type instead of all the wrapped generics */\nexport type _<T> = T extends {} ? { [k in keyof T]: T[k] } : T;\n\n//\n// Schema Config\n//\n\nexport type Flags = 's' | 'd' | '';\n\nexport type SetFlag<Old extends Flags, F extends Flags> = Exclude<Old, ''> | F;\n\nexport type UnsetFlag<Old extends Flags, F extends Flags> = Exclude<\n  Old,\n  F\n> extends never\n  ? ''\n  : Exclude<Old, F>;\n\nexport type ToggleDefault<F extends Flags, D> = Preserve<\n  D,\n  undefined\n> extends never\n  ? SetFlag<F, 'd'>\n  : UnsetFlag<F, 'd'>;\n\nexport type ResolveFlags<T, F extends Flags, D = T> = Extract<\n  F,\n  'd'\n> extends never\n  ? T\n  : D extends undefined\n  ? T\n  : Defined<T>;\n\nexport type Concat<T, U> = NonNullable<T> & NonNullable<U> extends never\n  ? never\n  : (NonNullable<T> & NonNullable<U>) | Optionals<U>;\n"
  },
  {
    "path": "test/.eslintignore",
    "content": ".eslintrc\n.eslintrc.js\n"
  },
  {
    "path": "test/ValidationError.ts",
    "content": "import { describe, it, expect } from 'vitest';\nimport ValidationError from '../src/ValidationError';\n\ndescribe('ValidationError', () => {\n  describe('formatError', () => {\n    it('should insert the params into the message', () => {\n      const str = ValidationError.formatError('Some message ${param}', {\n        param: 'here',\n      });\n      expect(str).toContain('here');\n    });\n\n    it(`should auto include any param named 'label' or 'path' as the 'path' param`, () => {\n      const str = ValidationError.formatError('${path} goes here', {\n        label: 'label',\n      });\n      expect(str).toContain('label');\n    });\n\n    it(`should use 'this' if a 'label' or 'path' param is not provided`, () => {\n      const str = ValidationError.formatError('${path} goes here', {});\n      expect(str).toContain('this');\n    });\n\n    it(`should include \"undefined\" in the message if undefined is provided as a param`, () => {\n      const str = ValidationError.formatError('${path} value is ${min}', {\n        min: undefined,\n      });\n      expect(str).toContain('undefined');\n    });\n\n    it(`should include \"null\" in the message if null is provided as a param`, () => {\n      const str = ValidationError.formatError('${path} value is ${min}', {\n        min: null,\n      });\n      expect(str).toContain('null');\n    });\n\n    it(`should include \"NaN\" in the message if null is provided as a param`, () => {\n      const str = ValidationError.formatError('${path} value is ${min}', {\n        min: NaN,\n      });\n      expect(str).toContain('NaN');\n    });\n\n    it(`should include 0 in the message if 0 is provided as a param`, () => {\n      const str = ValidationError.formatError('${path} value is ${min}', {\n        min: 0,\n      });\n      expect(str).toContain('0');\n    });\n  });\n\n  it('should disable stacks', () => {\n    const disabled = new ValidationError('error', 1, 'field', 'type', true);\n\n    expect(disabled.constructor.name).toEqual('ValidationErrorNoStack');\n    expect(disabled).toBeInstanceOf(ValidationError);\n  });\n});\n"
  },
  {
    "path": "test/array.ts",
    "content": "import { describe, it, expect, test, vi } from 'vitest';\nimport {\n  string,\n  number,\n  object,\n  array,\n  StringSchema,\n  AnySchema,\n  ValidationError,\n} from '../src';\n\ndescribe('Array types', () => {\n  describe('casting', () => {\n    it('should parse json strings', () => {\n      expect(array().json().cast('[2,3,5,6]')).toEqual([2, 3, 5, 6]);\n    });\n\n    it('should failed casts return input', () => {\n      expect(array().cast('asfasf', { assert: false })).toEqual('asfasf');\n\n      expect(array().cast('{}', { assert: false })).toEqual('{}');\n    });\n\n    it('should recursively cast fields', () => {\n      expect(array().of(number()).cast(['4', '5'])).toEqual([4, 5]);\n\n      expect(array().of(string()).cast(['4', 5, false])).toEqual([\n        '4',\n        '5',\n        'false',\n      ]);\n    });\n\n    it('should pass array options to descendants when casting', async () => {\n      let value = ['1', '2'];\n\n      let itemSchema = string().when([], function (_, _s, opts: any) {\n\n        const parent = opts.parent;\n        const idx = opts.index;\n        const val = opts.value;\n        const originalValue = opts.originalValue;\n        \n        expect(parent).toEqual(value);\n        expect(typeof idx).toBe('number');\n        expect(val).toEqual(parent[idx]);\n        expect(originalValue).toEqual(parent[idx]);\n\n        return string().transform((value, _originalValue, _schema, options: any) => {\n          expect(parent).toEqual(options.parent);\n          expect(typeof options.index).toBe('number');\n          expect(val).toEqual(value);\n\n          return value;\n        });\n      });\n\n      await array().of(itemSchema).validate(value, { context: { name: 'test'} });\n    });\n  });\n\n  it('should handle DEFAULT', () => {\n    expect(array().getDefault()).toBeUndefined();\n\n    expect(\n      array()\n        .default(() => [1, 2, 3])\n        .getDefault(),\n    ).toEqual([1, 2, 3]);\n  });\n\n  it('should type check', () => {\n    let inst = array();\n\n    expect(inst.isType([])).toBe(true);\n    expect(inst.isType({})).toBe(false);\n    expect(inst.isType('true')).toBe(false);\n    expect(inst.isType(NaN)).toBe(false);\n    expect(inst.isType(34545)).toBe(false);\n\n    expect(inst.isType(null)).toBe(false);\n\n    expect(inst.nullable().isType(null)).toBe(true);\n  });\n\n  it('should cast children', () => {\n    expect(array().of(number()).cast(['1', '3'])).toEqual([1, 3]);\n  });\n\n  it('should concat subType correctly', async () => {\n    expect(array(number()).concat(array()).innerType).toBeDefined();\n\n    let merged = array(number()).concat(array(number().required()));\n\n    const ve = new ValidationError('');\n    // expect(ve.toString()).toBe('[object Error]');\n    expect(Object.prototype.toString.call(ve)).toBe('[object Error]');\n    expect((merged.innerType as AnySchema).type).toBe('number');\n\n    await expect(merged.validateAt('[0]', undefined)).rejects.toThrowError();\n  });\n\n  it('should pass options to children', () => {\n    expect(\n      array(object({ name: string() })).cast([{ id: 1, name: 'john' }], {\n        stripUnknown: true,\n      }),\n    ).toEqual([{ name: 'john' }]);\n  });\n\n  describe('validation', () => {\n    test.each([\n      ['required', undefined, array().required()],\n      ['required', null, array().required()],\n      ['null', null, array()],\n      ['length', [1, 2, 3], array().length(2)],\n    ])('Basic validations fail: %s %p', async (_, value, schema) => {\n      expect(await schema.isValid(value)).toBe(false);\n    });\n\n    test.each([\n      ['required', [], array().required()],\n      ['nullable', null, array().nullable()],\n      ['length', [1, 2, 3], array().length(3)],\n    ])('Basic validations pass: %s %p', async (_, value, schema) => {\n      expect(await schema.isValid(value)).toBe(true);\n    });\n\n    it('should allow undefined', async () => {\n      await expect(\n        array().of(number().max(5)).isValid(undefined),\n      ).resolves.toBe(true);\n    });\n\n    it('max should replace earlier tests', async () => {\n      expect(await array().max(4).max(10).isValid(Array(5).fill(0))).toBe(true);\n    });\n\n    it('min should replace earlier tests', async () => {\n      expect(await array().min(10).min(4).isValid(Array(5).fill(0))).toBe(true);\n    });\n\n    it('should respect subtype validations', async () => {\n      let inst = array().of(number().max(5));\n\n      await expect(inst.isValid(['gg', 3])).resolves.toBe(false);\n      await expect(inst.isValid([7, 3])).resolves.toBe(false);\n\n      let value = await inst.validate(['4', 3]);\n\n      expect(value).toEqual([4, 3]);\n    });\n\n    it('should prevent recursive casting', async () => {\n      // @ts-ignore\n      let castSpy = vi.spyOn(StringSchema.prototype, '_cast');\n\n      let value = await array(string()).defined().validate([5]);\n\n      expect(value[0]).toBe('5');\n\n      expect(castSpy).toHaveBeenCalledTimes(1);\n      castSpy.mockRestore();\n    });\n  });\n\n  it('should respect abortEarly', async () => {\n    let inst = array()\n      .of(object({ str: string().required() }))\n      .test('name', 'oops', () => false);\n\n    await expect(inst.validate([{ str: '' }])).rejects.toEqual(\n      expect.objectContaining({\n        value: [{ str: '' }],\n        errors: ['oops'],\n      }),\n    );\n\n    await expect(\n      inst.validate([{ str: '' }], { abortEarly: false }),\n    ).rejects.toEqual(\n      expect.objectContaining({\n        value: [{ str: '' }],\n        errors: ['[0].str is a required field', 'oops'],\n      }),\n    );\n  });\n\n  it('should respect disableStackTrace', async () => {\n    let inst = array().of(object({ str: string().required() }));\n\n    const data = [{ str: undefined }, { str: undefined }];\n    return Promise.all([\n      expect(inst.strict().validate(data)).rejects.toHaveProperty('stack'),\n\n      expect(\n        inst.strict().validate(data, { disableStackTrace: true }),\n      ).rejects.not.toHaveProperty('stack'),\n    ]);\n  });\n\n  it('should compact arrays', () => {\n    let arr = ['', 1, 0, 4, false, null],\n      inst = array();\n\n    expect(inst.compact().cast(arr)).toEqual([1, 4]);\n\n    expect(inst.compact((v) => v == null).cast(arr)).toEqual([\n      '',\n      1,\n      0,\n      4,\n      false,\n    ]);\n  });\n\n  it('should ensure arrays', () => {\n    let inst = array().ensure();\n\n    const a = [1, 4];\n    expect(inst.cast(a)).toBe(a);\n\n    expect(inst.cast(null)).toEqual([]);\n    // nullable is redundant since this should always produce an array\n    // but we want to ensure that null is actually turned into an array\n    expect(inst.nullable().cast(null)).toEqual([]);\n\n    expect(inst.cast(1)).toEqual([1]);\n    expect(inst.nullable().cast(1)).toEqual([1]);\n  });\n\n  it('should pass resolved path to descendants', async () => {\n    let value = ['2', '3'];\n    let expectedPaths = ['[0]', '[1]'];\n\n    let itemSchema = string().when([], function (_, _s, opts: any) {\n      let path = opts.path;\n      expect(expectedPaths).toContain(path);\n      return string().required();\n    });\n\n    await array().of(itemSchema).validate(value);\n  });\n\n  it('should pass deeply resolved path to descendants', async () => {\n    let value = ['2', '3'];\n    let expectedPaths = ['items[0]', 'items[1]'];\n\n    let itemSchema = string().when([], function (_, _s, opts: any) {\n      let path = opts.path;\n      expect(expectedPaths).toContain(path);\n      return string().required();\n    });\n\n    const schema = object({\n      items: array().of(itemSchema)\n    })\n\n    await schema.validate({ items: value });\n  });\n\n  it('should maintain array sparseness through validation', async () => {\n    let sparseArray = new Array(2);\n    sparseArray[1] = 1;\n    let value = await array().of(number()).validate(sparseArray);\n    expect(0 in sparseArray).toBe(false);\n    expect(0 in value!).toBe(false);\n\n    // eslint-disable-next-line no-sparse-arrays\n    expect(value).toEqual([, 1]);\n  });\n\n  it('should validate empty slots in sparse array', async () => {\n    let sparseArray = new Array(2);\n    sparseArray[1] = 1;\n    await expect(\n      array().of(number().required()).isValid(sparseArray),\n    ).resolves.toEqual(false);\n  });\n});\n"
  },
  {
    "path": "test/bool.ts",
    "content": "import { describe, it, expect } from 'vitest';\nimport { bool } from '../src';\nimport * as TestHelpers from './helpers';\n\ndescribe('Boolean types', () => {\n  it('should CAST correctly', () => {\n    let inst = bool();\n\n    expect(inst.cast('true')).toBe(true);\n    expect(inst.cast('True')).toBe(true);\n    expect(inst.cast('false')).toBe(false);\n    expect(inst.cast('False')).toBe(false);\n    expect(inst.cast(1)).toBe(true);\n    expect(inst.cast(0)).toBe(false);\n\n    TestHelpers.castAndShouldFail(inst, 'foo');\n\n    TestHelpers.castAndShouldFail(inst, 'bar1');\n  });\n\n  it('should handle DEFAULT', () => {\n    let inst = bool();\n\n    expect(inst.getDefault()).toBeUndefined();\n    expect(inst.default(true).required().getDefault()).toBe(true);\n  });\n\n  it('should type check', () => {\n    let inst = bool();\n\n    expect(inst.isType(1)).toBe(false);\n    expect(inst.isType(false)).toBe(true);\n    expect(inst.isType('true')).toBe(false);\n    expect(inst.isType(NaN)).toBe(false);\n    expect(inst.isType(new Number('foooo'))).toBe(false);\n\n    expect(inst.isType(34545)).toBe(false);\n    expect(inst.isType(new Boolean(false))).toBe(true);\n\n    expect(inst.isType(null)).toBe(false);\n\n    expect(inst.nullable().isType(null)).toBe(true);\n  });\n\n  it('bool should VALIDATE correctly', () => {\n    let inst = bool().required();\n\n    return Promise.all([\n      expect(bool().isValid('1')).resolves.toBe(true),\n      expect(bool().strict().isValid(null)).resolves.toBe(false),\n      expect(bool().nullable().isValid(null)).resolves.toBe(true),\n      expect(inst.validate(undefined)).rejects.toEqual(\n        expect.objectContaining({\n          errors: ['this is a required field'],\n        }),\n      ),\n    ]);\n  });\n\n  it('should check isTrue correctly', () => {\n    return Promise.all([\n      expect(bool().isTrue().isValid(true)).resolves.toBe(true),\n      expect(bool().isTrue().isValid(false)).resolves.toBe(false),\n    ]);\n  });\n\n  it('should check isFalse correctly', () => {\n    return Promise.all([\n      expect(bool().isFalse().isValid(false)).resolves.toBe(true),\n      expect(bool().isFalse().isValid(true)).resolves.toBe(false),\n    ]);\n  });\n});\n"
  },
  {
    "path": "test/date.ts",
    "content": "import { describe, it, expect } from 'vitest';\nimport { ref, date } from '../src';\nimport * as TestHelpers from './helpers';\n\nfunction isInvalidDate(date: any): date is Date {\n  return date instanceof Date && isNaN(date.getTime());\n}\n\ndescribe('Date types', () => {\n  it('should CAST correctly', () => {\n    let inst = date();\n\n    expect(inst.cast(new Date())).toBeInstanceOf(Date);\n    expect(inst.cast('jan 15 2014')).toEqual(new Date(2014, 0, 15));\n    expect(inst.cast('2014-09-23T19:25:25Z')).toEqual(new Date(1411500325000));\n    // Leading-zero milliseconds\n    expect(inst.cast('2016-08-10T11:32:19.012Z')).toEqual(\n      new Date(1470828739012),\n    );\n    // Microsecond precision\n    expect(inst.cast('2016-08-10T11:32:19.2125Z')).toEqual(\n      new Date(1470828739212),\n    );\n\n    expect(inst.cast(null, { assert: false })).toEqual(null);\n  });\n\n  it('should return invalid date for failed non-null casts', function () {\n    let inst = date();\n\n    expect(inst.cast(null, { assert: false })).toEqual(null);\n    expect(inst.cast(undefined, { assert: false })).toEqual(undefined);\n\n    expect(isInvalidDate(inst.cast('', { assert: false }))).toBe(true);\n    expect(isInvalidDate(inst.cast({}, { assert: false }))).toBe(true);\n  });\n\n  it('should type check', () => {\n    let inst = date();\n\n    expect(inst.isType(new Date())).toBe(true);\n    expect(inst.isType(false)).toBe(false);\n    expect(inst.isType(null)).toBe(false);\n    expect(inst.isType(NaN)).toBe(false);\n    expect(inst.nullable().isType(new Date())).toBe(true);\n  });\n\n  it('should VALIDATE correctly', () => {\n    let inst = date().max(new Date(2014, 5, 15));\n\n    return Promise.all([\n      expect(date().isValid(null)).resolves.toBe(false),\n      expect(date().nullable().isValid(null)).resolves.toBe(true),\n\n      expect(inst.isValid(new Date(2014, 0, 15))).resolves.toBe(true),\n      expect(inst.isValid(new Date(2014, 7, 15))).resolves.toBe(false),\n      expect(inst.isValid('5')).resolves.toBe(true),\n\n      expect(inst.required().validate(undefined)).rejects.toEqual(\n        expect.objectContaining({\n          errors: ['this is a required field'],\n        }),\n      ),\n\n      expect(inst.required().validate(undefined)).rejects.toEqual(\n        TestHelpers.validationErrorWithMessages(\n          expect.stringContaining('required'),\n        ),\n      ),\n      expect(inst.validate(null)).rejects.toEqual(\n        TestHelpers.validationErrorWithMessages(\n          expect.stringContaining('cannot be null'),\n        ),\n      ),\n      expect(inst.validate({})).rejects.toEqual(\n        TestHelpers.validationErrorWithMessages(\n          expect.stringContaining('must be a `date` type'),\n        ),\n      ),\n    ]);\n  });\n\n  it('should check MIN correctly', () => {\n    let min = new Date(2014, 3, 15),\n      invalid = new Date(2014, 1, 15),\n      valid = new Date(2014, 5, 15);\n    expect(function () {\n      date().max('hello');\n    }).toThrowError(TypeError);\n    expect(function () {\n      date().max(ref('$foo'));\n    }).not.toThrowError();\n\n    return Promise.all([\n      expect(date().min(min).isValid(valid)).resolves.toBe(true),\n      expect(date().min(min).isValid(invalid)).resolves.toBe(false),\n      expect(date().min(min).isValid(null)).resolves.toBe(false),\n\n      expect(\n        date()\n          .min(ref('$foo'))\n          .isValid(valid, { context: { foo: min } }),\n      ).resolves.toBe(true),\n      expect(\n        date()\n          .min(ref('$foo'))\n          .isValid(invalid, { context: { foo: min } }),\n      ).resolves.toBe(false),\n    ]);\n  });\n\n  it('should check MAX correctly', () => {\n    let max = new Date(2014, 7, 15),\n      invalid = new Date(2014, 9, 15),\n      valid = new Date(2014, 5, 15);\n    expect(function () {\n      date().max('hello');\n    }).toThrowError(TypeError);\n    expect(function () {\n      date().max(ref('$foo'));\n    }).not.toThrowError();\n\n    return Promise.all([\n      expect(date().max(max).isValid(valid)).resolves.toBe(true),\n      expect(date().max(max).isValid(invalid)).resolves.toBe(false),\n      expect(date().max(max).nullable().isValid(null)).resolves.toBe(true),\n\n      expect(\n        date()\n          .max(ref('$foo'))\n          .isValid(valid, { context: { foo: max } }),\n      ).resolves.toBe(true),\n      expect(\n        date()\n          .max(ref('$foo'))\n          .isValid(invalid, { context: { foo: max } }),\n      ).resolves.toBe(false),\n    ]);\n  });\n});\n"
  },
  {
    "path": "test/helpers.ts",
    "content": "import { describe, it, expect } from 'vitest';\nimport { ISchema } from '../src/types';\nimport printValue from '../src/util/printValue';\n\nexport let castAndShouldFail = (schema: ISchema<any>, value: any) => {\n  expect(() => schema.cast(value)).toThrowError(TypeError);\n};\n\ntype Options = {\n  invalid?: any[];\n  valid?: any[];\n};\nexport let castAll = (\n  inst: ISchema<any>,\n  { invalid = [], valid = [] }: Options,\n) => {\n  valid.forEach(([value, result, schema = inst]) => {\n    it(`should cast ${printValue(value)} to ${printValue(result)}`, () => {\n      expect(schema.cast(value)).toBe(result);\n    });\n  });\n\n  invalid.forEach((value) => {\n    it(`should not cast ${printValue(value)}`, () => {\n      castAndShouldFail(inst, value);\n    });\n  });\n};\n\nexport let validateAll = (\n  inst: ISchema<any>,\n  { valid = [], invalid = [] }: Options,\n) => {\n  describe('valid:', () => {\n    runValidations(valid, true);\n  });\n\n  describe('invalid:', () => {\n    runValidations(invalid, false);\n  });\n\n  function runValidations(arr: any[], isValid: boolean) {\n    arr.forEach((config) => {\n      let message = '',\n        value = config,\n        schema = inst;\n\n      if (Array.isArray(config)) [value, schema, message = ''] = config;\n\n      it(`${printValue(value)}${message && `  (${message})`}`, async () => {\n        await expect((schema as any).isValid(value)).resolves.toEqual(isValid);\n      });\n    });\n  }\n};\n\nexport function validationErrorWithMessages(...errors: any[]) {\n  return expect.objectContaining({\n    errors,\n  });\n}\n\nexport function ensureSync(fn: () => Promise<any>) {\n  let run = false;\n  let resolve = (t: any) => {\n    if (!run) return t;\n    throw new Error('Did not execute synchronously');\n  };\n  let err = (t: any) => {\n    if (!run) throw t;\n    throw new Error('Did not execute synchronously');\n  };\n\n  let result = fn().then(resolve, err);\n\n  run = true;\n  return result;\n}\n"
  },
  {
    "path": "test/lazy.ts",
    "content": "import { describe, it, expect, beforeEach, vi } from 'vitest';\nimport { lazy, object, mixed, ValidationError } from '../src';\n\ndescribe('lazy', function () {\n  it('should throw on a non-schema value', () => {\n    // @ts-expect-error testing incorrect usage\n    expect(() => lazy(() => undefined).validateSync(undefined)).toThrowError();\n  });\n\n  describe('mapper', () => {\n    const value = 1;\n    let mapper: any;\n\n    beforeEach(() => {\n      mapper = vi.fn(() => mixed());\n    });\n\n    it('should call with value', () => {\n      lazy(mapper).validate(value);\n      expect(mapper).toHaveBeenCalledWith(value, expect.any(Object));\n    });\n\n    it('should call with context', () => {\n      const context = {\n        a: 1,\n      };\n      let options = { context };\n      lazy(mapper).validate(value, options);\n      expect(mapper).toHaveBeenCalledWith(value, options);\n    });\n\n    it('should call with context when nested: #1799', () => {\n      let context = { a: 1 };\n      let value = { lazy: 1 };\n      let options = { context };\n\n      object({\n        lazy: lazy(mapper),\n      }).validate(value, options);\n\n      lazy(mapper).validate(value, options);\n      expect(mapper).toHaveBeenCalledWith(value, options);\n    });\n\n    it('should allow meta', () => {\n      const meta = { a: 1 };\n      const schema = lazy(mapper).meta(meta);\n\n      expect(schema.meta()).toEqual(meta);\n\n      expect(schema.meta({ added: true })).not.toEqual(schema.meta());\n\n      expect(schema.meta({ added: true }).meta()).toEqual({\n        a: 1,\n        added: true,\n      });\n    });\n\n    it('should allow throwing validation error in builder', async () => {\n      const schema = lazy(() => {\n        throw new ValidationError('oops');\n      });\n\n      await expect(schema.validate(value)).rejects.toThrowError('oops');\n      await expect(schema.isValid(value)).resolves.toEqual(false);\n\n      expect(() => schema.validateSync(value)).toThrowError('oops');\n\n      const schema2 = lazy(() => {\n        throw new Error('error');\n      });\n      // none validation errors are thrown sync to maintain back compat\n      expect(() => schema2.validate(value)).toThrowError('error');\n      expect(() => schema2.isValid(value)).toThrowError('error');\n    });\n  });\n});\n"
  },
  {
    "path": "test/mixed.ts",
    "content": "import { describe, it, expect, beforeEach, vi } from 'vitest';\nimport {\n  array,\n  bool,\n  lazy,\n  mixed,\n  number,\n  object,\n  reach,\n  ref,\n  Schema,\n  string,\n  tuple,\n  ValidationError,\n} from '../src';\nimport ObjectSchema from '../src/object';\nimport { ISchema } from '../src/types';\nimport { ensureSync, validateAll } from './helpers';\n\nlet noop = () => {};\n\n// @ts-ignore\nglobal.YUP_USE_SYNC &&\n  it('[internal] normal methods should be running in sync Mode', async () => {\n    let schema = number();\n\n    // test negative ensure case\n    await expect(ensureSync(() => Promise.resolve())).rejects.toThrowError(\n      'Did not execute synchronously',\n    );\n\n    // test positive case\n    await expect(ensureSync(() => schema.isValid(1))).resolves.toBe(true);\n\n    // ensure it fails with the correct message in sync mode\n    await expect(\n      ensureSync(() => schema.validate('john')),\n    ).rejects.toThrowError(\n      /the final value was: `NaN`.+cast from the value `\"john\"`/,\n    );\n  });\n\ndescribe('Mixed Types ', () => {\n  it('is not nullable by default', async () => {\n    let inst = mixed();\n\n    await expect(inst.isValid(null)).resolves.toBe(false);\n    await expect(inst.nullable().isValid(null)).resolves.toBe(true);\n  });\n\n  it('cast should return a default when undefined', () => {\n    let inst = mixed().default('hello');\n\n    expect(inst.cast(undefined)).toBe('hello');\n  });\n\n  it('getDefault should return the default value', function () {\n    let inst = string().default('hi');\n    expect(inst.getDefault({})).toBe('hi');\n    expect(inst.getDefault()).toBe('hi');\n  });\n\n  it('getDefault should return the default value using context', function () {\n    let inst = string().when('$foo', {\n      is: 'greet',\n      then: (s) => s.default('hi'),\n    });\n    expect(inst.getDefault({ context: { foo: 'greet' } })).toBe('hi');\n  });\n\n  it('should use provided check', async () => {\n    let schema = mixed((v): v is string => typeof v === 'string');\n\n    // @ts-expect-error narrowed type\n    schema.default(1);\n\n    expect(schema.isType(1)).toBe(false);\n    expect(schema.isType('foo')).toBe(true);\n\n    await expect(schema.validate(1)).rejects.toThrowError(\n      /this must match the configured type\\. The validated value was: `1`/,\n    );\n\n    schema = mixed({\n      type: 'string',\n      check: (v): v is string => typeof v === 'string',\n    });\n\n    // @ts-expect-error narrowed type\n    schema.default(1);\n\n    expect(schema.isType(1)).toBe(false);\n    expect(schema.isType('foo')).toBe(true);\n\n    await expect(schema.validate(1)).rejects.toThrowError(\n      /this must be a `string` type/,\n    );\n  });\n\n  it('should allow missing values with the \"ignore-optionality\" option', () => {\n    expect(\n      string().required().cast(null, { assert: 'ignore-optionality' }),\n    ).toBe(null);\n\n    expect(\n      string().required().cast(undefined, { assert: 'ignore-optionality' }),\n    ).toBe(undefined);\n  });\n\n  it('should warn about null types', async () => {\n    await expect(string().strict().validate(null)).rejects.toThrowError(\n      /this cannot be null/,\n    );\n  });\n\n  it('should validateAt', async () => {\n    const schema = object({\n      foo: array().of(\n        object({\n          loose: bool(),\n          bar: string().when('loose', {\n            is: true,\n            otherwise: (s) => s.strict(),\n          }),\n        }),\n      ),\n    });\n    const value = {\n      foo: [{ bar: 1 }, { bar: 1, loose: true }],\n    };\n\n    await expect(schema.validateAt('foo[1].bar', value)).resolves.toBeDefined();\n\n    await expect(schema.validateAt('foo[0].bar', value)).rejects.toThrowError(\n      /bar must be a `string` type/,\n    );\n  });\n\n  // xit('should castAt', async () => {\n  //   const schema = object({\n  //     foo: array().of(\n  //       object({\n  //         loose: bool().default(true),\n  //         bar: string(),\n  //       }),\n  //     ),\n  //   });\n  //   const value = {\n  //     foo: [{ bar: 1 }, { bar: 1, loose: true }],\n  //   };\n\n  //   schema.castAt('foo[1].bar', value).should.equal('1');\n\n  //   schema.castAt('foo[0].loose', value).should.equal(true);\n  // });\n\n  it('should print the original value', async () => {\n    await expect(number().validate('john')).rejects.toThrowError(\n      /the final value was: `NaN`.+cast from the value `\"john\"`/,\n    );\n  });\n\n  it('should allow function messages', async () => {\n    await expect(\n      string()\n        .label('My string')\n        .required((d) => `${d.label} is required`)\n        .validate(undefined),\n    ).rejects.toThrowError(/My string is required/);\n  });\n\n  it('should check types', async () => {\n    let inst = string().strict().typeError('must be a ${type}!');\n\n    await expect(inst.validate(5)).rejects.toEqual(\n      expect.objectContaining({\n        type: 'typeError',\n        message: 'must be a string!',\n        inner: [],\n      }),\n    );\n\n    await expect(inst.validate(5, { abortEarly: false })).rejects.toEqual(\n      expect.objectContaining({\n        type: undefined,\n        message: 'must be a string!',\n        inner: [expect.any(ValidationError)],\n      }),\n    );\n  });\n\n  it('should limit values', async () => {\n    let inst = mixed().oneOf([5, 'hello']);\n\n    await expect(inst.isValid(5)).resolves.toBe(true);\n    await expect(inst.isValid('hello')).resolves.toBe(true);\n\n    await expect(inst.validate(6)).rejects.toThrowError(\n      'this must be one of the following values: 5, hello',\n    );\n  });\n\n  it('should limit values with a ref', async () => {\n    let someValues = [1, 2, 3];\n    let context = { someValues };\n    let inst = mixed().oneOf([\n      ref('$someValues[0]'),\n      ref('$someValues[1]'),\n      ref('$someValues[2]'),\n    ]);\n    await expect(inst.validate(1, { context })).resolves.toBe(1);\n\n    await expect(inst.validate(4, { context })).rejects.toEqual(\n      expect.objectContaining({\n        type: 'oneOf',\n        params: expect.objectContaining({ resolved: someValues }),\n      }),\n    );\n  });\n\n  it('should not require field when notRequired was set', async () => {\n    let inst = mixed().required();\n\n    await expect(inst.isValid('test')).resolves.toBe(true);\n    await expect(inst.isValid(1)).resolves.toBe(true);\n\n    await expect(inst.validate(undefined)).rejects.toThrowError(\n      'this is a required field',\n    );\n\n    const next = inst.notRequired();\n\n    await expect(next.isValid(undefined)).resolves.toBe(true);\n  });\n\n  // @ts-ignore\n  global.YUP_USE_SYNC &&\n    describe('synchronous methods', () => {\n      it('should validate synchronously', async () => {\n        let schema = number();\n\n        expect(schema.isValidSync('john')).toBe(false);\n\n        expect(() => schema.validateSync('john')).toThrowError(\n          /the final value was: `NaN`.+cast from the value `\"john\"`/,\n        );\n      });\n\n      it('should isValid synchronously', async () => {\n        let schema = number();\n\n        expect(schema.isValidSync('john')).toBe(false);\n      });\n\n      it('should throw on async test', async () => {\n        let schema = mixed().test('test', 'foo', () => Promise.resolve(true));\n\n        await expect(\n          ensureSync(() => schema.validate('john')),\n        ).rejects.toThrowError(/Validation test of type: \"test\"/);\n      });\n    });\n\n  describe('oneOf', () => {\n    let inst = mixed().oneOf(['hello']);\n\n    validateAll(inst, {\n      valid: [undefined, 'hello', [null, inst.nullable()]],\n      invalid: [\n        'YOLO',\n        [undefined, inst.required(), 'required'],\n        // [null, inst.nullable()],\n        [null, inst.nullable().required(), 'required'],\n      ],\n    });\n\n    it('should work with refs', async () => {\n      let inst = object({\n        foo: string(),\n        bar: string().oneOf([ref('foo'), 'b']),\n      });\n\n      await expect(\n        inst.validate({ foo: 'a', bar: 'a' }),\n      ).resolves.toBeDefined();\n\n      await expect(\n        inst.validate({ foo: 'foo', bar: 'bar' }),\n      ).rejects.toThrowError();\n    });\n  });\n\n  describe('should exclude values', () => {\n    let inst = mixed().nullable().notOneOf([5, 'hello']);\n\n    validateAll(inst, {\n      valid: [6, 'hfhfh', [5, inst.oneOf([5]), '`oneOf` called after'], null],\n      invalid: [5, [null, inst.required(), 'required schema']],\n    });\n\n    it('should throw the correct error', async () => {\n      await expect(inst.validate(5)).rejects.toThrowError(\n        'this must not be one of the following values: 5, hello',\n      );\n    });\n  });\n\n  it('should run subset of validations first', async () => {\n    let called = false;\n    let inst = string()\n      .strict()\n      .test('test', 'boom', () => (called = true));\n\n    await expect(inst.validate(25)).rejects.toThrowError();\n\n    expect(called).toBe(false);\n  });\n\n  it('should respect strict', () => {\n    let inst = string().equals(['hello', '5']);\n\n    return Promise.all([\n      expect(inst.isValid(5)).resolves.toBe(true),\n      expect(inst.strict().isValid(5)).resolves.toBe(false),\n    ]);\n  });\n\n  it('should respect abortEarly', () => {\n    let inst = string().trim().min(10);\n\n    return Promise.all([\n      expect(inst.strict().validate(' hi ')).rejects.toThrowError(\n        /must be a trimmed string/,\n      ),\n\n      expect(\n        inst.strict().validate(' hi ', { abortEarly: false }),\n      ).rejects.toThrowError(/2 errors/),\n    ]);\n  });\n\n  it('should respect disableStackTrace', () => {\n    // let inst = string().trim();\n    // return Promise.all([\n    //   expect(inst.strict().validate(' hi ')).rejects.toHaveProperty('stack'),\n    //   expect(\n    //     inst.strict().validate(' hi ', { disableStackTrace: true }),\n    //   ).not.toHaveProperty('stack'),\n    // ]);\n  });\n\n  it('should overload test()', () => {\n    let inst = mixed().test('test', noop);\n\n    expect(inst.tests).toHaveLength(1);\n    expect(inst.tests[0]!.OPTIONS!.test).toBe(noop);\n    expect(inst.tests[0]!.OPTIONS!.message).toBe('${path} is invalid');\n  });\n\n  it('should fallback to default message', async () => {\n    let inst = mixed().test(() => false);\n\n    await expect(inst.validate('foo')).rejects.toThrowError('this is invalid');\n  });\n\n  it('should allow non string messages', async () => {\n    let message = { key: 'foo' };\n    let inst = mixed().test('test', message, () => false);\n\n    expect(inst.tests).toHaveLength(1);\n    expect(inst.tests[0]!.OPTIONS!.message).toBe(message);\n\n    let err = await inst.validate('foo').catch((err) => err);\n    expect(err.message).toEqual(message);\n  });\n\n  it('should dedupe tests with the same test function', () => {\n    let inst = mixed().test('test', ' ', noop).test('test', 'asdasd', noop);\n\n    expect(inst.tests).toHaveLength(1);\n    expect(inst.tests[0]!.OPTIONS!.message).toBe('asdasd');\n  });\n\n  it('should not dedupe tests with the same test function and different type', () => {\n    let inst = mixed().test('test', ' ', noop).test('test-two', 'asdasd', noop);\n\n    expect(inst.tests).toHaveLength(2);\n  });\n\n  it('should respect exclusive validation', () => {\n    let inst = mixed().test({\n      message: 'invalid',\n      exclusive: true,\n      name: 'test',\n      test: () => {},\n    });\n\n    //.test({ message: 'also invalid', name: 'test', test: () => {} });\n\n    expect(inst.tests).toHaveLength(1);\n\n    inst = mixed()\n      .test({ message: 'invalid', name: 'test', test: () => {} })\n      .test({ message: 'also invalid', name: 'test', test: () => {} });\n\n    expect(inst.tests).toHaveLength(2);\n  });\n\n  it('should non-exclusive tests should stack', () => {\n    let inst = mixed()\n      .test({ name: 'test', message: ' ', test: () => {} })\n      .test({ name: 'test', message: ' ', test: () => {} });\n\n    expect(inst.tests).toHaveLength(2);\n  });\n\n  it('should replace existing tests, with exclusive test ', () => {\n    let inst = mixed()\n      .test({ name: 'test', message: ' ', test: noop })\n      .test({ name: 'test', exclusive: true, message: ' ', test: noop });\n\n    expect(inst.tests).toHaveLength(1);\n  });\n\n  it('should replace existing exclusive tests, with non-exclusive', () => {\n    let inst = mixed()\n      .test({ name: 'test', exclusive: true, message: ' ', test: () => {} })\n      .test({ name: 'test', message: ' ', test: () => {} })\n      .test({ name: 'test', message: ' ', test: () => {} });\n\n    expect(inst.tests).toHaveLength(2);\n  });\n\n  it('exclusive tests should throw without a name', () => {\n    expect(() => {\n      mixed().test({ message: 'invalid', exclusive: true, test: noop });\n    }).toThrowError();\n  });\n\n  it('exclusive tests should replace previous ones', async () => {\n    let inst = mixed<number>().test({\n      message: 'invalid',\n      exclusive: true,\n      name: 'max',\n      test: (v) => v! < 5,\n    });\n\n    expect(await inst.isValid(8)).toBe(false);\n\n    expect(\n      await inst\n        .test({\n          message: 'invalid',\n          exclusive: true,\n          name: 'max',\n          test: (v) => v! < 10,\n        })\n        .isValid(8),\n    ).toBe(true);\n  });\n\n  it('tests should be called with the correct `this`', async () => {\n    let called = false;\n    let inst = object({\n      other: mixed(),\n      test: mixed().test({\n        message: 'invalid',\n        exclusive: true,\n        name: 'max',\n        test() {\n          expect(this.path).toBe('test');\n          expect(this.parent).toEqual({ other: 5, test: 'hi' });\n          expect(this.options.context).toEqual({ user: 'jason' });\n          called = true;\n          return true;\n        },\n      }),\n    });\n\n    await inst.validate(\n      { other: 5, test: 'hi' },\n      { context: { user: 'jason' } },\n    );\n\n    expect(called).toBe(true);\n  });\n\n  it('tests should be able to access nested parent', async () => {\n    let finalFrom: any, finalOptions: any;\n    let testFixture = {\n      firstField: 'test',\n      second: [\n        {\n          thirdField: 'test3',\n        },\n        {\n          thirdField: 'test4',\n        },\n      ],\n    };\n\n    let third = object({\n      thirdField: mixed().test({\n        test() {\n          finalFrom = this.from!;\n          finalOptions = this.options;\n          return true;\n        },\n      }),\n    });\n\n    let second = array().of(third);\n\n    let first = object({\n      firstField: mixed(),\n      second,\n    });\n\n    await first.validate(testFixture);\n\n    expect(finalFrom[0].value).toEqual(testFixture.second[finalOptions.index]);\n    expect(finalFrom[0].schema).toBe(third);\n    expect(finalFrom[1].value).toBe(testFixture);\n    expect(finalFrom[1].schema).toBe(first);\n  });\n\n  it('tests can return an error', () => {\n    let inst = mixed().test({\n      message: 'invalid ${path}',\n      name: 'max',\n      test() {\n        return this.createError({ path: 'my.path' });\n      },\n    });\n\n    return expect(inst.validate('')).rejects.toEqual(\n      expect.objectContaining({\n        path: 'my.path',\n        errors: ['invalid my.path'],\n      }),\n    );\n  });\n\n  it('should use returned error path and message', () => {\n    let inst = mixed().test({\n      message: 'invalid ${path}',\n      name: 'max',\n      test: function () {\n        return this.createError({ message: '${path} nope!', path: 'my.path' });\n      },\n    });\n\n    return expect(inst.validate({ other: 5, test: 'hi' })).rejects.toEqual(\n      expect.objectContaining({\n        path: 'my.path',\n        errors: ['my.path nope!'],\n      }),\n    );\n  });\n\n  it('should allow custom validation', async () => {\n    let inst = string().test('name', 'test a', (val) => val === 'jim');\n\n    return expect(inst.validate('joe')).rejects.toThrowError('test a');\n  });\n\n  // @ts-ignore\n  !global.YUP_USE_SYNC &&\n    it('should fail when the test function returns a rejected Promise', async () => {\n      let inst = string().test(() => {\n        return Promise.reject(new Error('oops an error occurred'));\n      });\n\n      return expect(inst.validate('joe')).rejects.toThrowError(\n        'oops an error occurred',\n      );\n    });\n\n  describe('withMutation', () => {\n    it('should pass the same instance to a provided function', () => {\n      let inst = mixed();\n      let func = vi.fn();\n\n      inst.withMutation(func);\n\n      expect(func).toHaveBeenCalledWith(inst);\n    });\n\n    it('should temporarily make mutable', () => {\n      let inst = mixed();\n\n      expect(inst.tests).toHaveLength(0);\n\n      inst.withMutation((inst) => {\n        inst.test('a', () => true);\n      });\n\n      expect(inst.tests).toHaveLength(1);\n    });\n\n    it('should return immutability', () => {\n      let inst = mixed();\n      inst.withMutation(() => {});\n\n      expect(inst.tests).toHaveLength(0);\n\n      inst.test('a', () => true);\n\n      expect(inst.tests).toHaveLength(0);\n    });\n\n    it('should work with nesting', () => {\n      let inst = mixed();\n\n      expect(inst.tests).toHaveLength(0);\n\n      inst.withMutation((inst) => {\n        inst.withMutation((inst) => {\n          inst.test('a', () => true);\n        });\n        inst.test('b', () => true);\n      });\n\n      expect(inst.tests).toHaveLength(2);\n    });\n  });\n\n  describe('concat', () => {\n    let next: ISchema<any>;\n    let inst = object({\n      str: string().required(),\n      obj: object({\n        str: string(),\n      }),\n    });\n\n    beforeEach(() => {\n      next = inst.concat(\n        object({\n          str: string().required().trim(),\n          str2: string().required(),\n          obj: object({\n            str: string().required(),\n          }),\n        }),\n      );\n    });\n\n    it('should have the correct number of tests', () => {\n      expect((reach(next, 'str') as Schema).tests).toHaveLength(2);\n    });\n\n    it('should have the tests in the correct order', () => {\n      expect((reach(next, 'str') as Schema).tests[0].OPTIONS?.name).toBe(\n        'required',\n      );\n    });\n\n    it('should validate correctly', async () => {\n      await expect(\n        inst.isValid({ str: 'hi', str2: 'hi', obj: {} }),\n      ).resolves.toBe(true);\n\n      await expect(\n        next.validate({ str: ' hi  ', str2: 'hi', obj: { str: 'hi' } }),\n      ).resolves.toEqual({\n        str: 'hi',\n        str2: 'hi',\n        obj: { str: 'hi' },\n      });\n    });\n\n    it('should throw the correct validation errors', async () => {\n      await expect(\n        next.validate({ str: 'hi', str2: 'hi', obj: {} }),\n      ).rejects.toThrowError('obj.str is a required field');\n\n      await expect(\n        next.validate({ str2: 'hi', obj: { str: 'hi' } }),\n      ).rejects.toThrowError('str is a required field');\n    });\n  });\n\n  it('concat should carry over transforms', async () => {\n    let inst = string().trim();\n\n    expect(inst.concat(string().min(4)).cast(' hello  ')).toBe('hello');\n\n    await expect(inst.concat(string().min(4)).isValid(' he  ')).resolves.toBe(\n      false,\n    );\n  });\n\n  it('concat should fail on different types', function () {\n    let inst = string().default('hi');\n\n    expect(function () {\n      // @ts-expect-error invalid combo\n      inst.concat(object());\n    }).toThrowError(TypeError);\n  });\n\n  it('concat should not overwrite label and meta with undefined', function () {\n    const testLabel = 'Test Label';\n    const testMeta = {\n      testField: 'test field',\n    };\n    let baseSchema = mixed().label(testLabel).meta(testMeta);\n    const otherSchema = mixed();\n\n    baseSchema = baseSchema.concat(otherSchema);\n    expect(baseSchema.spec.label).toBe(testLabel);\n    expect(baseSchema.spec.meta?.testField).toBe(testMeta.testField);\n  });\n\n  it('concat should allow mixed and other type', function () {\n    let inst = mixed().default('hi');\n\n    expect(function () {\n      expect(inst.concat(string()).type).toBe('string');\n    }).not.toThrowError(TypeError);\n  });\n\n  it('concat should validate with mixed and other type', async function () {\n    let inst = mixed().concat(number());\n\n    await expect(inst.validate([])).rejects.toThrowError(\n      /must be a `number` type/,\n    );\n  });\n\n  it('concat should maintain undefined defaults', function () {\n    let inst = string().default('hi');\n\n    expect(\n      inst.concat(string().default(undefined)).getDefault(),\n    ).toBeUndefined();\n  });\n\n  it('concat should preserve oneOf', async function () {\n    let inst = string().oneOf(['a']).concat(string().default('hi'));\n\n    await expect(inst.isValid('a')).resolves.toBe(true);\n  });\n\n  it('concat should override presence', async function () {\n    let inst = string().required().concat(string().nullable());\n\n    await expect(inst.isValid(undefined)).resolves.toBe(true);\n    await expect(inst.isValid(null)).resolves.toBe(true);\n  });\n\n  it('gives whitelist precedence to second in concat', async function () {\n    let inst = string()\n      .oneOf(['a', 'b', 'c'])\n      .concat(string().notOneOf(['b']));\n\n    await expect(inst.isValid('a')).resolves.toBe(true);\n    await expect(inst.isValid('b')).resolves.toBe(false);\n    await expect(inst.isValid('c')).resolves.toBe(true);\n  });\n\n  it('gives blacklist precedence to second in concat', async function () {\n    let inst = string()\n      .notOneOf(['a', 'b', 'c'])\n      .concat(string().oneOf(['b', 'c']));\n\n    await expect(inst.isValid('a')).resolves.toBe(false);\n    await expect(inst.isValid('b')).resolves.toBe(true);\n    await expect(inst.isValid('c')).resolves.toBe(true);\n  });\n\n  it('concats whitelist with refs', async function () {\n    let inst = object({\n      x: string().required(),\n      y: string()\n        .oneOf([ref('$x'), 'b', 'c'])\n        .concat(string().notOneOf(['c', ref('$x')])),\n    });\n\n    await expect(inst.isValid({ x: 'a', y: 'a' })).resolves.toBe(false);\n    await expect(inst.isValid({ x: 'a', y: 'b' })).resolves.toBe(true);\n    await expect(inst.isValid({ x: 'a', y: 'c' })).resolves.toBe(false);\n  });\n\n  it('defaults should be validated but not transformed', function () {\n    let inst = string().trim().default('  hi  ');\n\n    return expect(inst.validate(undefined)).rejects.toThrowError(\n      'this must be a trimmed string',\n    );\n  });\n\n  it('should handle conditionals', async function () {\n    let inst = mixed().when('prop', {\n      is: 5,\n      then: (s) => s.required('from parent'),\n    });\n\n    await expect(\n      inst.validate(undefined, { parent: { prop: 5 } } as any),\n    ).rejects.toThrowError();\n    await expect(\n      inst.validate(undefined, { parent: { prop: 1 } } as any),\n    ).resolves.toBeUndefined();\n    await expect(\n      inst.validate('hello', { parent: { prop: 5 } } as any),\n    ).resolves.toBeDefined();\n\n    const strInst = string().when('prop', {\n      is: 5,\n      then: (s) => s.required(),\n      otherwise: (s) => s.min(4),\n    });\n\n    await expect(\n      strInst.validate(undefined, { parent: { prop: 5 } } as any),\n    ).rejects.toThrowError();\n    await expect(\n      strInst.validate('hello', { parent: { prop: 1 } } as any),\n    ).resolves.toBeDefined();\n    await expect(\n      strInst.validate('hel', { parent: { prop: 1 } } as any),\n    ).rejects.toThrowError();\n  });\n\n  it('should handle multiple conditionals', function () {\n    let called = false;\n    let inst = mixed().when(['$prop', '$other'], ([prop, other], schema) => {\n      expect(other).toBe(true);\n      expect(prop).toBe(1);\n      called = true;\n\n      return schema;\n    });\n\n    inst.cast({}, { context: { prop: 1, other: true } });\n    expect(called).toBe(true);\n\n    inst = mixed().when(['$prop', '$other'], {\n      is: 5,\n      then: (s) => s.required(),\n    });\n\n    return expect(\n      inst.isValid(undefined, { context: { prop: 5, other: 5 } }),\n    ).resolves.toBe(false);\n  });\n\n  it('should require context when needed', async function () {\n    let inst = mixed().when('$prop', {\n      is: 5,\n      then: (s) => s.required('from context'),\n    });\n\n    await expect(\n      inst.validate(undefined, { context: { prop: 5 } }),\n    ).rejects.toThrowError();\n    await expect(\n      inst.validate(undefined, { context: { prop: 1 } }),\n    ).resolves.toBeUndefined();\n    await expect(\n      inst.validate('hello', { context: { prop: 5 } }),\n    ).resolves.toBeDefined();\n\n    const strInst = string().when('$prop', {\n      is: (val: any) => val === 5,\n      then: (s) => s.required(),\n      otherwise: (s) => s.min(4),\n    });\n\n    await expect(\n      strInst.validate(undefined, { context: { prop: 5 } }),\n    ).rejects.toThrowError();\n    await expect(\n      strInst.validate('hello', { context: { prop: 1 } }),\n    ).resolves.toBeDefined();\n    await expect(\n      strInst.validate('hel', { context: { prop: 1 } }),\n    ).rejects.toThrowError();\n  });\n\n  it('should not use context refs in object calculations', function () {\n    let inst = object({\n      prop: string().when('$prop', {\n        is: 5,\n        then: (s) => s.required('from context'),\n      }),\n    });\n\n    expect(inst.getDefault()).toEqual({ prop: undefined });\n  });\n\n  it('should support self references in conditions', async function () {\n    let inst = number().when('.', {\n      is: (value: number) => value > 0,\n      then: (s) => s.min(5),\n    });\n\n    await expect(inst.validate(4)).rejects.toThrowError(/must be greater/);\n\n    await expect(inst.validate(5)).resolves.toBeDefined();\n\n    await expect(inst.validate(-1)).resolves.toBeDefined();\n  });\n\n  it('should support conditional single argument as options shortcut', async function () {\n    let inst = number().when({\n      is: (value: number) => value > 0,\n      then: (s) => s.min(5),\n    });\n\n    await expect(inst.validate(4)).rejects.toThrowError(/must be greater/);\n\n    await expect(inst.validate(5)).resolves.toBeDefined();\n\n    await expect(inst.validate(-1)).resolves.toBeDefined();\n  });\n\n  it('should allow nested conditions and lazies', async function () {\n    let inst = string().when('$check', {\n      is: (value: any) => typeof value === 'string',\n      then: (s) =>\n        s.when('$check', {\n          is: (value: any) => /hello/.test(value),\n          then: () => lazy(() => string().min(6)),\n        }),\n    });\n\n    await expect(\n      inst.validate('pass', { context: { check: false } }),\n    ).resolves.toBeDefined();\n\n    await expect(\n      inst.validate('pass', { context: { check: 'hello' } }),\n    ).rejects.toThrowError(/must be at least/);\n\n    await expect(\n      inst.validate('passes', { context: { check: 'hello' } }),\n    ).resolves.toBeDefined();\n  });\n\n  it('should use label in error message', async function () {\n    let label = 'Label';\n    let inst = object({\n      prop: string().required().label(label),\n    });\n\n    await expect(inst.validate({})).rejects.toThrowError(\n      `${label} is a required field`,\n    );\n  });\n\n  it('should add meta() data', () => {\n    expect(string().meta({ input: 'foo' }).meta({ foo: 'bar' }).meta()).toEqual(\n      {\n        input: 'foo',\n        foo: 'bar',\n      },\n    );\n  });\n\n  describe('schema.describe()', () => {\n    let schema: ObjectSchema<any>;\n    beforeEach(() => {\n      schema = object({\n        lazy: lazy(() => string().nullable()),\n        foo: array(number().integer()).required(),\n        bar: string()\n          .max(2)\n          .default(() => 'a')\n          .meta({ input: 'foo' })\n          .label('str!')\n          .oneOf(['a', 'b'])\n          .notOneOf([ref('foo')])\n          .when('lazy', {\n            is: 'entered',\n            then: (s) => s.defined(),\n          }),\n        baz: tuple([string(), number()]),\n      }).when(['dummy'], (_, s) => {\n        return s.shape({\n          when: string(),\n        });\n      });\n    });\n\n    it('should describe', () => {\n      expect(schema.describe()).toEqual({\n        type: 'object',\n        meta: undefined,\n        label: undefined,\n        default: {\n          foo: undefined,\n          bar: 'a',\n          lazy: undefined,\n          baz: undefined,\n        },\n        nullable: false,\n        optional: true,\n        tests: [],\n        oneOf: [],\n        notOneOf: [],\n        fields: {\n          lazy: {\n            type: 'lazy',\n            meta: undefined,\n            label: undefined,\n            default: undefined,\n          },\n          foo: {\n            type: 'array',\n            meta: undefined,\n            label: undefined,\n            default: undefined,\n            nullable: false,\n            optional: false,\n            tests: [],\n            oneOf: [],\n            notOneOf: [],\n            innerType: {\n              type: 'number',\n              meta: undefined,\n              label: undefined,\n              default: undefined,\n              nullable: false,\n              optional: true,\n              oneOf: [],\n              notOneOf: [],\n              tests: [\n                {\n                  name: 'integer',\n                  params: undefined,\n                },\n              ],\n            },\n          },\n          bar: {\n            type: 'string',\n            label: 'str!',\n            default: 'a',\n            tests: [{ name: 'max', params: { max: 2 } }],\n            meta: {\n              input: 'foo',\n            },\n            nullable: false,\n            optional: true,\n            oneOf: ['a', 'b'],\n            notOneOf: [\n              {\n                type: 'ref',\n                key: 'foo',\n              },\n            ],\n          },\n          baz: {\n            type: 'tuple',\n            meta: undefined,\n            label: undefined,\n            default: undefined,\n            nullable: false,\n            optional: true,\n            tests: [],\n            oneOf: [],\n            notOneOf: [],\n            innerType: [\n              {\n                type: 'string',\n                meta: undefined,\n                label: undefined,\n                default: undefined,\n                nullable: false,\n                optional: true,\n                oneOf: [],\n                notOneOf: [],\n                tests: [],\n              },\n              {\n                type: 'number',\n                meta: undefined,\n                label: undefined,\n                default: undefined,\n                nullable: false,\n                optional: true,\n                oneOf: [],\n                notOneOf: [],\n                tests: [],\n              },\n            ],\n          },\n        },\n      });\n    });\n\n    it('should describe with options', () => {\n      expect(schema.describe({ value: { lazy: 'entered' } })).toEqual({\n        type: 'object',\n        meta: undefined,\n        label: undefined,\n        default: {\n          foo: undefined,\n          bar: 'a',\n          lazy: undefined,\n          baz: undefined,\n          when: undefined,\n        },\n        nullable: false,\n        optional: true,\n        tests: [],\n        oneOf: [],\n        notOneOf: [],\n        fields: {\n          lazy: {\n            type: 'string',\n            meta: undefined,\n            label: undefined,\n            default: undefined,\n            nullable: true,\n            optional: true,\n            oneOf: [],\n            notOneOf: [],\n            tests: [],\n          },\n          foo: {\n            type: 'array',\n            meta: undefined,\n            label: undefined,\n            default: undefined,\n            nullable: false,\n            optional: false,\n            tests: [],\n            oneOf: [],\n            notOneOf: [],\n            innerType: {\n              type: 'number',\n              meta: undefined,\n              label: undefined,\n              default: undefined,\n              nullable: false,\n              optional: true,\n              oneOf: [],\n              notOneOf: [],\n              tests: [\n                {\n                  name: 'integer',\n                  params: undefined,\n                },\n              ],\n            },\n          },\n          bar: {\n            type: 'string',\n            label: 'str!',\n            default: 'a',\n            tests: [{ name: 'max', params: { max: 2 } }],\n            meta: {\n              input: 'foo',\n            },\n            nullable: false,\n            optional: false,\n            oneOf: ['a', 'b'],\n            notOneOf: [\n              {\n                type: 'ref',\n                key: 'foo',\n              },\n            ],\n          },\n          baz: {\n            type: 'tuple',\n            meta: undefined,\n            label: undefined,\n            default: undefined,\n            nullable: false,\n            optional: true,\n            tests: [],\n            oneOf: [],\n            notOneOf: [],\n            innerType: [\n              {\n                type: 'string',\n                meta: undefined,\n                label: undefined,\n                default: undefined,\n                nullable: false,\n                optional: true,\n                oneOf: [],\n                notOneOf: [],\n                tests: [],\n              },\n              {\n                type: 'number',\n                meta: undefined,\n                label: undefined,\n                default: undefined,\n                nullable: false,\n                optional: true,\n                oneOf: [],\n                notOneOf: [],\n                tests: [],\n              },\n            ],\n          },\n          when: {\n            type: 'string',\n            meta: undefined,\n            label: undefined,\n            default: undefined,\n            notOneOf: [],\n            nullable: false,\n            oneOf: [],\n            optional: true,\n            tests: [],\n          },\n        },\n      });\n    });\n  });\n\n  describe('defined', () => {\n    it('should fail when value is undefined', async () => {\n      let inst = object({\n        prop: string().defined(),\n      });\n\n      await expect(inst.validate({})).rejects.toThrowError(\n        'prop must be defined',\n      );\n    });\n\n    it('should pass when value is null', async () => {\n      let inst = object({\n        prop: string().nullable().defined(),\n      });\n\n      await expect(inst.isValid({ prop: null })).resolves.toBe(true);\n    });\n\n    it('should pass when value is not undefined', async () => {\n      let inst = object({\n        prop: string().defined(),\n      });\n\n      await expect(inst.isValid({ prop: 'prop value' })).resolves.toBe(true);\n    });\n  });\n\n  describe('description options', () => {\n    const schema = object({\n      name: string(),\n      type: bool(),\n      fancy: string()\n        .label('bad label')\n        .when('type', {\n          is: true,\n          then: (schema) => schema.required().label('good label'),\n          otherwise: (schema) => schema.label('default label'),\n        }),\n    });\n\n    it('should pass options', async () => {\n      expect(\n        // @ts-ignore\n        schema.fields.fancy.describe({ parent: { type: true } }).label,\n      ).toBe('good label');\n      expect(\n        // @ts-ignore\n        schema.fields.fancy.describe({ parent: { type: true } }).optional,\n      ).toBe(false);\n\n      expect(\n        // @ts-ignore\n        schema.fields.fancy.describe({ parent: { type: false } }).label,\n      ).toEqual('default label');\n      expect(\n        // @ts-ignore\n        schema.fields.fancy.describe({ parent: { type: false } }).optional,\n      ).toBe(true);\n    });\n  });\n});\n"
  },
  {
    "path": "test/number.ts",
    "content": "import { describe, it, expect } from 'vitest';\nimport * as TestHelpers from './helpers';\n\nimport { number, NumberSchema, object, ref } from '../src';\n\ndescribe('Number types', function () {\n  it('is extensible', () => {\n    class MyNumber extends NumberSchema {\n      foo() {\n        return this;\n      }\n    }\n\n    new MyNumber().foo().integer().required();\n  });\n\n  describe('casting', () => {\n    let schema = number();\n\n    TestHelpers.castAll(schema, {\n      valid: [\n        ['5', 5],\n        [3, 3],\n        //[new Number(5), 5],\n        [' 5.656 ', 5.656],\n      ],\n      invalid: ['', false, true, new Date(), new Number('foo')],\n    });\n\n    it('should round', () => {\n      // @ts-expect-error stricter type than accepted\n      expect(schema.round('ceIl').cast(45.1111)).toBe(46);\n\n      expect(schema.round().cast(45.444444)).toBe(45);\n\n      expect(schema.nullable().integer().round().cast(null)).toBeNull();\n      expect(function () {\n        // @ts-expect-error testing incorrectness\n        schema.round('fasf');\n      }).toThrowError(TypeError);\n    });\n\n    it('should truncate', () => {\n      expect(schema.truncate().cast(45.55)).toBe(45);\n    });\n\n    it('should return NaN for failed casts', () => {\n      expect(number().cast('asfasf', { assert: false })).toEqual(NaN);\n\n      expect(number().cast(new Date(), { assert: false })).toEqual(NaN);\n      expect(number().cast(null, { assert: false })).toEqual(null);\n    });\n  });\n\n  it('should handle DEFAULT', function () {\n    let inst = number().default(0);\n\n    expect(inst.getDefault()).toBe(0);\n    expect(inst.default(5).required().getDefault()).toBe(5);\n  });\n\n  it('should type check', function () {\n    let inst = number();\n\n    expect(inst.isType(5)).toBe(true);\n    expect(inst.isType(new Number(5))).toBe(true);\n    expect(inst.isType(new Number('foo'))).toBe(false);\n    expect(inst.isType(false)).toBe(false);\n    expect(inst.isType(null)).toBe(false);\n    expect(inst.isType(NaN)).toBe(false);\n    expect(inst.nullable().isType(null)).toBe(true);\n  });\n\n  it('should VALIDATE correctly', function () {\n    let inst = number().min(4);\n\n    return Promise.all([\n      expect(number().isValid(null)).resolves.toBe(false),\n      expect(number().nullable().isValid(null)).resolves.toBe(true),\n      expect(number().isValid(' ')).resolves.toBe(false),\n      expect(number().isValid('12abc')).resolves.toBe(false),\n      expect(number().isValid(0xff)).resolves.toBe(true),\n      expect(number().isValid('0xff')).resolves.toBe(true),\n\n      expect(inst.isValid(5)).resolves.toBe(true),\n      expect(inst.isValid(2)).resolves.toBe(false),\n\n      expect(inst.required().validate(undefined)).rejects.toEqual(\n        TestHelpers.validationErrorWithMessages(\n          expect.stringContaining('required'),\n        ),\n      ),\n      expect(inst.validate(null)).rejects.toEqual(\n        TestHelpers.validationErrorWithMessages(\n          expect.stringContaining('cannot be null'),\n        ),\n      ),\n      expect(inst.validate({})).rejects.toEqual(\n        TestHelpers.validationErrorWithMessages(\n          expect.stringContaining('must be a `number` type'),\n        ),\n      ),\n    ]);\n  });\n\n  describe('min', () => {\n    let schema = number().min(5);\n\n    TestHelpers.validateAll(schema, {\n      valid: [7, 35738787838, [null, schema.nullable()]],\n      invalid: [2, null, [14, schema.min(10).min(15)]],\n    });\n  });\n\n  describe('max', () => {\n    let schema = number().max(5);\n\n    TestHelpers.validateAll(schema, {\n      valid: [4, -5222, [null, schema.nullable()]],\n      invalid: [10, null, [16, schema.max(20).max(15)]],\n    });\n  });\n\n  describe('lessThan', () => {\n    let schema = number().lessThan(5);\n\n    TestHelpers.validateAll(schema, {\n      valid: [4, -10, [null, schema.nullable()]],\n      invalid: [5, 7, null, [14, schema.lessThan(10).lessThan(14)]],\n    });\n\n    it('should return default message', async () => {\n      await expect(schema.validate(6)).rejects.toEqual(\n        TestHelpers.validationErrorWithMessages('this must be less than 5'),\n      );\n    });\n  });\n\n  describe('moreThan', () => {\n    let schema = number().moreThan(5);\n\n    TestHelpers.validateAll(schema, {\n      valid: [6, 56445435, [null, schema.nullable()]],\n      invalid: [5, -10, null, [64, schema.moreThan(52).moreThan(74)]],\n    });\n\n    it('should return default message', async () => {\n      await expect(schema.validate(4)).rejects.toEqual(\n        TestHelpers.validationErrorWithMessages(\n          expect.stringContaining('this must be greater than 5'),\n        ),\n      );\n    });\n  });\n\n  describe('integer', () => {\n    let schema = number().integer();\n\n    TestHelpers.validateAll(schema, {\n      valid: [4, -5222, 3.12312e51],\n      invalid: [10.53, 0.1 * 0.2, -34512535.626, new Date()],\n    });\n\n    it('should return default message', async () => {\n      await expect(schema.validate(10.53)).rejects.toEqual(\n        TestHelpers.validationErrorWithMessages('this must be an integer'),\n      );\n    });\n  });\n\n  it('should check POSITIVE correctly', function () {\n    let v = number().positive();\n\n    return Promise.all([\n      expect(v.isValid(7)).resolves.toBe(true),\n\n      expect(v.isValid(0)).resolves.toBe(false),\n\n      expect(v.validate(0)).rejects.toEqual(\n        TestHelpers.validationErrorWithMessages(\n          'this must be a positive number',\n        ),\n      ),\n    ]);\n  });\n\n  it('should check NEGATIVE correctly', function () {\n    let v = number().negative();\n\n    return Promise.all([\n      expect(v.isValid(-4)).resolves.toBe(true),\n\n      expect(v.isValid(0)).resolves.toBe(false),\n\n      expect(v.validate(10)).rejects.toEqual(\n        TestHelpers.validationErrorWithMessages(\n          'this must be a negative number',\n        ),\n      ),\n    ]);\n  });\n\n  it('should resolve param refs when describing', () => {\n    let schema = number().min(ref('$foo'));\n\n    expect(schema.describe({ value: 10, context: { foo: 5 } })).toEqual(\n      expect.objectContaining({\n        tests: [\n          expect.objectContaining({\n            params: {\n              min: 5,\n            },\n          }),\n        ],\n      }),\n    );\n\n    let schema2 = object({\n      x: number().min(0),\n      y: number().min(ref('x')),\n    }).required();\n\n    expect(\n      schema2.describe({ value: { x: 10 }, context: { foo: 5 } }).fields.y,\n    ).toEqual(\n      expect.objectContaining({\n        tests: [\n          expect.objectContaining({\n            params: {\n              min: 10,\n            },\n          }),\n        ],\n      }),\n    );\n  });\n});\n"
  },
  {
    "path": "test/object.ts",
    "content": "import { describe, it, expect, beforeEach, vi } from 'vitest';\nimport {\n  mixed,\n  string,\n  date,\n  number,\n  bool,\n  array,\n  object,\n  ref,\n  lazy,\n  reach,\n  StringSchema,\n  MixedSchema,\n} from '../src';\nimport ObjectSchema from '../src/object';\nimport { AnyObject } from '../src/types';\nimport { validationErrorWithMessages } from './helpers';\n\ndescribe('Object types', () => {\n  describe('casting', () => {\n    let createInst = () =>\n      object({\n        num: number(),\n        str: string(),\n        arr: array().of(number()),\n        dte: date(),\n        nested: object().shape({ str: string() }),\n        arrNested: array().of(object().shape({ num: number() })),\n        stripped: string().strip(),\n      });\n\n    let inst: ReturnType<typeof createInst>;\n\n    beforeEach(() => {\n      inst = createInst();\n    });\n\n    it('should parse json strings', () => {\n      expect(\n        object({ hello: number() }).json().cast('{ \"hello\": \"5\" }'),\n      ).toEqual({\n        hello: 5,\n      });\n    });\n\n    it('should return input for failed casts', () => {\n      expect(object().cast('dfhdfh', { assert: false })).toBe('dfhdfh');\n    });\n\n    it('should recursively cast fields', () => {\n      let obj = {\n        num: '5',\n        str: 'hello',\n        arr: ['4', 5],\n        dte: '2014-09-23T19:25:25Z',\n        nested: { str: 5 },\n        arrNested: [{ num: 5 }, { num: '5' }],\n      };\n\n      const cast = inst.cast(obj);\n\n      expect(cast).toEqual({\n        num: 5,\n        str: 'hello',\n        arr: [4, 5],\n        dte: new Date(1411500325000),\n        nested: { str: '5' },\n        arrNested: [{ num: 5 }, { num: 5 }],\n      });\n\n      expect(cast.arrNested![0]).toBe(obj.arrNested[0]);\n    });\n\n    it('should return the same object if all props are already cast', () => {\n      let obj = {\n        num: 5,\n        str: 'hello',\n        arr: [4, 5],\n        dte: new Date(1411500325000),\n        nested: { str: '5' },\n        arrNested: [{ num: 5 }, { num: 5 }],\n      };\n\n      expect(inst.cast(obj)).toBe(obj);\n    });\n  });\n\n  describe('validation', () => {\n    it('should run validations recursively', async () => {\n      let inst = object({\n        num: number(),\n        str: string(),\n        arr: array().of(number()),\n        dte: date(),\n        nested: object().shape({ str: string().strict() }),\n        arrNested: array().of(object().shape({ num: number() })),\n        stripped: string().strip(),\n      });\n\n      let obj: AnyObject = {\n        num: '4',\n        str: 'hello',\n        arr: ['4', 5, 6],\n        dte: '2014-09-23T19:25:25Z',\n        nested: { str: 5 },\n        arrNested: [{ num: 5 }, { num: '2' }],\n      };\n\n      await expect(inst.isValid(undefined)).resolves.toBe(true);\n\n      await expect(inst.validate(obj)).rejects.toEqual(\n        validationErrorWithMessages(expect.stringContaining('nested.str')),\n      );\n\n      obj.nested.str = 'hello';\n      obj.arrNested[1] = 8;\n\n      await expect(inst.validate(obj)).rejects.toEqual(\n        validationErrorWithMessages(expect.stringContaining('arrNested[1]')),\n      );\n    });\n\n    it('should prevent recursive casting', async () => {\n      let castSpy = vi.spyOn(StringSchema.prototype, '_cast' as any);\n\n      let inst = object({\n        field: string(),\n      });\n\n      let value = await inst.validate({ field: 5 });\n\n      expect(value.field).toBe('5');\n\n      expect(castSpy).toHaveBeenCalledTimes(1);\n\n      castSpy.mockRestore();\n    });\n\n    it('should respect strict for nested values', async () => {\n      let inst = object({\n        field: string(),\n      }).strict();\n\n      await expect(inst.validate({ field: 5 })).rejects.toThrowError(\n        /must be a `string` type/,\n      );\n    });\n\n    it('should respect strict for nested object values', async () => {\n      let inst = object({\n        obj: object({\n          field: string().strict(),\n        }),\n      });\n\n      await expect(inst.validate({ obj: { field: 5 } })).rejects.toThrowError(\n        /must be a `string` type/,\n      );\n    });\n\n    it('should respect child schema with strict()', async () => {\n      let inst = object({\n        field: number().strict(),\n      });\n\n      await expect(inst.validate({ field: '5' })).rejects.toThrowError(\n        /must be a `number` type/,\n      );\n\n      expect(inst.cast({ field: '5' })).toEqual({ field: 5 });\n\n      await expect(\n        object({\n          port: number().strict().integer(),\n        }).validate({ port: 'asdad' }),\n      ).rejects.toThrowError();\n    });\n\n    it('should handle custom validation', async () => {\n      let inst = object()\n        .shape({\n          prop: mixed(),\n          other: mixed(),\n        })\n        .test('test', '${path} oops', () => false);\n\n      await expect(inst.validate({})).rejects.toThrowError('this oops');\n    });\n\n    it('should not clone during validating', async function () {\n      let inst = object({\n        num: number(),\n        str: string(),\n        arr: array().of(number()),\n        dte: date(),\n        nested: object().shape({ str: string() }),\n        arrNested: array().of(object().shape({ num: number() })),\n        stripped: string().strip(),\n      });\n\n      let base = MixedSchema.prototype.clone;\n\n      MixedSchema.prototype.clone = function (...args) {\n        // @ts-expect-error private property\n        if (!this._mutate) throw new Error('should not call clone');\n\n        return base.apply(this, args);\n      };\n\n      try {\n        await inst.validate({\n          nested: { str: 'jimmm' },\n          arrNested: [{ num: 5 }, { num: '2' }],\n        });\n        await inst.validate({\n          nested: { str: 5 },\n          arrNested: [{ num: 5 }, { num: '2' }],\n        });\n      } catch (err) {\n        /* ignore */\n      } finally {\n        //eslint-disable-line\n        MixedSchema.prototype.clone = base;\n      }\n    });\n  });\n\n  it('should pass options to children', function () {\n    expect(\n      object({\n        names: object({\n          first: string(),\n        }),\n      }).cast(\n        {\n          extra: true,\n          names: { first: 'john', extra: true },\n        },\n        { stripUnknown: true },\n      ),\n    ).toEqual({\n      names: {\n        first: 'john',\n      },\n    });\n  });\n\n  it('should call shape with constructed with an arg', () => {\n    let inst = object({\n      prop: mixed(),\n    });\n\n    expect(inst.fields.prop).toBeDefined();\n  });\n\n  describe('stripUnknown', () => {\n    it('should remove extra fields', () => {\n      const inst = object({\n        str: string(),\n      });\n\n      expect(\n        inst.cast(\n          { str: 'hi', extra: false, sneaky: undefined },\n          { stripUnknown: true },\n        ),\n      ).toStrictEqual({\n        str: 'hi',\n      });\n    });\n\n    it('should one undefined extra fields', () => {\n      const inst = object({\n        str: string(),\n      });\n\n      expect(\n        inst.cast({ str: 'hi', sneaky: undefined }, { stripUnknown: true }),\n      ).toStrictEqual({\n        str: 'hi',\n      });\n    });\n  });\n\n  describe('object defaults', () => {\n    const createSchema = () =>\n      object({\n        nest: object({\n          str: string().default('hi'),\n        }),\n      });\n\n    let objSchema: ReturnType<typeof createSchema>;\n\n    beforeEach(() => {\n      objSchema = createSchema();\n    });\n\n    it('should expand objects by default', () => {\n      expect(objSchema.getDefault()).toEqual({\n        nest: { str: 'hi' },\n      });\n    });\n\n    it('should accept a user provided default', () => {\n      let schema = objSchema.default({ boom: 'hi' });\n\n      expect(schema.getDefault()).toEqual({\n        boom: 'hi',\n      });\n    });\n\n    it('should add empty keys when sub schema has no default', () => {\n      expect(\n        object({\n          str: string(),\n          nest: object({ str: string() }),\n        }).getDefault(),\n      ).toEqual({\n        nest: { str: undefined },\n        str: undefined,\n      });\n    });\n\n    it('should create defaults for missing object fields', () => {\n      expect(\n        object({\n          prop: mixed(),\n          other: object({\n            x: object({ b: string() }),\n          }),\n        }).cast({ prop: 'foo' }),\n      ).toEqual({\n        prop: 'foo',\n        other: { x: { b: undefined } },\n      });\n    });\n\n    it('should propagate context', () => {\n      const objectWithConditions = object({\n        child: string().when('$variable', {\n          is: 'foo',\n          then: (s) => s.default('is foo'),\n          otherwise: (s) => s.default('not foo'),\n        }),\n      });\n\n      expect(\n        objectWithConditions.getDefault({ context: { variable: 'foo' } }),\n      ).toEqual({ child: 'is foo' });\n\n      expect(\n        objectWithConditions.getDefault({\n          context: { variable: 'somethingElse' },\n        }),\n      ).toEqual({ child: 'not foo' });\n\n      expect(objectWithConditions.getDefault()).toEqual({ child: 'not foo' });\n    });\n\n    it('should respect options when casting to default', () => {\n      const objectWithConditions = object({\n        child: string().when('$variable', {\n          is: 'foo',\n          then: (s) => s.default('is foo'),\n          otherwise: (s) => s.default('not foo'),\n        }),\n      });\n\n      expect(\n        objectWithConditions.cast(undefined, { context: { variable: 'foo' } }),\n      ).toEqual({ child: 'is foo' });\n\n      expect(\n        objectWithConditions.cast(undefined, {\n          context: { variable: 'somethingElse' },\n        }),\n      ).toEqual({ child: 'not foo' });\n\n      expect(objectWithConditions.cast(undefined)).toEqual({\n        child: 'not foo',\n      });\n    });\n  });\n\n  it('should handle empty keys', () => {\n    let inst = object().shape({\n      prop: mixed(),\n    });\n\n    return Promise.all([\n      expect(inst.isValid({})).resolves.toBe(true),\n\n      expect(\n        inst.shape({ prop: mixed().required() }).isValid({}),\n      ).resolves.toBe(false),\n    ]);\n  });\n\n  it('should work with noUnknown', () => {\n    let inst = object().shape({\n      prop: mixed(),\n      other: mixed(),\n    });\n\n    return Promise.all([\n      expect(\n        inst.noUnknown('hi').validate({ extra: 'field' }, { strict: true }),\n      ).rejects.toThrowError('hi'),\n\n      expect(\n        inst.noUnknown().validate({ extra: 'field' }, { strict: true }),\n      ).rejects.toThrowError(/extra/),\n    ]);\n  });\n\n  it('should work with noUnknown override', async () => {\n    let inst = object()\n      .shape({\n        prop: mixed(),\n      })\n      .noUnknown()\n      .noUnknown(false);\n\n    await expect(inst.validate({ extra: 'field' })).resolves.toEqual({\n      extra: 'field',\n    });\n  });\n\n  it('should work with exact', async () => {\n    let inst = object()\n      .shape({\n        prop: mixed(),\n      })\n      .exact();\n\n    await expect(inst.validate({ extra: 'field' })).rejects.toThrowError(\n      'this object contains unknown properties: extra',\n    );\n  });\n\n  it('should strip specific fields', () => {\n    let inst = object().shape({\n      prop: mixed().strip(false),\n      other: mixed().strip(),\n    });\n\n    expect(inst.cast({ other: 'boo', prop: 'bar' })).toEqual({\n      prop: 'bar',\n    });\n  });\n\n  it('should handle field striping with `when`', () => {\n    let inst = object().shape({\n      other: bool(),\n      prop: mixed().when('other', {\n        is: true,\n        then: (s) => s.strip(),\n      }),\n    });\n\n    expect(inst.cast({ other: true, prop: 'bar' })).toEqual({\n      other: true,\n    });\n  });\n\n  it('should allow refs', async function () {\n    let schema = object({\n      quz: ref('baz'),\n      baz: ref('foo.bar'),\n      foo: object({\n        bar: string(),\n      }),\n      x: ref('$x'),\n    });\n\n    let value = await schema.validate(\n      {\n        foo: { bar: 'boom' },\n      },\n      { context: { x: 5 } },\n    );\n\n    //console.log(value)\n    expect(value).toEqual({\n      foo: {\n        bar: 'boom',\n      },\n      baz: 'boom',\n      quz: 'boom',\n      x: 5,\n    });\n  });\n\n  it('should allow refs with abortEarly false', async () => {\n    let schema = object().shape({\n      field: string(),\n      dupField: ref('field'),\n    });\n\n    await expect(\n      schema.validate(\n        {\n          field: 'test',\n        },\n        { abortEarly: false },\n      ),\n    ).resolves.toEqual({ field: 'test', dupField: 'test' });\n  });\n\n  describe('lazy evaluation', () => {\n    let types = {\n      string: string(),\n      number: number(),\n    };\n\n    it('should be cast-able', () => {\n      let inst = lazy(() => number());\n\n      expect(inst.cast).toBeInstanceOf(Function);\n      expect(inst.cast('4')).toBe(4);\n    });\n\n    it('should be validatable', async () => {\n      let inst = lazy(() => string().trim('trim me!').strict());\n\n      expect(inst.validate).toBeInstanceOf(Function);\n\n      try {\n        await inst.validate('  john  ');\n      } catch (err: any) {\n        expect(err.message).toBe('trim me!');\n      }\n    });\n\n    it('should resolve to schema', () => {\n      type Nested = {\n        nested: Nested;\n        x: {\n          y: Nested;\n        };\n      };\n      let inst: ObjectSchema<Nested> = object({\n        nested: lazy(() => inst),\n        x: object({\n          y: lazy(() => inst),\n        }),\n      });\n\n      expect(reach(inst, 'nested').resolve({})).toBe(inst);\n      expect(reach(inst, 'x.y').resolve({})).toBe(inst);\n    });\n\n    it('should be passed the value', () => {\n      let passed = false;\n      let inst = object({\n        nested: lazy((value) => {\n          expect(value).toBe('foo');\n          passed = true;\n          return string();\n        }),\n      });\n\n      inst.cast({ nested: 'foo' });\n      expect(passed).toBe(true);\n    });\n\n    it('should be passed the options', () => {\n      let opts = {};\n      let passed = false;\n      let inst = lazy((_, options) => {\n        expect(options).toBe(opts);\n        passed = true;\n        return object();\n      });\n\n      inst.cast({ nested: 'foo' }, opts);\n      expect(passed).toBe(true);\n    });\n\n    it('should always return a schema', () => {\n      // @ts-expect-error Incorrect usage\n      expect(() => lazy(() => {}).cast()).toThrowError(\n        /must return a valid schema/,\n      );\n    });\n\n    it('should set the correct path', async () => {\n      type Nested = {\n        str: string | null;\n        nested: Nested;\n      };\n\n      let inst: ObjectSchema<Nested> = object({\n        str: string().required().nullable(),\n        nested: lazy(() => inst.default(undefined)),\n      });\n\n      let value = {\n        nested: { str: null },\n        str: 'foo',\n      };\n\n      try {\n        await inst.validate(value, { strict: true });\n      } catch (err: any) {\n        expect(err.path).toBe('nested.str');\n        expect(err.message).toMatch(/required/);\n      }\n    });\n\n    it('should set the correct path with dotted keys', async () => {\n      let inst: ObjectSchema<any> = object({\n        'dotted.str': string().required().nullable(),\n        nested: lazy(() => inst.default(undefined)),\n      });\n\n      let value = {\n        nested: { 'dotted.str': null },\n        'dotted.str': 'foo',\n      };\n\n      try {\n        await inst.validate(value, { strict: true });\n      } catch (err: any) {\n        expect(err.path).toBe('nested[\"dotted.str\"]');\n        expect(err.message).toMatch(/required/);\n      }\n    });\n\n    it('should resolve array sub types', async () => {\n      let inst: ObjectSchema<any> = object({\n        str: string().required().nullable(),\n        nested: array().of(lazy(() => inst.default(undefined))),\n      });\n\n      let value = {\n        nested: [{ str: null }],\n        str: 'foo',\n      };\n\n      try {\n        await inst.validate(value, { strict: true });\n      } catch (err: any) {\n        expect(err.path).toBe('nested[0].str');\n        expect(err.message).toMatch(/required/);\n      }\n    });\n\n    it('should resolve for each array item', async () => {\n      let inst = array().of(\n        lazy((value: string | number) => (types as any)[typeof value]),\n      );\n\n      let val = await inst.validate(['john', 4], { strict: true });\n\n      expect(val).toEqual(['john', 4]);\n    });\n  });\n\n  it('should respect abortEarly', async () => {\n    let inst = object({\n      nest: object({\n        str: string().required(),\n      }).test('name', 'oops', () => false),\n    });\n\n    return Promise.all([\n      expect(inst.validate({ nest: { str: '' } })).rejects.toEqual(\n        expect.objectContaining({\n          value: { nest: { str: '' } },\n          // path: 'nest',\n          errors: ['oops'],\n        }),\n      ),\n\n      expect(\n        inst.validate({ nest: { str: '' } }, { abortEarly: false }),\n      ).rejects.toEqual(\n        expect.objectContaining({\n          value: { nest: { str: '' } },\n          errors: ['nest.str is a required field', 'oops'],\n        }),\n      ),\n    ]);\n  });\n\n  it('should flatten validation errors with abortEarly=false', async () => {\n    let inst = object({\n      str: string().required(),\n      nest: object({\n        innerStr: string().required(),\n        num: number().moreThan(5),\n        other: number().test('nested', 'invalid', () => {\n          string().email().min(3).validateSync('f', { abortEarly: false });\n          return true;\n        }),\n      }).test('name', 'oops', () => false),\n    });\n\n    const error = await inst\n      .validate(\n        { str: null, nest: { num: 2, str: undefined } },\n        { abortEarly: false },\n      )\n      .catch((e) => e);\n\n    expect(error.inner).toMatchInlineSnapshot(`\n      [\n        [ValidationError: str is a required field],\n        [ValidationError: nest.innerStr is a required field],\n        [ValidationError: nest.num must be greater than 5],\n        [ValidationError: oops],\n        [ValidationError: this must be a valid email],\n        [ValidationError: this must be at least 3 characters],\n      ]\n    `);\n\n    expect(error.errors).toEqual([\n      'str is a required field',\n      'nest.innerStr is a required field',\n      'nest.num must be greater than 5',\n      'oops',\n      'this must be a valid email',\n      'this must be at least 3 characters',\n    ]);\n  });\n\n  it('should sort errors by insertion order', async () => {\n    let inst = object({\n      // use `when` to make sure it is validated second\n      foo: string().when('bar', () => string().min(5)),\n      bar: string().required(),\n    });\n\n    await expect(\n      inst.validate({ foo: 'foo' }, { abortEarly: false }),\n    ).rejects.toEqual(\n      validationErrorWithMessages(\n        'foo must be at least 5 characters',\n        'bar is a required field',\n      ),\n    );\n  });\n\n  it('should respect recursive', () => {\n    let inst = object({\n      nest: object({\n        str: string().required(),\n      }),\n    }).test('name', 'oops', () => false);\n\n    let val = { nest: { str: null } };\n\n    return Promise.all([\n      expect(inst.validate(val, { abortEarly: false })).rejects.toEqual(\n        validationErrorWithMessages(expect.any(String), expect.any(String)),\n      ),\n\n      expect(\n        inst.validate(val, { abortEarly: false, recursive: false }),\n      ).rejects.toEqual(validationErrorWithMessages('oops')),\n    ]);\n  });\n\n  it('partial() should work', async () => {\n    let inst = object({\n      age: number().required(),\n      name: string().required(),\n    });\n\n    await expect(inst.isValid({ age: null, name: '' })).resolves.toEqual(false);\n\n    await expect(inst.partial().isValid({})).resolves.toEqual(true);\n\n    await expect(inst.partial().isValid({ age: null })).resolves.toEqual(false);\n    await expect(inst.partial().isValid({ name: '' })).resolves.toEqual(false);\n  });\n\n  it('deepPartial() should work', async () => {\n    let inst = object({\n      age: number().required(),\n      name: string().required(),\n      contacts: array(\n        object({\n          name: string().required(),\n          age: number().required(),\n          lazy: lazy(() => number().required()),\n        }),\n      ).defined(),\n    });\n\n    await expect(inst.isValid({ age: 2, name: 'fs' })).resolves.toEqual(false);\n    await expect(\n      inst.isValid({ age: 2, name: 'fs', contacts: [{}] }),\n    ).resolves.toEqual(false);\n\n    const instPartial = inst.deepPartial();\n\n    await expect(\n      inst.validate({ age: 1, name: 'f', contacts: [{ name: 'f', age: 1 }] }),\n    ).rejects.toThrowError('contacts[0].lazy is a required field');\n\n    await expect(instPartial.isValid({})).resolves.toEqual(true);\n\n    await expect(instPartial.isValid({ contacts: [{}] })).resolves.toEqual(\n      true,\n    );\n\n    await expect(\n      instPartial.isValid({ contacts: [{ age: null }] }),\n    ).resolves.toEqual(false);\n\n    await expect(\n      instPartial.isValid({ contacts: [{ lazy: null }] }),\n    ).resolves.toEqual(false);\n  });\n\n  it('should alias or move keys', () => {\n    let inst = object()\n      .shape({\n        myProp: mixed(),\n        Other: mixed(),\n      })\n      .from('prop', 'myProp')\n      .from('other', 'Other', true);\n\n    expect(inst.cast({ prop: 5, other: 6 })).toEqual({\n      myProp: 5,\n      other: 6,\n      Other: 6,\n    });\n  });\n\n  it('should alias nested keys', () => {\n    let inst = object({\n      foo: object({\n        bar: string(),\n      }),\n      // @ts-expect-error FIXME\n    }).from('foo.bar', 'foobar', true);\n\n    expect(inst.cast({ foo: { bar: 'quz' } })).toEqual({\n      foobar: 'quz',\n      foo: { bar: 'quz' },\n    });\n  });\n\n  it('should not move keys when it does not exist', () => {\n    let inst = object()\n      .shape({\n        myProp: mixed(),\n      })\n      .from('prop', 'myProp');\n\n    expect(inst.cast({ myProp: 5 })).toEqual({ myProp: 5 });\n\n    expect(inst.cast({ myProp: 5, prop: 7 })).toEqual({ myProp: 7 });\n  });\n\n  it('should handle conditionals', () => {\n    let inst = object().shape({\n      noteDate: number()\n        .when('stats.isBig', {\n          is: true,\n          then: (s) => s.min(5),\n        })\n        .when('other', ([v], schema) => (v === 4 ? schema.max(6) : schema)),\n      stats: object({ isBig: bool() }),\n      other: number()\n        .min(1)\n        .when('stats', { is: 5, then: (s) => s }),\n    });\n\n    return Promise.all([\n      expect(\n        // other makes noteDate too large\n        inst.isValid({\n          stats: { isBig: true },\n          rand: 5,\n          noteDate: 7,\n          other: 4,\n        }),\n      ).resolves.toBe(false),\n      expect(\n        inst.isValid({ stats: { isBig: true }, noteDate: 1, other: 4 }),\n      ).resolves.toBe(false),\n\n      expect(\n        inst.isValid({ stats: { isBig: true }, noteDate: 7, other: 6 }),\n      ).resolves.toBe(true),\n      expect(\n        inst.isValid({ stats: { isBig: true }, noteDate: 7, other: 4 }),\n      ).resolves.toBe(false),\n\n      expect(\n        inst.isValid({ stats: { isBig: false }, noteDate: 4, other: 4 }),\n      ).resolves.toBe(true),\n\n      expect(\n        inst.isValid({ stats: { isBig: true }, noteDate: 1, other: 4 }),\n      ).resolves.toBe(false),\n      expect(\n        inst.isValid({ stats: { isBig: true }, noteDate: 6, other: 4 }),\n      ).resolves.toBe(true),\n    ]);\n  });\n\n  it('should handle conditionals with unknown dependencies', () => {\n    let inst = object().shape({\n      value: number().when('isRequired', {\n        is: true,\n        then: (s) => s.required(),\n      }),\n    });\n\n    return Promise.all([\n      expect(\n        inst.isValid({\n          isRequired: true,\n          value: 1234,\n        }),\n      ).resolves.toBe(true),\n      expect(\n        inst.isValid({\n          isRequired: true,\n        }),\n      ).resolves.toBe(false),\n\n      expect(\n        inst.isValid({\n          isRequired: false,\n          value: 1234,\n        }),\n      ).resolves.toBe(true),\n      expect(\n        inst.isValid({\n          value: 1234,\n        }),\n      ).resolves.toBe(true),\n    ]);\n  });\n\n  it('should handle conditionals synchronously', () => {\n    let inst = object().shape({\n      knownDependency: bool(),\n      value: number().when(['unknownDependency', 'knownDependency'], {\n        is: true,\n        then: (s) => s.required(),\n      }),\n    });\n\n    // expect(() =>\n    //   inst.validateSync({\n    //     unknownDependency: true,\n    //     knownDependency: true,\n    //     value: 1234,\n    //   }),\n    // ).not.throw();\n\n    expect(() =>\n      inst.validateSync({\n        unknownDependency: true,\n        knownDependency: true,\n      }),\n    ).toThrowError(/required/);\n  });\n\n  it('should allow opt out of topo sort on specific edges', () => {\n    expect(() => {\n      object().shape({\n        orgID: number().when('location', ([v], schema) => {\n          return v == null ? schema.required() : schema;\n        }),\n        location: string().when('orgID', (v, schema) => {\n          return v == null ? schema.required() : schema;\n        }),\n      });\n    }).toThrowError('Cyclic dependency, node was:\"location\"');\n\n    expect(() => {\n      object().shape(\n        {\n          orgID: number().when('location', ([v], schema) => {\n            return v == null ? schema.required() : schema;\n          }),\n          location: string().when('orgID', ([v], schema) => {\n            return v == null ? schema.required() : schema;\n          }),\n        },\n        [['location', 'orgID']],\n      );\n    }).not.toThrowError();\n  });\n\n  it('should use correct default when concating', () => {\n    let inst = object({\n      other: bool(),\n    }).default(undefined);\n\n    expect(inst.concat(object()).getDefault()).toBeUndefined();\n\n    expect(inst.concat(object().default({})).getDefault()).toEqual({});\n  });\n\n  it('should maintain excluded edges when concating', async () => {\n    const schema = object().shape(\n      {\n        a1: string().when('a2', {\n          is: undefined,\n          then: (s) => s.required(),\n        }),\n        a2: string().when('a1', {\n          is: undefined,\n          then: (s) => s.required(),\n        }),\n      },\n      [['a1', 'a2']],\n    );\n\n    await expect(\n      schema.concat(object()).isValid({ a1: null }),\n    ).resolves.toEqual(false);\n\n    await expect(\n      object().concat(schema).isValid({ a1: null }),\n    ).resolves.toEqual(false);\n  });\n\n  it('should handle nested conditionals', () => {\n    let countSchema = number().when('isBig', {\n      is: true,\n      then: (s) => s.min(5),\n    });\n    let inst = object({\n      other: bool(),\n      stats: object({\n        isBig: bool(),\n        count: countSchema,\n      })\n        .default(undefined)\n        .when('other', { is: true, then: (s) => s.required() }),\n    });\n\n    return Promise.all([\n      expect(inst.validate({ stats: undefined, other: true })).rejects.toEqual(\n        validationErrorWithMessages(expect.stringContaining('required')),\n      ),\n      expect(\n        inst.validate({ stats: { isBig: true, count: 3 }, other: true }),\n      ).rejects.toEqual(\n        validationErrorWithMessages(\n          'stats.count must be greater than or equal to 5',\n        ),\n      ),\n      expect(\n        inst.validate({ stats: { isBig: true, count: 10 }, other: true }),\n      ).resolves.toEqual({\n        stats: { isBig: true, count: 10 },\n        other: true,\n      }),\n\n      expect(\n        countSchema.validate(10, { context: { isBig: true } }),\n      ).resolves.toEqual(10),\n    ]);\n  });\n\n  it('should camelCase keys', () => {\n    let inst = object()\n      .shape({\n        conStat: number(),\n        caseStatus: number(),\n        hiJohn: number(),\n      })\n      .camelCase();\n\n    expect(inst.cast({ CON_STAT: 5, CaseStatus: 6, 'hi john': 4 })).toEqual({\n      conStat: 5,\n      caseStatus: 6,\n      hiJohn: 4,\n    });\n\n    expect(inst.nullable().cast(null)).toBeNull();\n  });\n\n  it('should CONSTANT_CASE keys', () => {\n    let inst = object()\n      .shape({\n        CON_STAT: number(),\n        CASE_STATUS: number(),\n        HI_JOHN: number(),\n      })\n      .constantCase();\n\n    expect(inst.cast({ conStat: 5, CaseStatus: 6, 'hi john': 4 })).toEqual({\n      CON_STAT: 5,\n      CASE_STATUS: 6,\n      HI_JOHN: 4,\n    });\n\n    expect(inst.nullable().cast(null)).toBeNull();\n  });\n\n  it('should pick', async () => {\n    let inst = object({\n      age: number().default(30).required(),\n      name: string().default('pat').required(),\n      color: string().default('red').required(),\n    });\n\n    expect(inst.pick(['age', 'name']).getDefault()).toEqual({\n      age: 30,\n      name: 'pat',\n    });\n\n    expect(\n      await inst.pick(['age', 'name']).validate({ age: 24, name: 'Bill' }),\n    ).toEqual({\n      age: 24,\n      name: 'Bill',\n    });\n  });\n\n  it('should omit', async () => {\n    let inst = object({\n      age: number().default(30).required(),\n      name: string().default('pat').required(),\n      color: string().default('red').required(),\n    });\n\n    expect(inst.omit(['age', 'name']).getDefault()).toEqual({\n      color: 'red',\n    });\n\n    expect(\n      await inst.omit(['age', 'name']).validate({ color: 'mauve' }),\n    ).toEqual({ color: 'mauve' });\n  });\n\n  it('should pick and omit with excluded edges', async () => {\n    const inst = object().shape(\n      {\n        a1: string().when('a2', {\n          is: undefined,\n          then: (schema) => schema.required(),\n        }),\n        a2: string().when('a1', {\n          is: undefined,\n          then: (schema) => schema.required(),\n        }),\n        a3: string().required(),\n      },\n      [['a1', 'a2']],\n    );\n\n    await expect(\n      inst.pick(['a1', 'a2']).isValid({\n        a1: undefined,\n        a2: 'over9000',\n      }),\n    ).resolves.toEqual(true);\n\n    await expect(\n      inst.pick(['a1', 'a3']).isValid({\n        a1: 'required',\n        a3: 'asfasf',\n      }),\n    ).resolves.toEqual(true);\n\n    await expect(\n      inst.omit(['a1', 'a2']).isValid({\n        a3: 'asfasf',\n      }),\n    ).resolves.toEqual(true);\n\n    await expect(\n      inst.omit(['a1']).isValid({\n        a1: undefined,\n        a3: 'asfasf',\n      }),\n    ).resolves.toEqual(false);\n  });\n});\n"
  },
  {
    "path": "test/setLocale.ts",
    "content": "import { describe, it, expect } from 'vitest';\nimport { setLocale } from '../src';\nimport locale from '../src/locale';\n\ndescribe('Custom locale', () => {\n  it('should get default locale', () => {\n    expect(locale.string?.email).toBe('${path} must be a valid email');\n  });\n\n  it('should set a new locale', () => {\n    const dict = {\n      string: {\n        email: 'Invalid email',\n      },\n    };\n\n    setLocale(dict);\n\n    expect(locale.string?.email).toBe(dict.string.email);\n  });\n\n  it('should update the main locale', () => {\n    expect(locale.string?.email).toBe('Invalid email');\n  });\n\n  it('should not allow prototype pollution', () => {\n    const payload = JSON.parse(\n      '{\"__proto__\":{\"polluted\":\"Yes! Its Polluted\"}}',\n    );\n\n    expect(() => setLocale(payload)).toThrowError();\n\n    expect(payload).not.toHaveProperty('polluted');\n  });\n\n  it('should not pollute Object.prototype builtins', () => {\n    const payload: any = { toString: { polluted: 'oh no' } };\n\n    expect(() => setLocale(payload)).toThrowError();\n\n    expect(Object.prototype.toString).not.toHaveProperty('polluted');\n  });\n});\n"
  },
  {
    "path": "test/standardSchema.ts",
    "content": "import { describe, it, expect, test, beforeAll } from 'vitest';\nimport {\n  string,\n  number,\n  array,\n  bool,\n  object,\n  date,\n  mixed,\n  tuple,\n  lazy,\n  addMethod,\n} from '../src';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\n\nfunction verifyStandardSchema<Input, Output>(\n  schema: StandardSchemaV1<Input, Output>,\n) {\n  return (\n    schema['~standard'].version === 1 &&\n    schema['~standard'].vendor === 'yup' &&\n    typeof schema['~standard'].validate === 'function'\n  );\n}\n\n/**\n * Helper function to get Yup validation error directly without try-catch boilerplate\n */\nasync function getYupValidationError(\n  schema: any,\n  value: any,\n  options?: any,\n): Promise<any> {\n  try {\n    await schema.validate(value, { abortEarly: false, ...options });\n    return null; // No error occurred\n  } catch (err) {\n    return err; // Return the validation error\n  }\n}\n\n/**\n * Helper function to compare standard schema validation results with main Yup API\n */\nasync function expectValidationConsistency(\n  schema: any,\n  testValue: any,\n  shouldBeValid?: boolean,\n  expectedMessage?: string,\n  options?: any,\n) {\n  // Test with standard schema\n  const standardResult = await schema['~standard'].validate(testValue);\n\n  // Test with main API\n  const mainAPIError = await getYupValidationError(schema, testValue, options);\n\n  if (shouldBeValid === true) {\n    // Both should succeed\n    expect(standardResult.issues).toBeUndefined();\n    expect(mainAPIError).toBeNull();\n  } else if (shouldBeValid === false) {\n    // Both should have errors\n    expect(standardResult.issues).toBeDefined();\n    expect(mainAPIError).toBeDefined();\n\n    if (expectedMessage) {\n      expect(mainAPIError?.message).toEqual(\n        expect.stringContaining(expectedMessage),\n      );\n      expect(standardResult.issues?.[0]?.message).toEqual(\n        expect.stringContaining(expectedMessage),\n      );\n    }\n  } else {\n    // Original behavior - just compare that both have errors\n    expect(standardResult.issues).toBeDefined();\n    expect(mainAPIError).toBeDefined();\n\n    // Compare error counts\n    expect(standardResult.issues?.length).toBe(mainAPIError.inner.length);\n\n    // Compare error messages (sorted for order independence)\n    const standardMessages = standardResult.issues\n      ?.map((issue: any) => issue.message)\n      .sort();\n    const mainMessages = mainAPIError.inner\n      .map((err: any) => err.message)\n      .sort();\n    expect(standardMessages).toEqual(mainMessages);\n  }\n\n  return { standardResult, mainAPIError };\n}\n\ntest('is compatible with standard schema', () => {\n  expect(verifyStandardSchema(string())).toBe(true);\n  expect(verifyStandardSchema(number())).toBe(true);\n  expect(verifyStandardSchema(array())).toBe(true);\n  expect(verifyStandardSchema(bool())).toBe(true);\n  expect(verifyStandardSchema(object())).toBe(true);\n  expect(verifyStandardSchema(date())).toBe(true);\n  expect(verifyStandardSchema(mixed())).toBe(true);\n  expect(verifyStandardSchema(tuple([mixed()]))).toBe(true);\n  expect(verifyStandardSchema(lazy(() => string()))).toBe(true);\n});\n\ntest('issues path is an array of property paths', async () => {\n  const schema = object({\n    obj: object({\n      foo: string().required(),\n      'not.obj.nested': string().required(),\n    }).required(),\n    arr: array(\n      object({\n        foo: string().required(),\n        'not.array.nested': string().required(),\n      }),\n    ).required(),\n    'not.a.field': string().required(),\n  });\n\n  const testValue = {\n    obj: { foo: '', 'not.obj.nested': '' },\n    arr: [{ foo: '', 'not.array.nested': '' }],\n  };\n\n  // Use helper function to compare validation consistency\n  const { standardResult } = await expectValidationConsistency(\n    schema,\n    testValue,\n  );\n\n  // Verify specific path structures are correct\n  expect(standardResult.issues?.map((issue: any) => issue.path)).toEqual(\n    expect.arrayContaining([\n      ['obj', 'foo'],\n      ['obj', 'not.obj.nested'],\n      ['arr', '0', 'foo'],\n      ['arr', '0', 'not.array.nested'],\n      ['not.a.field'],\n    ]),\n  );\n});\n\ntest('should clone correctly when using modifiers', async () => {\n  const schema = string().required();\n  const testValue = '';\n\n  // Use helper function to compare validation consistency\n  const { standardResult } = await expectValidationConsistency(\n    schema,\n    testValue,\n  );\n\n  // Verify path is undefined for root-level validation\n  expect(standardResult.issues?.[0]?.path).toBeUndefined();\n});\n\ntest('should work correctly with lazy schemas', async () => {\n  let isNumber = false;\n  const schema = lazy(() => {\n    if (isNumber) {\n      return number().min(10);\n    }\n\n    return string().required().min(12);\n  });\n\n  const testValue1 = '';\n\n  // Use helper function to compare validation consistency for string validation\n  const { standardResult: result1 } = await expectValidationConsistency(\n    schema,\n    testValue1,\n  );\n\n  // Verify path is undefined for root-level validation\n  expect(result1.issues?.every((issue: any) => issue.path === undefined)).toBe(\n    true,\n  );\n\n  isNumber = true;\n\n  const testValue2 = 5;\n\n  // Use helper function to compare validation consistency for number validation\n  const { standardResult: result2 } = await expectValidationConsistency(\n    schema,\n    testValue2,\n  );\n\n  // Verify path is undefined for root-level validation\n  expect(result2.issues?.[0]?.path).toBeUndefined();\n});\n\ndescribe('Array schema standard interface tests', () => {\n  test('should handle basic array validation', async () => {\n    const schema = array(string());\n\n    // Test with valid array\n    const validResult = await schema['~standard'].validate(['a', 'b', 'c']);\n    if (!validResult.issues) {\n      expect(validResult.value).toEqual(['a', 'b', 'c']);\n    }\n\n    // Test with invalid array items - use an object that can't be cast to string\n    const testValue = ['a', { foo: 'bar' }, 'c'];\n\n    // Use helper function to compare validation consistency\n    const { standardResult } = await expectValidationConsistency(\n      schema,\n      testValue,\n    );\n\n    // Verify specific error details\n    expect(standardResult.issues?.[0]?.path).toEqual(['1']);\n    expect(standardResult.issues?.[0]?.message).toContain(\n      'must be a `string` type',\n    );\n  });\n\n  test('should handle array length validations', async () => {\n    const schema = array(string()).min(2).max(4);\n\n    // Test empty array\n    const emptyTestValue: string[] = [];\n\n    // Use helper function to compare validation consistency for empty array\n    await expectValidationConsistency(schema, emptyTestValue);\n\n    // Test array too long\n    const longTestValue = ['a', 'b', 'c', 'd', 'e'];\n\n    // Use helper function to compare validation consistency for long array\n    await expectValidationConsistency(schema, longTestValue);\n  });\n\n  test('should handle required array validation', async () => {\n    const schema = array(string()).required();\n    const testValue = undefined;\n\n    // Use helper function to compare validation consistency\n    const { standardResult } = await expectValidationConsistency(\n      schema,\n      testValue,\n    );\n\n    // Verify path is undefined for root-level validation\n    expect(standardResult.issues?.[0]?.path).toBeUndefined();\n  });\n\n  test('array validation should produce same errors as main API', async () => {\n    const schema = array(string().required()).min(2);\n    const testValue = ['valid', ''];\n\n    // Use helper function to compare validation consistency\n    await expectValidationConsistency(schema, testValue);\n  });\n});\n\ndescribe('Object schema standard interface tests', () => {\n  test('should handle basic object validation', async () => {\n    const schema = object({\n      name: string().required(),\n      age: number().required().min(0),\n    });\n\n    // Test with valid object\n    const validResult = await schema['~standard'].validate({\n      name: 'John',\n      age: 25,\n    });\n    if (!validResult.issues) {\n      expect(validResult.value).toEqual({ name: 'John', age: 25 });\n    }\n\n    // Test with invalid object\n    const testValue = {\n      name: '',\n      age: -1,\n    };\n\n    // Use helper function to compare validation consistency\n    const { standardResult } = await expectValidationConsistency(\n      schema,\n      testValue,\n    );\n\n    // Verify specific error details with flexible matching\n    expect(standardResult.issues).toEqual(\n      expect.arrayContaining([\n        { path: ['name'], message: expect.stringContaining('required') },\n        {\n          path: ['age'],\n          message: expect.stringContaining('greater than or equal to 0'),\n        },\n      ]),\n    );\n  });\n\n  test('should handle nested object validation', async () => {\n    const schema = object({\n      user: object({\n        profile: object({\n          name: string().required(),\n          email: string().email(),\n        }),\n      }),\n    });\n\n    const testValue = {\n      user: {\n        profile: {\n          name: '',\n          email: 'invalid-email',\n        },\n      },\n    };\n\n    // Use helper function to compare validation consistency\n    const { standardResult } = await expectValidationConsistency(\n      schema,\n      testValue,\n    );\n\n    // Verify specific error details\n    expect(standardResult.issues).toEqual(\n      expect.arrayContaining([\n        {\n          path: ['user', 'profile', 'name'],\n          message: expect.stringContaining('required'),\n        },\n        {\n          path: ['user', 'profile', 'email'],\n          message: expect.stringContaining('valid email'),\n        },\n      ]),\n    );\n  });\n\n  test('should handle object with array fields', async () => {\n    const schema = object({\n      tags: array(string().required()).min(1),\n      metadata: object({\n        version: number().required(),\n      }).required(),\n    });\n\n    const testValue = {\n      tags: [],\n      metadata: null,\n    };\n\n    // Use helper function to compare validation consistency\n    const { standardResult } = await expectValidationConsistency(\n      schema,\n      testValue,\n    );\n\n    // Verify specific error details with more flexible matching\n    expect(standardResult.issues).toEqual(\n      expect.arrayContaining([\n        { path: ['tags'], message: expect.stringContaining('at least 1') },\n        { path: ['metadata'], message: expect.stringContaining('required') },\n      ]),\n    );\n  });\n\n  test('object validation should produce same errors as main API', async () => {\n    const schema = object({\n      email: string().email().required(),\n      age: number().min(18).required(),\n      profile: object({\n        bio: string().max(100),\n      }),\n    });\n\n    const testValue = {\n      email: 'invalid-email',\n      age: 16,\n      profile: {\n        bio: 'x'.repeat(150),\n      },\n    };\n\n    // Use helper function to compare validation consistency\n    await expectValidationConsistency(schema, testValue);\n  });\n});\n\ndescribe('Lazy schema standard interface tests', () => {\n  test('should handle conditional lazy schema validation', async () => {\n    const schema = lazy((value: any) => {\n      if (typeof value === 'string') {\n        return string().min(5);\n      }\n      if (typeof value === 'number') {\n        return number().max(100);\n      }\n      return mixed().required();\n    });\n\n    // Test string validation\n    const stringTestValue = 'abc';\n    const { standardResult: stringResult } = await expectValidationConsistency(\n      schema,\n      stringTestValue,\n    );\n    expect(stringResult.issues?.[0]?.path).toBeUndefined();\n\n    // Test number validation\n    const numberTestValue = 150;\n    const { standardResult: numberResult } = await expectValidationConsistency(\n      schema,\n      numberTestValue,\n    );\n    expect(numberResult.issues?.[0]?.path).toBeUndefined();\n\n    // Test successful validation\n    const validStringResult = await schema['~standard'].validate('hello world');\n    if (!validStringResult.issues) {\n      expect(validStringResult.value).toBe('hello world');\n    }\n  });\n\n  test('should handle lazy schema with object validation', async () => {\n    const schema = lazy((value: any) => {\n      if (value?.type === 'user') {\n        return object({\n          type: string().oneOf(['user']),\n          name: string().required(),\n          email: string().email().required(),\n        });\n      }\n      if (value?.type === 'admin') {\n        return object({\n          type: string().oneOf(['admin']),\n          name: string().required(),\n          permissions: array(string()).min(1),\n        });\n      }\n      return object({\n        type: string().required(),\n      });\n    });\n\n    // Test user validation\n    const userTestValue = {\n      type: 'user',\n      name: '',\n      email: 'invalid',\n    };\n\n    const { standardResult: userResult } = await expectValidationConsistency(\n      schema,\n      userTestValue,\n    );\n\n    expect(userResult.issues).toEqual(\n      expect.arrayContaining([\n        { path: ['name'], message: expect.stringContaining('required') },\n        { path: ['email'], message: expect.stringContaining('valid email') },\n      ]),\n    );\n\n    // Test admin validation\n    const adminTestValue = {\n      type: 'admin',\n      name: 'Admin User',\n      permissions: [],\n    };\n\n    const { standardResult: adminResult } = await expectValidationConsistency(\n      schema,\n      adminTestValue,\n    );\n\n    expect(adminResult.issues).toEqual([\n      {\n        path: ['permissions'],\n        message: expect.stringContaining('at least 1'),\n      },\n    ]);\n  });\n\n  test('lazy validation should produce same errors as main API', async () => {\n    const schema = lazy((value: any) => {\n      if (Array.isArray(value)) {\n        return array(string().required()).min(2);\n      }\n      return string().required().min(5);\n    });\n\n    const testValue = ['valid', ''];\n\n    // Use helper function to compare validation consistency\n    await expectValidationConsistency(schema, testValue);\n  });\n});\n\ndescribe('Complex nested validation comparisons', () => {\n  test('should handle deeply nested structure validation identically', async () => {\n    const schema = object({\n      users: array(\n        object({\n          id: number().required().positive(),\n          profile: object({\n            name: string().required().min(2),\n            contact: object({\n              email: string().email().required(),\n              phone: string().matches(/^\\d{10}$/, 'Phone must be 10 digits'),\n            }),\n          }),\n          preferences: array(string()).max(5),\n        }),\n      ).min(1),\n      metadata: object({\n        version: string().required(),\n        tags: array(string().required()).min(1),\n      }),\n    });\n\n    const testValue = {\n      users: [\n        {\n          id: -1,\n          profile: {\n            name: 'A',\n            contact: {\n              email: 'invalid-email',\n              phone: '123',\n            },\n          },\n          preferences: ['a', 'b', 'c', 'd', 'e', 'f'],\n        },\n      ],\n      metadata: {\n        version: '',\n        tags: [],\n      },\n    };\n\n    // Use helper function to compare validation consistency\n    const { standardResult } = await expectValidationConsistency(\n      schema,\n      testValue,\n    );\n\n    // Verify specific error paths exist\n    const standardPaths = standardResult.issues?.map((issue: any) =>\n      issue.path ? issue.path.join('.') : undefined,\n    );\n    expect(standardPaths).toContain('users.0.id');\n    expect(standardPaths).toContain('users.0.profile.name');\n    expect(standardPaths).toContain('users.0.profile.contact.email');\n    expect(standardPaths).toContain('users.0.profile.contact.phone');\n    expect(standardPaths).toContain('users.0.preferences');\n    expect(standardPaths).toContain('metadata.version');\n    expect(standardPaths).toContain('metadata.tags');\n  });\n\n  test('should handle successful validation identically', async () => {\n    const schema = object({\n      name: string().required(),\n      age: number().min(0).max(120),\n      email: string().email(),\n      address: object({\n        street: string(),\n        city: string().required(),\n        zipCode: string().matches(/^\\d{5}$/),\n      }),\n      hobbies: array(string()).max(10),\n    });\n\n    const validValue = {\n      name: 'John Doe',\n      age: 30,\n      email: 'john@example.com',\n      address: {\n        street: '123 Main St',\n        city: 'Anytown',\n        zipCode: '12345',\n      },\n      hobbies: ['reading', 'swimming'],\n    };\n\n    // Test with standard schema\n    const standardResult = await schema['~standard'].validate(validValue);\n\n    // Test with main API\n    const mainResult = await schema.validate(validValue);\n\n    // Both should succeed\n    expect(standardResult.issues).toBeUndefined();\n    if (!standardResult.issues) {\n      expect(standardResult.value).toEqual(mainResult);\n    }\n  });\n});\n\ndescribe('Error message consistency tests', () => {\n  test('should produce identical error messages for string validations', async () => {\n    const schema = string().required().min(5).max(10).email();\n    const testValue = 'abc';\n\n    // Use helper function to compare validation consistency\n    await expectValidationConsistency(schema, testValue);\n  });\n\n  test('should produce identical error messages for number validations', async () => {\n    const schema = number().required().min(10).max(100).integer();\n    const testValue = 5.5;\n\n    // Use helper function to compare validation consistency\n    await expectValidationConsistency(schema, testValue);\n  });\n\n  test('should handle transform behavior consistently', async () => {\n    const schema = object({\n      name: string().trim().lowercase(),\n      age: number(),\n      active: bool(),\n    });\n\n    const testValue = {\n      name: '  JOHN DOE  ',\n      age: '25',\n      active: 'true',\n    };\n\n    // Test with standard schema\n    const standardResult = await schema['~standard'].validate(testValue);\n\n    // Test with main API\n    const mainResult = await schema.validate(testValue);\n\n    // Both should succeed and produce same transformed values\n    expect(standardResult.issues).toBeUndefined();\n    if (!standardResult.issues) {\n      expect(standardResult.value).toEqual(mainResult);\n      expect(standardResult.value).toEqual({\n        name: 'john doe',\n        age: 25,\n        active: true,\n      });\n    }\n  });\n});\n\ndescribe('Conditional validation tests with when API', () => {\n  test('should handle basic conditional validation', async () => {\n    const schema = object({\n      isMember: bool(),\n      membershipId: string().when('isMember', {\n        is: true,\n        then: (schema) => schema.required(),\n        otherwise: (schema) => schema.optional(),\n      }),\n    });\n\n    // Test when condition is true\n    const testValue = {\n      isMember: true,\n      membershipId: '',\n    };\n\n    // Use helper function to compare validation consistency\n    const { standardResult } = await expectValidationConsistency(\n      schema,\n      testValue,\n    );\n\n    // Verify specific error details with flexible matching\n    expect(standardResult.issues).toEqual([\n      { path: ['membershipId'], message: expect.stringContaining('required') },\n    ]);\n\n    // Test when condition is false\n    const nonMemberResult = await schema['~standard'].validate({\n      isMember: false,\n      membershipId: '',\n    });\n    if (!nonMemberResult.issues) {\n      expect(nonMemberResult.value).toEqual({\n        isMember: false,\n        membershipId: '',\n      });\n    }\n  });\n\n  test('should handle conditional validation with function predicate', async () => {\n    const schema = object({\n      age: number().required(),\n      parentalConsent: bool().when('age', {\n        is: (age: number) => age < 18,\n        then: (schema) => schema.required(),\n        otherwise: (schema) => schema.optional(),\n      }),\n    });\n\n    // Test when condition is true (age < 18)\n    const testValue = {\n      age: 16,\n      parentalConsent: undefined,\n    };\n\n    // Use helper function to compare validation consistency\n    const { standardResult } = await expectValidationConsistency(\n      schema,\n      testValue,\n    );\n\n    // Verify specific error details\n    expect(standardResult.issues).toEqual([\n      {\n        path: ['parentalConsent'],\n        message: expect.stringContaining('required'),\n      },\n    ]);\n\n    // Test when condition is false (age >= 18)\n    const adultResult = await schema['~standard'].validate({\n      age: 25,\n      parentalConsent: undefined,\n    });\n    if (!adultResult.issues) {\n      expect(adultResult.value).toEqual({\n        age: 25,\n        parentalConsent: undefined,\n      });\n    }\n  });\n\n  test('should handle multiple conditional dependencies', async () => {\n    const schema = object({\n      accountType: string().oneOf(['personal', 'business']),\n      hasEmployees: bool(),\n      employeeCount: number().when(['accountType', 'hasEmployees'], {\n        is: (accountType: string, hasEmployees: boolean) =>\n          accountType === 'business' && hasEmployees,\n        then: (schema) => schema.required().min(1),\n        otherwise: (schema) => schema.optional(),\n      }),\n    });\n\n    // Test when both conditions are met\n    const testValue = {\n      accountType: 'business',\n      hasEmployees: true,\n      employeeCount: undefined,\n    };\n\n    // Use helper function to compare validation consistency\n    const { standardResult } = await expectValidationConsistency(\n      schema,\n      testValue,\n    );\n\n    // Verify specific error details\n    expect(standardResult.issues).toEqual([\n      { path: ['employeeCount'], message: expect.stringContaining('required') },\n    ]);\n\n    // Test when conditions are not met\n    const personalAccountResult = await schema['~standard'].validate({\n      accountType: 'personal',\n      hasEmployees: false,\n      employeeCount: undefined,\n    });\n    if (!personalAccountResult.issues) {\n      expect(personalAccountResult.value).toEqual({\n        accountType: 'personal',\n        hasEmployees: false,\n        employeeCount: undefined,\n      });\n    }\n  });\n\n  test('should handle nested conditional validation', async () => {\n    const schema = object({\n      shippingMethod: string().oneOf([\n        'standard',\n        'express',\n        'overnight',\n        'pickup',\n      ]),\n      deliveryAddress: object({\n        street: string().required(),\n        city: string().required(),\n        state: string().required(),\n        zipCode: string().required(),\n        country: string().required(),\n      }).when('shippingMethod', {\n        is: (method: string) => method !== 'pickup',\n        then: (schema) => schema.required(),\n        otherwise: (schema) => schema.optional(),\n      }),\n    });\n\n    // Test with shipping method that requires address but missing address\n    const testValue = {\n      shippingMethod: 'overnight',\n      // deliveryAddress is completely missing\n    };\n\n    // Use helper function to compare validation consistency\n    const { standardResult } = await expectValidationConsistency(\n      schema,\n      testValue,\n    );\n\n    // When the address is required but missing, we get errors for its required fields\n    expect(\n      standardResult.issues?.some(\n        (issue: any) =>\n          issue.path?.join('.') === 'deliveryAddress.street' &&\n          issue.message.includes('required'),\n      ),\n    ).toBe(true);\n\n    // Test with pickup method where address is optional\n    const pickupResult = await schema['~standard'].validate({\n      shippingMethod: 'pickup',\n      // deliveryAddress is optional for pickup\n    });\n\n    if (!pickupResult.issues) {\n      expect(pickupResult.value).toEqual({\n        shippingMethod: 'pickup',\n      });\n    }\n  });\n\n  test('should handle conditional validation with context variables', async () => {\n    const schema = object({\n      role: string().oneOf(['user', 'admin']),\n      permissions: array(string()).when('$userRole', {\n        is: 'admin',\n        then: (schema) => schema.min(1).required(),\n        otherwise: (schema) => schema.optional(),\n      }),\n    });\n\n    // Test standard schema (doesn't support context, so this should pass)\n    const adminStandardResult = await schema['~standard'].validate({\n      role: 'user',\n      permissions: [],\n    });\n\n    // Note: Standard schema doesn't have context, so this should pass\n    if (!adminStandardResult.issues) {\n      expect(adminStandardResult.value).toEqual({\n        role: 'user',\n        permissions: [],\n      });\n    }\n  });\n\n  test('conditional validation should produce same errors as main API', async () => {\n    const schema = object({\n      subscriptionType: string().oneOf(['free', 'premium', 'enterprise']),\n      features: array(string()).when('subscriptionType', {\n        is: 'free',\n        then: (schema) => schema.max(3),\n        otherwise: (schema) => schema.max(20),\n      }),\n      maxUsers: number().when('subscriptionType', {\n        is: 'enterprise',\n        then: (schema) => schema.required().min(50),\n        otherwise: (schema) => schema.optional().max(10),\n      }),\n    });\n\n    const testValue = {\n      subscriptionType: 'enterprise',\n      features: Array(25).fill('feature'), // Too many for any plan\n      maxUsers: 5, // Too low for enterprise\n    };\n\n    // Use helper function to compare validation consistency\n    await expectValidationConsistency(schema, testValue);\n  });\n\n  test('should handle when with function returning schema', async () => {\n    const schema = object({\n      userType: string().oneOf(['individual', 'organization']),\n      name: string().when('userType', ([userType], schema) => {\n        if (userType === 'organization') {\n          return schema.required().min(2).max(100);\n        }\n        return schema.required().min(1).max(50);\n      }),\n      taxId: string().when('userType', ([userType], schema) => {\n        if (userType === 'organization') {\n          return schema\n            .required()\n            .matches(/^\\d{2}-\\d{7}$/, 'Tax ID must be in format XX-XXXXXXX');\n        }\n        return schema.optional();\n      }),\n    });\n\n    // Test organization validation\n    const testValue = {\n      userType: 'organization',\n      name: 'A', // Too short for organization\n      taxId: 'invalid-format',\n    };\n\n    // Use helper function to compare validation consistency\n    const { standardResult } = await expectValidationConsistency(\n      schema,\n      testValue,\n    );\n\n    // Verify specific error details with flexible matching\n    expect(standardResult.issues).toEqual(\n      expect.arrayContaining([\n        { path: ['name'], message: expect.stringContaining('at least 2') },\n        {\n          path: ['taxId'],\n          message: expect.stringContaining('Tax ID must be in format'),\n        },\n      ]),\n    );\n\n    // Test individual validation\n    const individualResult = await schema['~standard'].validate({\n      userType: 'individual',\n      name: 'John Doe',\n      taxId: undefined,\n    });\n\n    if (!individualResult.issues) {\n      expect(individualResult.value).toEqual({\n        userType: 'individual',\n        name: 'John Doe',\n        taxId: undefined,\n      });\n    }\n  });\n\n  test('should handle complex conditional chains', async () => {\n    const schema = object({\n      eventType: string().oneOf(['conference', 'workshop', 'webinar']),\n      isVirtual: bool(),\n      location: string().when(['eventType', 'isVirtual'], {\n        is: (eventType: string, isVirtual: boolean) =>\n          eventType !== 'webinar' && !isVirtual,\n        then: (schema) => schema.required().min(5),\n        otherwise: (schema) => schema.optional(),\n      }),\n      platformUrl: string()\n        .url()\n        .when('isVirtual', {\n          is: true,\n          then: (schema) => schema.required(),\n          otherwise: (schema) => schema.optional(),\n        }),\n      capacity: number()\n        .min(1)\n        .when('eventType', {\n          is: 'conference',\n          then: (schema) => schema.min(50).required(),\n          otherwise: (schema) => schema.max(100).optional(),\n        }),\n    });\n\n    const testValue = {\n      eventType: 'conference',\n      isVirtual: false,\n      location: '', // Required but empty\n      platformUrl: '', // Not required but invalid URL if provided\n      capacity: 10, // Too low for conference\n    };\n\n    // Use helper function to compare validation consistency\n    const { standardResult } = await expectValidationConsistency(\n      schema,\n      testValue,\n    );\n\n    // Verify specific conditional errors\n    const standardPaths = standardResult.issues?.map((issue: any) =>\n      issue.path ? issue.path.join('.') : undefined,\n    );\n    expect(standardPaths).toContain('location');\n    expect(standardPaths).toContain('capacity');\n  });\n});\n\ndescribe('Concat API standard interface tests', () => {\n  test('should handle string schema concatenation', async () => {\n    const baseSchema = string().required();\n    const extendedSchema = string().min(5).max(20);\n    const concatenatedSchema = baseSchema.concat(extendedSchema);\n\n    // Test with invalid value that violates both base and extended rules\n    const testValue = '';\n\n    // Use helper function to compare validation consistency\n    const { standardResult } = await expectValidationConsistency(\n      concatenatedSchema,\n      testValue,\n    );\n\n    // Verify that concatenated schema produces errors for all combined rules\n    expect(standardResult.issues?.length).toBeGreaterThan(0);\n    expect(standardResult.issues?.[0]?.path).toBeUndefined(); // Root level validation\n  });\n\n  test('should handle number schema concatenation', async () => {\n    const baseSchema = number().required().min(0);\n    const extendedSchema = number().max(100).integer();\n    const concatenatedSchema = baseSchema.concat(extendedSchema);\n\n    // Test with invalid value that violates extended rules\n    const testValue = 150.5;\n\n    // Use helper function to compare validation consistency\n    await expectValidationConsistency(concatenatedSchema, testValue);\n  });\n\n  test('should handle object schema concatenation', async () => {\n    const baseSchema = object({\n      name: string().required(),\n      email: string().email(),\n    });\n\n    const extendedSchema = object({\n      age: number().required().min(18),\n      phone: string().matches(/^\\d{10}$/, 'Phone must be 10 digits'),\n    });\n\n    const concatenatedSchema = baseSchema.concat(extendedSchema);\n\n    // Test with value that has errors in both base and extended fields\n    const testValue = {\n      name: '', // Violates base schema\n      email: 'invalid-email', // Violates base schema\n      age: 16, // Violates extended schema\n      phone: '123', // Violates extended schema\n    };\n\n    // Use helper function to compare validation consistency\n    const { standardResult } = await expectValidationConsistency(\n      concatenatedSchema,\n      testValue,\n    );\n\n    // Verify that all fields from both schemas are validated\n    const errorPaths = standardResult.issues?.map(\n      (issue: any) => issue.path?.[0],\n    );\n    expect(errorPaths).toContain('name');\n    expect(errorPaths).toContain('email');\n    expect(errorPaths).toContain('age');\n    expect(errorPaths).toContain('phone');\n  });\n\n  test('should handle array schema concatenation', async () => {\n    const baseSchema = array(string()).required();\n    const extendedSchema = array().min(2).max(5);\n    const concatenatedSchema = baseSchema.concat(extendedSchema);\n\n    // Test with array that violates extended rules\n    const testValue = ['single-item']; // Less than min length\n\n    // Use helper function to compare validation consistency\n    await expectValidationConsistency(concatenatedSchema, testValue);\n  });\n\n  test('should handle concat with conditional validation', async () => {\n    const baseSchema = object({\n      type: string().oneOf(['user', 'admin']),\n      name: string().required(),\n    });\n\n    const extendedSchema = object({\n      permissions: array(string()).when('type', {\n        is: 'admin',\n        then: (schema) => schema.required().min(1),\n        otherwise: (schema) => schema.optional(),\n      }),\n    });\n\n    const concatenatedSchema = baseSchema.concat(extendedSchema);\n\n    // Test admin type without permissions\n    const testValue = {\n      type: 'admin',\n      name: 'Admin User',\n      permissions: [], // Should be required and non-empty for admin\n    };\n\n    // Use helper function to compare validation consistency\n    const { standardResult } = await expectValidationConsistency(\n      concatenatedSchema,\n      testValue,\n    );\n\n    // Verify conditional validation works in concatenated schema\n    expect(standardResult.issues).toEqual([\n      {\n        path: ['permissions'],\n        message: expect.stringContaining('at least 1'),\n      },\n    ]);\n  });\n\n  test('should handle concat with transforms', async () => {\n    const baseSchema = object({\n      name: string().trim(),\n      email: string().lowercase(),\n    });\n\n    const extendedSchema = object({\n      age: number(),\n      active: bool(),\n    });\n\n    const concatenatedSchema = baseSchema.concat(extendedSchema);\n\n    // Test with transformable values\n    const testValue = {\n      name: '  John Doe  ',\n      email: 'JOHN@EXAMPLE.COM',\n      age: '25',\n      active: 'true',\n    };\n\n    // Test with standard schema\n    const standardResult = await concatenatedSchema['~standard'].validate(\n      testValue,\n    );\n\n    // Test with main API\n    const mainResult = await concatenatedSchema.validate(testValue);\n\n    // Both should succeed and produce same transformed values\n    expect(standardResult.issues).toBeUndefined();\n    if (!standardResult.issues) {\n      expect(standardResult.value).toEqual(mainResult);\n      expect(standardResult.value).toEqual({\n        name: 'John Doe',\n        email: 'john@example.com',\n        age: 25,\n        active: true,\n      });\n    }\n  });\n\n  test('should handle multiple concat operations', async () => {\n    const baseSchema = string().required();\n    const firstExtension = string().min(3);\n    const secondExtension = string().max(10);\n    const thirdExtension = string().matches(\n      /^[A-Z]/,\n      'Must start with uppercase letter',\n    );\n\n    const concatenatedSchema = baseSchema\n      .concat(firstExtension)\n      .concat(secondExtension)\n      .concat(thirdExtension);\n\n    // Test with value that violates multiple rules\n    const testValue = 'ab'; // Too short and doesn't start with uppercase\n\n    // Use helper function to compare validation consistency\n    await expectValidationConsistency(concatenatedSchema, testValue);\n  });\n\n  test('should handle concat with nested object schemas', async () => {\n    const baseSchema = object({\n      user: object({\n        name: string().required(),\n        email: string().email(),\n      }),\n    });\n\n    const extendedSchema = object({\n      user: object({\n        age: number().min(18),\n        phone: string().required(),\n      }),\n      metadata: object({\n        createdAt: date().required(),\n      }),\n    });\n\n    const concatenatedSchema = baseSchema.concat(extendedSchema);\n\n    // Test with nested validation errors\n    const testValue = {\n      user: {\n        name: '',\n        email: 'invalid-email',\n        age: 16,\n        phone: '',\n      },\n      metadata: {\n        createdAt: null,\n      },\n    };\n\n    // Use helper function to compare validation consistency\n    const { standardResult } = await expectValidationConsistency(\n      concatenatedSchema,\n      testValue,\n    );\n\n    // With object concat, the extended schema typically overrides the base schema fields\n    // So we mainly check for the extended schema fields and metadata\n    const errorPaths = standardResult.issues?.map((issue: any) =>\n      issue.path ? issue.path.join('.') : undefined,\n    );\n    expect(errorPaths).toContain('user.age');\n    expect(errorPaths).toContain('user.phone');\n    expect(errorPaths).toContain('metadata.createdAt');\n  });\n\n  test('should handle concat with mixed schema types', async () => {\n    const baseSchema = object({\n      value: mixed().required(),\n    });\n\n    const extendedSchema = object({\n      value: mixed().test('custom', 'Value must be positive', (value: any) => {\n        return typeof value === 'number' ? value > 0 : true;\n      }),\n      description: string().optional(),\n    });\n\n    const concatenatedSchema = baseSchema.concat(extendedSchema);\n\n    // Test with negative number (violates custom test)\n    const testValue = {\n      value: -5,\n      description: 'A negative value',\n    };\n\n    // Use helper function to compare validation consistency\n    await expectValidationConsistency(concatenatedSchema, testValue);\n  });\n\n  test('should handle successful concat validation', async () => {\n    const baseSchema = object({\n      name: string().required(),\n      email: string().email().required(),\n    });\n\n    const extendedSchema = object({\n      age: number().min(18).max(120),\n      newsletter: bool().default(false),\n    });\n\n    const concatenatedSchema = baseSchema.concat(extendedSchema);\n\n    // Test with valid data\n    const validValue = {\n      name: 'John Doe',\n      email: 'john@example.com',\n      age: 30,\n      newsletter: true,\n    };\n\n    // Test with standard schema\n    const standardResult = await concatenatedSchema['~standard'].validate(\n      validValue,\n    );\n\n    // Test with main API\n    const mainResult = await concatenatedSchema.validate(validValue);\n\n    // Both should succeed\n    expect(standardResult.issues).toBeUndefined();\n    if (!standardResult.issues) {\n      expect(standardResult.value).toEqual(mainResult);\n    }\n  });\n});\n\ndescribe('AddMethod API standard interface tests', () => {\n  beforeAll(() => {\n    // Add custom methods to string schema\n    addMethod(string, 'isUpperCase', function (message = 'Must be uppercase') {\n      return this.test('isUpperCase', message, function (value: any) {\n        return value == null || value === value.toUpperCase();\n      });\n    });\n\n    addMethod(\n      string,\n      'hasMinWords',\n      function (minWords: number, message?: string) {\n        const defaultMessage = `Must have at least ${minWords} words`;\n        return this.test(\n          'hasMinWords',\n          message || defaultMessage,\n          function (value: any) {\n            if (value == null) return true;\n            return value.trim().split(/\\s+/).length >= minWords;\n          },\n        );\n      },\n    );\n\n    addMethod(\n      string,\n      'startsWithCapital',\n      function (message = 'Must start with capital letter') {\n        return this.test('startsWithCapital', message, function (value: any) {\n          return value == null || /^[A-Z]/.test(value);\n        });\n      },\n    );\n\n    addMethod(\n      string,\n      'endsWithPeriod',\n      function (message = 'Must end with period') {\n        return this.test('endsWithPeriod', message, function (value: any) {\n          return value == null || value.endsWith('.');\n        });\n      },\n    );\n\n    // Add custom methods to number schema\n    addMethod(number, 'isEven', function (message = 'Must be an even number') {\n      return this.test('isEven', message, function (value: any) {\n        return value == null || value % 2 === 0;\n      });\n    });\n\n    addMethod(\n      number,\n      'isPositiveWhenDefined',\n      function (message = 'Must be positive when defined') {\n        return this.test(\n          'isPositiveWhenDefined',\n          message,\n          function (value: any) {\n            return value == null || value > 0;\n          },\n        );\n      },\n    );\n\n    // Add custom methods to object schema\n    addMethod(\n      object,\n      'hasRequiredFields',\n      function (fields: string[], message = 'Missing required fields') {\n        return this.test('hasRequiredFields', message, function (value: any) {\n          if (value == null) return true;\n          return fields.every((field) =>\n            Object.prototype.hasOwnProperty.call(value, field),\n          );\n        });\n      },\n    ); // Add custom methods to array schema\n    addMethod(\n      array,\n      'hasNoDuplicates',\n      function (message = 'Array must not contain duplicates') {\n        return this.test('hasNoDuplicates', message, function (value: any) {\n          if (value == null) return true;\n          return new Set(value).size === value.length;\n        });\n      },\n    );\n\n    // Add custom methods to mixed schema\n    addMethod(\n      mixed,\n      'isNotEmpty',\n      function (message = 'Value cannot be empty') {\n        return this.test('isNotEmpty', message, function (value: any) {\n          if (value == null) return false;\n          if (typeof value === 'string') return value.trim().length > 0;\n          if (Array.isArray(value)) return value.length > 0;\n          if (typeof value === 'object') return Object.keys(value).length > 0;\n          return true;\n        });\n      },\n    );\n  });\n\n  it('should maintain validation consistency with basic string addMethod', async () => {\n    const customStringSchema = (string().nullable() as any).isUpperCase();\n\n    const validValues = ['HELLO', 'WORLD', 'TEST', '', undefined, null];\n    const invalidValues = ['hello', 'Hello', 'HELLO world', 'test'];\n\n    for (const value of validValues) {\n      await expectValidationConsistency(customStringSchema, value, true);\n    }\n\n    for (const value of invalidValues) {\n      await expectValidationConsistency(\n        customStringSchema,\n        value,\n        false,\n        'Must be uppercase',\n      );\n    }\n  });\n\n  it('should maintain validation consistency with number addMethod', async () => {\n    const customNumberSchema = (number().nullable() as any).isEven();\n\n    const validValues = [2, 4, 6, 0, -2, undefined, null];\n    const invalidValues = [1, 3, 5, -1, 7.5];\n\n    for (const value of validValues) {\n      await expectValidationConsistency(customNumberSchema, value, true);\n    }\n\n    for (const value of invalidValues) {\n      await expectValidationConsistency(\n        customNumberSchema,\n        value,\n        false,\n        'Must be an even number',\n      );\n    }\n  });\n\n  it('should maintain validation consistency with object addMethod', async () => {\n    const customObjectSchema = (object().nullable() as any).hasRequiredFields([\n      'name',\n      'email',\n    ]);\n\n    const validValues = [\n      { name: 'John', email: 'john@example.com' },\n      { name: 'Jane', email: 'jane@example.com', age: 30 },\n      undefined,\n      null,\n    ];\n    const invalidValues = [\n      { name: 'John' },\n      { email: 'john@example.com' },\n      { age: 30 },\n      {},\n    ];\n\n    for (const value of validValues) {\n      await expectValidationConsistency(customObjectSchema, value, true);\n    }\n\n    for (const value of invalidValues) {\n      await expectValidationConsistency(\n        customObjectSchema,\n        value,\n        false,\n        'Missing required fields',\n      );\n    }\n  });\n\n  it('should maintain validation consistency with array addMethod', async () => {\n    const customArraySchema = (array().nullable() as any).hasNoDuplicates();\n\n    const validValues = [[1, 2, 3], ['a', 'b', 'c'], [], [1], undefined, null];\n    const invalidValues = [\n      [1, 2, 2],\n      ['a', 'b', 'a'],\n      [1, 1, 2, 3],\n    ];\n\n    for (const value of validValues) {\n      await expectValidationConsistency(customArraySchema, value, true);\n    }\n\n    for (const value of invalidValues) {\n      await expectValidationConsistency(\n        customArraySchema,\n        value,\n        false,\n        'Array must not contain duplicates',\n      );\n    }\n  });\n\n  it('should maintain validation consistency with chained addMethod', async () => {\n    const customStringSchema = (string().nullable() as any)\n      .startsWithCapital()\n      .endsWithPeriod();\n\n    const validValues = ['Hello world.', 'Test.', 'A.', undefined, null];\n    const invalidValues = ['hello world.', 'Test', 'Hello world', 'a.'];\n\n    for (const value of validValues) {\n      await expectValidationConsistency(customStringSchema, value, true);\n    }\n\n    for (const value of invalidValues) {\n      await expectValidationConsistency(customStringSchema, value, false);\n    }\n  });\n\n  it('should maintain validation consistency with parameterized addMethod', async () => {\n    const customStringSchema = (string().nullable() as any).hasMinWords(3);\n\n    const validValues = [\n      'hello world test',\n      'one two three',\n      'a b c d',\n      undefined,\n      null,\n    ];\n    const invalidValues = ['hello', 'hello world', '', '  '];\n\n    for (const value of validValues) {\n      await expectValidationConsistency(customStringSchema, value, true);\n    }\n\n    for (const value of invalidValues) {\n      await expectValidationConsistency(\n        customStringSchema,\n        value,\n        false,\n        'Must have at least 3 words',\n      );\n    }\n  });\n\n  it('should maintain validation consistency with addMethod on mixed schema', async () => {\n    const customMixedSchema = (mixed().nullable() as any).isNotEmpty();\n\n    const validValues = ['hello', 123, [1, 2], { a: 1 }, true];\n    const invalidValues = ['', '  ', [], {}, null, undefined];\n\n    for (const value of validValues) {\n      await expectValidationConsistency(customMixedSchema, value, true);\n    }\n\n    for (const value of invalidValues) {\n      await expectValidationConsistency(\n        customMixedSchema,\n        value,\n        false,\n        'Value cannot be empty',\n      );\n    }\n  });\n\n  it('should maintain validation consistency with addMethod and conditional logic', async () => {\n    const customNumberSchema = (\n      number().nullable() as any\n    ).isPositiveWhenDefined();\n\n    // Test without conditional logic first\n    const validValues = [1, 5.5, 100, undefined, null];\n    const invalidValues = [0, -1, -5.5];\n\n    for (const value of validValues) {\n      await expectValidationConsistency(customNumberSchema, value, true);\n    }\n\n    for (const value of invalidValues) {\n      await expectValidationConsistency(\n        customNumberSchema,\n        value,\n        false,\n        'Must be positive when defined',\n      );\n    }\n  });\n\n  it('should maintain validation consistency with multiple custom methods', async () => {\n    const complexSchema = (string().nullable() as any)\n      .isUpperCase('Must be uppercase')\n      .hasMinWords(2, 'Must have at least 2 words');\n\n    const validValues = ['HELLO WORLD', 'TEST CASE', 'A B', undefined, null];\n    const invalidValues = [\n      'hello world', // not uppercase\n      'HELLO', // not enough words\n      'hello', // both violations\n      '', // not enough words\n      'HELLO world', // not uppercase\n    ];\n\n    for (const value of validValues) {\n      await expectValidationConsistency(complexSchema, value, true);\n    }\n\n    for (const value of invalidValues) {\n      await expectValidationConsistency(complexSchema, value, false);\n    }\n  });\n\n  it('should maintain validation consistency with addMethod cast behavior', async () => {\n    // Test that custom methods work with casting\n    const customStringSchema = (string().nullable() as any).isUpperCase();\n\n    // Test casting behavior\n    expect(customStringSchema.cast(123)).toBe('123');\n    expect(customStringSchema.cast(true)).toBe('true');\n\n    // Test that casting works correctly with validation\n    const castValue = customStringSchema.cast('TEST');\n    expect(castValue).toBe('TEST');\n    await expectValidationConsistency(customStringSchema, 'TEST', true);\n\n    // Test that non-uppercase strings still fail validation even after casting\n    const nonUpperCase = customStringSchema.cast('hello');\n    expect(nonUpperCase).toBe('hello');\n    await expectValidationConsistency(\n      customStringSchema,\n      'hello',\n      false,\n      'Must be uppercase',\n    );\n  });\n});\n"
  },
  {
    "path": "test/string.ts",
    "content": "import { describe, it, expect, assert } from 'vitest';\nimport * as TestHelpers from './helpers';\n\nimport {\n  string,\n  number,\n  object,\n  ref,\n  ValidationError,\n  AnySchema,\n} from '../src';\n\ndescribe('String types', () => {\n  describe('casting', () => {\n    let schema = string();\n\n    TestHelpers.castAll(schema, {\n      valid: [\n        [5, '5'],\n        ['3', '3'],\n        // [new String('foo'), 'foo'],\n        ['', ''],\n        [true, 'true'],\n        [false, 'false'],\n        [0, '0'],\n        [null, null, schema.nullable()],\n        [\n          {\n            toString: () => 'hey',\n          },\n          'hey',\n        ],\n      ],\n      invalid: [null, {}, []],\n    });\n\n    describe('ensure', () => {\n      let schema = string().ensure();\n\n      TestHelpers.castAll(schema, {\n        valid: [\n          [5, '5'],\n          ['3', '3'],\n          [null, ''],\n          [undefined, ''],\n          [null, '', schema.default('foo')],\n          [undefined, 'foo', schema.default('foo')],\n        ],\n      });\n    });\n\n    it('should trim', () => {\n      expect(schema.trim().cast(' 3  ')).toBe('3');\n    });\n\n    it('should transform to lowercase', () => {\n      expect(schema.lowercase().cast('HellO JohN')).toBe('hello john');\n    });\n\n    it('should transform to uppercase', () => {\n      expect(schema.uppercase().cast('HellO JohN')).toBe('HELLO JOHN');\n    });\n\n    it('should handle nulls', () => {\n      expect(\n        schema.nullable().trim().lowercase().uppercase().cast(null),\n      ).toBeNull();\n    });\n  });\n\n  it('should handle DEFAULT', function () {\n    let inst = string();\n\n    expect(inst.default('my_value').required().getDefault()).toBe('my_value');\n  });\n\n  it('should type check', function () {\n    let inst = string();\n\n    expect(inst.isType('5')).toBe(true);\n    expect(inst.isType(new String('5'))).toBe(true);\n    expect(inst.isType(false)).toBe(false);\n    expect(inst.isType(null)).toBe(false);\n    expect(inst.nullable().isType(null)).toBe(true);\n  });\n\n  it('should VALIDATE correctly', function () {\n    let inst = string().required().min(4).strict();\n\n    return Promise.all([\n      expect(string().strict().isValid(null)).resolves.toBe(false),\n\n      expect(string().strict().nullable().isValid(null)).resolves.toBe(true),\n\n      expect(inst.isValid('hello')).resolves.toBe(true),\n\n      expect(inst.isValid('hel')).resolves.toBe(false),\n\n      expect(inst.validate('')).rejects.toEqual(\n        TestHelpers.validationErrorWithMessages(expect.any(String)),\n      ),\n    ]);\n  });\n\n  it('should handle NOTREQUIRED correctly', function () {\n    let v = string().required().notRequired();\n\n    return Promise.all([\n      expect(v.isValid(undefined)).resolves.toBe(true),\n      expect(v.isValid('')).resolves.toBe(true),\n    ]);\n  });\n\n  it('should check MATCHES correctly', function () {\n    let v = string().matches(/(hi|bye)/, 'A message');\n\n    return Promise.all([\n      expect(v.isValid('hi')).resolves.toBe(true),\n      expect(v.isValid('nope')).resolves.toBe(false),\n      expect(v.isValid('bye')).resolves.toBe(true),\n    ]);\n  });\n\n  it('should check MATCHES correctly with global and sticky flags', function () {\n    let v = string().matches(/hi/gy);\n\n    return Promise.all([\n      expect(v.isValid('hi')).resolves.toBe(true),\n      expect(v.isValid('hi')).resolves.toBe(true),\n    ]);\n  });\n\n  it('MATCHES should include empty strings', () => {\n    let v = string().matches(/(hi|bye)/);\n\n    return expect(v.isValid('')).resolves.toBe(false);\n  });\n\n  it('MATCHES should exclude empty strings', () => {\n    let v = string().matches(/(hi|bye)/, { excludeEmptyString: true });\n\n    return expect(v.isValid('')).resolves.toBe(true);\n  });\n\n  it('EMAIL should exclude empty strings', () => {\n    let v = string().email();\n\n    return expect(v.isValid('')).resolves.toBe(true);\n  });\n\n  it('should check MIN correctly', function () {\n    let v = string().min(5);\n    let obj = object({\n      len: number(),\n      name: string().min(ref('len')),\n    });\n\n    return Promise.all([\n      expect(v.isValid('hiiofff')).resolves.toBe(true),\n      expect(v.isValid('big')).resolves.toBe(false),\n      expect(v.isValid('noffasfasfasf saf')).resolves.toBe(true),\n\n      expect(v.isValid(null)).resolves.toBe(false),\n      expect(v.nullable().isValid(null)).resolves.toBe(true),\n\n      expect(obj.isValid({ len: 10, name: 'john' })).resolves.toBe(false),\n    ]);\n  });\n\n  it('should check MAX correctly', function () {\n    let v = string().max(5);\n    let obj = object({\n      len: number(),\n      name: string().max(ref('len')),\n    });\n    return Promise.all([\n      expect(v.isValid('adgf')).resolves.toBe(true),\n      expect(v.isValid('bigdfdsfsdf')).resolves.toBe(false),\n      expect(v.isValid('no')).resolves.toBe(true),\n\n      expect(v.isValid(null)).resolves.toBe(false),\n\n      expect(v.nullable().isValid(null)).resolves.toBe(true),\n\n      expect(obj.isValid({ len: 3, name: 'john' })).resolves.toBe(false),\n    ]);\n  });\n\n  it('should check LENGTH correctly', function () {\n    let v = string().length(5);\n    let obj = object({\n      len: number(),\n      name: string().length(ref('len')),\n    });\n\n    return Promise.all([\n      expect(v.isValid('exact')).resolves.toBe(true),\n      expect(v.isValid('sml')).resolves.toBe(false),\n      expect(v.isValid('biiiig')).resolves.toBe(false),\n\n      expect(v.isValid(null)).resolves.toBe(false),\n      expect(v.nullable().isValid(null)).resolves.toBe(true),\n\n      expect(obj.isValid({ len: 5, name: 'foo' })).resolves.toBe(false),\n    ]);\n  });\n\n  it('should check url correctly', function () {\n    let v = string().url();\n\n    return Promise.all([\n      expect(v.isValid('//www.github.com/')).resolves.toBe(true),\n      expect(v.isValid('https://www.github.com/')).resolves.toBe(true),\n      expect(v.isValid('this is not a url')).resolves.toBe(false),\n    ]);\n  });\n\n  it('should check UUID correctly', function () {\n    let v = string().uuid();\n\n    return Promise.all([\n      expect(v.isValid('0c40428c-d88d-4ff0-a5dc-a6755cb4f4d1')).resolves.toBe(\n        true,\n      ),\n      expect(v.isValid('42c4a747-3e3e-42be-af30-469cfb9c1913')).resolves.toBe(\n        true,\n      ),\n      expect(v.isValid('42c4a747-3e3e-zzzz-af30-469cfb9c1913')).resolves.toBe(\n        false,\n      ),\n      expect(v.isValid('this is not a uuid')).resolves.toBe(false),\n      expect(v.isValid('')).resolves.toBe(false),\n    ]);\n  });\n\n  describe('DATETIME', function () {\n    it('should check DATETIME correctly', function () {\n      let v = string().datetime();\n\n      return Promise.all([\n        expect(v.isValid('2023-01-09T12:34:56Z')).resolves.toBe(true),\n        expect(v.isValid('1977-00-28T12:34:56.0Z')).resolves.toBe(true),\n        expect(v.isValid('1900-10-29T12:34:56.00Z')).resolves.toBe(true),\n        expect(v.isValid('1000-11-30T12:34:56.000Z')).resolves.toBe(true),\n        expect(v.isValid('4444-12-31T12:34:56.0000Z')).resolves.toBe(true),\n\n        // Should not allow time zone offset by default\n        expect(v.isValid('2010-04-10T14:06:14+00:00')).resolves.toBe(false),\n        expect(v.isValid('2000-07-11T21:06:14+07:00')).resolves.toBe(false),\n        expect(v.isValid('1999-08-16T07:06:14-07:00')).resolves.toBe(false),\n\n        expect(v.isValid('this is not a datetime')).resolves.toBe(false),\n        expect(v.isValid('2023-08-16T12:34:56')).resolves.toBe(false),\n        expect(v.isValid('2023-08-1612:34:56Z')).resolves.toBe(false),\n        expect(v.isValid('1970-01-01 00:00:00Z')).resolves.toBe(false),\n        expect(v.isValid('1970-01-01T00:00:00,000Z')).resolves.toBe(false),\n        expect(v.isValid('1970-01-01T0000')).resolves.toBe(false),\n        expect(v.isValid('1970-01-01T00:00.000')).resolves.toBe(false),\n        expect(v.isValid('2023-01-09T12:34:56.Z')).resolves.toBe(false),\n        expect(v.isValid('2023-08-16')).resolves.toBe(false),\n        expect(v.isValid('1970-as-df')).resolves.toBe(false),\n        expect(v.isValid('19700101')).resolves.toBe(false),\n        expect(v.isValid('197001')).resolves.toBe(false),\n      ]);\n    });\n\n    it('should support DATETIME allowOffset option', function () {\n      let v = string().datetime({ allowOffset: true });\n\n      return Promise.all([\n        expect(v.isValid('2023-01-09T12:34:56Z')).resolves.toBe(true),\n        expect(v.isValid('2010-04-10T14:06:14+00:00')).resolves.toBe(true),\n        expect(v.isValid('2000-07-11T21:06:14+07:00')).resolves.toBe(true),\n        expect(v.isValid('1999-08-16T07:06:14-07:00')).resolves.toBe(true),\n        expect(v.isValid('1970-01-01T00:00:00+0630')).resolves.toBe(true),\n      ]);\n    });\n\n    it('should support DATETIME precision option', function () {\n      let v = string().datetime({ precision: 4 });\n\n      return Promise.all([\n        expect(v.isValid('2023-01-09T12:34:56.0000Z')).resolves.toBe(true),\n        expect(v.isValid('2023-01-09T12:34:56.00000Z')).resolves.toBe(false),\n        expect(v.isValid('2023-01-09T12:34:56.000Z')).resolves.toBe(false),\n        expect(v.isValid('2023-01-09T12:34:56.00Z')).resolves.toBe(false),\n        expect(v.isValid('2023-01-09T12:34:56.0Z')).resolves.toBe(false),\n        expect(v.isValid('2023-01-09T12:34:56.Z')).resolves.toBe(false),\n        expect(v.isValid('2023-01-09T12:34:56Z')).resolves.toBe(false),\n        expect(v.isValid('2010-04-10T14:06:14.0000+00:00')).resolves.toBe(\n          false,\n        ),\n      ]);\n    });\n\n    describe('DATETIME error strings', function () {\n      function getErrorString(schema: AnySchema, value: string) {\n        try {\n          schema.validateSync(value);\n          assert.fail('should have thrown validation error');\n        } catch (e) {\n          const err = e as ValidationError;\n          return err.errors[0];\n        }\n      }\n\n      it('should use the default locale string on error', function () {\n        let v = string().datetime();\n        expect(getErrorString(v, 'asdf')).toBe(\n          'this must be a valid ISO date-time',\n        );\n      });\n\n      it('should use the allowOffset locale string on error when offset caused error', function () {\n        let v = string().datetime();\n        expect(getErrorString(v, '2010-04-10T14:06:14+00:00')).toBe(\n          'this must be a valid ISO date-time with UTC \"Z\" timezone',\n        );\n      });\n\n      it('should use the precision locale string on error when precision caused error', function () {\n        let v = string().datetime({ precision: 2 });\n        expect(getErrorString(v, '2023-01-09T12:34:56Z')).toBe(\n          'this must be a valid ISO date-time with a sub-second precision of exactly 2 digits',\n        );\n      });\n\n      it('should prefer options.message over all default error messages', function () {\n        let msg = 'hello';\n        let v = string().datetime({ message: msg });\n        expect(getErrorString(v, 'asdf')).toBe(msg);\n        expect(getErrorString(v, '2010-04-10T14:06:14+00:00')).toBe(msg);\n\n        v = string().datetime({ message: msg, precision: 2 });\n        expect(getErrorString(v, '2023-01-09T12:34:56Z')).toBe(msg);\n      });\n    });\n  });\n\n  // eslint-disable-next-line jest/no-disabled-tests\n  it.skip('should check allowed values at the end', () => {\n    return Promise.all([\n      expect(\n        string()\n          .required('Required')\n          .notOneOf([ref('$someKey')])\n          .validate('', { context: { someKey: '' } }),\n      ).rejects.toEqual(\n        TestHelpers.validationErrorWithMessages(\n          expect.stringContaining('Ref($someKey)'),\n        ),\n      ),\n      expect(\n        object({\n          email: string().required('Email Required'),\n          password: string()\n            .required('Password Required')\n            .notOneOf([ref('email')]),\n        })\n          .validate({ email: '', password: '' }, { abortEarly: false })\n          .catch(console.log),\n      ).rejects.toEqual(\n        TestHelpers.validationErrorWithMessages(\n          expect.stringContaining('Email Required'),\n          expect.stringContaining('Password Required'),\n        ),\n      ),\n    ]);\n  });\n\n  it('should validate transforms', function () {\n    return Promise.all([\n      expect(string().trim().isValid(' 3  ')).resolves.toBe(true),\n\n      expect(string().lowercase().isValid('HellO JohN')).resolves.toBe(true),\n\n      expect(string().uppercase().isValid('HellO JohN')).resolves.toBe(true),\n\n      expect(string().trim().isValid(' 3  ', { strict: true })).resolves.toBe(\n        false,\n      ),\n\n      expect(\n        string().lowercase().isValid('HellO JohN', { strict: true }),\n      ).resolves.toBe(false),\n\n      expect(\n        string().uppercase().isValid('HellO JohN', { strict: true }),\n      ).resolves.toBe(false),\n    ]);\n  });\n});\n"
  },
  {
    "path": "test/tsconfig.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"noEmit\": true,\n    \"noImplicitAny\": true,\n    \"types\": [\"node\"],\n    \"rootDir\": \"../\"\n  },\n  \"include\": [\"../src\", \".\"]\n}\n"
  },
  {
    "path": "test/tuple.ts",
    "content": "import { describe, it, expect, test } from 'vitest';\nimport { string, number, object, tuple, mixed } from '../src';\n\ndescribe('Array types', () => {\n  describe('casting', () => {\n    it('should failed casts return input', () => {\n      expect(\n        tuple([number(), number()]).cast('asfasf', { assert: false }),\n      ).toEqual('asfasf');\n    });\n\n    it('should recursively cast fields', () => {\n      expect(tuple([number(), number()]).cast(['4', '5'])).toEqual([4, 5]);\n\n      expect(\n        tuple([string(), string(), string()]).cast(['4', 5, false]),\n      ).toEqual(['4', '5', 'false']);\n    });\n\n    it('should pass array options to descendants when casting', async () => {\n      let value = ['1', '2'];\n  \n      let itemSchema = string().when([], function (_, _s, opts: any) {\n  \n        const parent = opts.parent;\n        const idx = opts.index;\n        const val = opts.value;\n        const originalValue = opts.originalValue;\n        \n        expect(parent).toEqual(value);\n        expect(typeof idx).toBe('number');\n        expect(val).toEqual(parent[idx]);\n        expect(originalValue).toEqual(parent[idx]);\n  \n        return string();\n      });\n\n      await tuple([itemSchema, itemSchema]).validate(value);\n    });\n  });\n\n  it('should handle DEFAULT', () => {\n    expect(tuple([number(), number(), number()]).getDefault()).toBeUndefined();\n\n    expect(\n      tuple([number(), number(), number()])\n        .default(() => [1, 2, 3])\n        .getDefault(),\n    ).toEqual([1, 2, 3]);\n  });\n\n  it('should type check', () => {\n    let inst = tuple([number()]);\n\n    expect(inst.isType([1])).toBe(true);\n    expect(inst.isType({})).toBe(false);\n    expect(inst.isType('true')).toBe(false);\n    expect(inst.isType(NaN)).toBe(false);\n    expect(inst.isType(34545)).toBe(false);\n\n    expect(inst.isType(null)).toBe(false);\n\n    expect(inst.nullable().isType(null)).toBe(true);\n  });\n\n  it('should pass options to children', () => {\n    expect(\n      tuple([object({ name: string() })]).cast([{ id: 1, name: 'john' }], {\n        stripUnknown: true,\n      }),\n    ).toEqual([{ name: 'john' }]);\n  });\n\n  describe('validation', () => {\n    test.each([\n      ['required', undefined, tuple([mixed()]).required()],\n      ['required', null, tuple([mixed()]).required()],\n      ['null', null, tuple([mixed()])],\n    ])('Basic validations fail: %s %p', async (_, value, schema) => {\n      expect(await schema.isValid(value)).toBe(false);\n    });\n\n    test.each([\n      ['required', ['any'], tuple([mixed()]).required()],\n      ['nullable', null, tuple([mixed()]).nullable()],\n    ])('Basic validations pass: %s %p', async (_, value, schema) => {\n      expect(await schema.isValid(value)).toBe(true);\n    });\n\n    it('should allow undefined', async () => {\n      await expect(\n        tuple([number().defined()]).isValid(undefined),\n      ).resolves.toBe(true);\n    });\n\n    it('should respect subtype validations', async () => {\n      let inst = tuple([number().max(5), string()]);\n\n      await expect(inst.isValid(['gg', 'any'])).resolves.toBe(false);\n      await expect(inst.isValid([7, 3])).resolves.toBe(false);\n\n      expect(await inst.validate(['4', 3])).toEqual([4, '3']);\n    });\n\n    it('should use labels', async () => {\n      let schema = tuple([\n        string().label('name'),\n        number().positive().integer().label('age'),\n      ]);\n\n      await expect(schema.validate(['James', -24.55])).rejects.toThrow(\n        'age must be a positive number',\n      );\n    });\n\n    it('should throw useful type error for length', async () => {\n      let schema = tuple([string().label('name'), number().label('age')]);\n\n      await expect(schema.validate(['James'])).rejects.toThrowError(\n        'this tuple value has too few items, expected a length of 2 but got 1 for value',\n      );\n\n      await expect(schema.validate(['James', 2, 4])).rejects.toThrowError(\n        'this tuple value has too many items, expected a length of 2 but got 3 for value',\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "test/types/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    tsconfigRootDir: __dirname,\n    project: ['../tsconfig.json'],\n  },\n  plugins: ['ts-expect'],\n  rules: {\n    'ts-expect/expect': 'error',\n  },\n};\n"
  },
  {
    "path": "test/types/types.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unused-expressions */\n/* eslint-disable no-unused-labels */\nimport {\n  array,\n  number,\n  string,\n  date,\n  ref,\n  mixed,\n  bool,\n  reach,\n  addMethod,\n  Schema,\n} from '../../src';\nimport { create as tuple } from '../../src/tuple';\nimport { create as lazy } from '../../src/Lazy';\nimport ObjectSchema, { create as object } from '../../src/object';\n\nimport { ResolveFlags, SetFlag, UnsetFlag, _ } from '../../src/util/types';\n\nResolveFlags: {\n  // $ExpectType string | undefined\n  type _a = ResolveFlags<string | undefined, 'd'>;\n\n  // $ExpectType string | undefined\n  type _b = ResolveFlags<string | undefined, 's'>;\n\n  // $ExpectType string\n  type _c = ResolveFlags<string | undefined, 's' | 'd', string>;\n\n  // $ExpectType string | undefined\n  type _d = ResolveFlags<string | undefined, 's' | '', string>;\n\n  // $ExpectType string\n  type _e = ResolveFlags<string | undefined, SetFlag<'s', 'd'>, string>;\n\n  // $ExpectType \"\"\n  type _f = UnsetFlag<'d', 'd'>;\n\n  // $ExpectType \"s\"\n  type _f2 = UnsetFlag<'d' | 's', 'd'>;\n\n  // $ExpectType \"\"\n  type _f3 = UnsetFlag<'', 'd'>;\n\n  // $ExpectType \"d\"\n  type _f4 = SetFlag<'', 'd'>;\n}\n\nBase_methods: {\n  // $ExpectType boolean | undefined\n  bool().oneOf([true, ref('$foo')]).__outputType;\n\n  // $ExpectType \"asf\" | \"foo\" | undefined\n  string().oneOf(['asf', ref<'foo'>('$foo')]).__outputType;\n\n  // $ExpectType Date | undefined\n  date().oneOf([new Date(), ref('$now')]).__outputType;\n\n  // $ExpectType number | undefined\n  number().oneOf([1, ref('$foo')]).__outputType;\n\n  // type s = StringSchema<string | undefined, any, '', 's' | 'd'>;\n\n  // type ss = s['__outputType'];\n}\n\nMixed: {\n  const mxRequired = mixed<string | number>().required();\n\n  // $ExpectType NonNullable<string | number | undefined>\n  mxRequired.cast(undefined);\n\n  // $ExpectType NonNullable<string | number | undefined> | null\n  mxRequired.nullable().cast(undefined);\n\n  // $ExpectType NonNullable<string | number | undefined>\n  mxRequired.nullable().nonNullable().cast(undefined);\n\n  //\n  const mxOptional = mixed<string>().optional();\n\n  // $ExpectType string | undefined\n  mxOptional.cast(undefined);\n\n  // $ExpectType string\n  mxOptional.defined().cast(undefined);\n\n  //\n  const mxNullableOptional = mixed<string>().nullable().optional();\n\n  // $ExpectType string | null | undefined\n  mxNullableOptional.cast('');\n\n  // $ExpectType string\n  mxNullableOptional.required().validateSync('');\n\n  //\n  const mxNullable = mixed<string>().nullable();\n\n  // $ExpectType string | null | undefined\n  mxNullable.validateSync('');\n\n  const mxDefined = mixed<string>().default('');\n\n  // $ExpectType \"\"\n  mxDefined.getDefault();\n\n  const mxDefault = mixed<string>().nullable().default('').nullable();\n\n  // $ExpectType string | null\n  mxDefault.cast('');\n\n  // $ExpectType string | null\n  mxDefault.validateSync('');\n\n  // $ExpectType MixedSchema<string, AnyObject, \"\", \"d\">\n  const mxDefaultRequired = mixed<string>().nullable().required().default('');\n\n  // $ExpectType string\n  mxDefaultRequired.cast('');\n\n  // $ExpectType string\n  mxDefaultRequired.validateSync(null);\n\n  // $ExpectType \"foo\" | \"bar\"\n  string<'foo' | 'bar'>().defined().validateSync('foo');\n\n  // $ExpectType string | undefined\n  mixed<string>().strip().cast(undefined);\n\n  // $ExpectType string | undefined\n  mixed<string>().strip().strip(false).cast(undefined);\n\n  // $ExpectType string | undefined\n  mixed<string>().optional().concat(mixed<string>()).cast('');\n\n  // $ExpectType string\n  mixed<string>().optional().concat(mixed<string>().defined()).cast('');\n\n  // $ExpectType string | undefined\n  mixed<string>().nullable().concat(mixed<string>()).cast('');\n\n  // $ExpectType string | null | undefined\n  mixed<string>()\n    .nullable()\n    .concat(mixed<string>().optional().nullable())\n    .cast('');\n\n  // $ExpectType \"foo\" | undefined\n  mixed<string>().notRequired().concat(string<'foo'>()).cast('');\n\n  // $ExpectType MixedSchema<string | undefined, AnyObject, undefined, \"\">\n  mixed((value): value is string => typeof value === 'string');\n\n  // $ExpectType MixedSchema<string | undefined, AnyObject, undefined, \"\">\n  mixed({\n    type: 'string',\n    check: (value): value is string => typeof value === 'string',\n  });\n\n  // $ExpectType string\n  mixed<string>().defined().cast('', { assert: true });\n\n  // $ExpectType string | null | undefined\n  mixed<string>().defined().cast('', { assert: 'ignore-optionality' });\n\n  // $ExpectType AnyPresentValue | null\n  mixed().defined().nullable().cast('');\n}\n\nStrings: {\n  const strRequired = string().required();\n\n  // $ExpectType string\n  strRequired.cast(undefined);\n\n  // $ExpectType string | null\n  strRequired.nullable().cast(undefined);\n\n  // $ExpectType string\n  strRequired.nullable().nonNullable().cast(undefined);\n\n  //\n  const strOptional = string().optional();\n\n  // $ExpectType string | undefined\n  strOptional.cast(undefined);\n\n  // $ExpectType string\n  strOptional.defined().cast(undefined);\n\n  //\n  const strNullableOptional = string().nullable().optional();\n\n  // $ExpectType string | null | undefined\n  strNullableOptional.cast('');\n\n  // $ExpectType string\n  strNullableOptional.required().validateSync('');\n\n  //\n  const strNullable = string().nullable();\n\n  // $ExpectType string | null | undefined\n  strNullable.validateSync('');\n\n  const strDefined = string().default('');\n\n  // $ExpectType \"\"\n  strDefined.getDefault();\n\n  const strDefault = string().nullable().default('').nullable().trim();\n\n  // $ExpectType string | null\n  strDefault.cast('');\n\n  // $ExpectType string | null\n  strDefault.validateSync('');\n\n  // $ExpectType StringSchema<string, AnyObject, \"\", \"d\">\n  const strDefaultRequired = string().nullable().required().default('').trim();\n\n  // $ExpectType string\n  strDefaultRequired.cast('');\n\n  // $ExpectType string\n  strDefaultRequired.validateSync(null);\n\n  // $ExpectType \"foo\" | \"bar\"\n  string<'foo' | 'bar'>().defined().validateSync('foo');\n\n  // $ExpectType string | undefined\n  string().strip().cast(undefined);\n\n  // $ExpectType string | undefined\n  string().strip().strip(false).cast(undefined);\n\n  // $ExpectType string | undefined\n  string().optional().concat(string()).cast('');\n\n  // $ExpectType string\n  string().optional().concat(string().defined()).cast('');\n\n  // $ExpectType string | undefined\n  string().nullable().concat(string()).cast('');\n\n  // $ExpectType string | null | undefined\n  string().nullable().concat(string().optional().nullable()).cast('');\n\n  // $ExpectType \"foo\" | undefined\n  string().notRequired().concat(string<'foo'>()).cast('');\n\n  // $ExpectType \"foo\" | null\n  string<'foo'>()\n    .notRequired()\n    .concat(string().nullable().default('bar'))\n    .cast('');\n\n  // $ExpectType never\n  string<'bar'>().concat(string<'foo'>().defined()).cast('');\n\n  // $ExpectType never\n  string<'bar'>().concat(string<'foo'>()).cast('');\n\n  // $ExpectType \"foo\" | \"bar\" | undefined\n  string().oneOf(['foo', 'bar']).__outputType;\n\n  // $ExpectType \"foo\" | \"bar\" | null | undefined\n  string().nullable().oneOf(['foo', 'bar']).__outputType;\n}\n\nNumbers: {\n  const numRequired = number().required();\n\n  // $ExpectType number\n  numRequired.cast(undefined);\n\n  // $ExpectType number | null\n  numRequired.nullable().cast(undefined);\n\n  // $ExpectType number\n  numRequired.nullable().nonNullable().cast(undefined);\n\n  //\n  const numOptional = number().optional();\n\n  // $ExpectType number | undefined\n  numOptional.cast(undefined);\n\n  // $ExpectType number\n  numOptional.defined().cast(undefined);\n\n  //\n  const numNullableOptional = number().nullable().optional();\n\n  // $ExpectType number | null | undefined\n  numNullableOptional.cast('');\n\n  // $ExpectType number\n  numNullableOptional.required().validateSync('');\n\n  //\n  //\n  const numNullable = number().nullable();\n\n  // $ExpectType number | null | undefined\n  numNullable.validateSync('');\n\n  const numDefined = number().default(3);\n\n  // $ExpectType 3\n  numDefined.getDefault();\n\n  const numDefault = number().nullable().default(3).nullable().min(2);\n\n  // $ExpectType number | null\n  numDefault.cast('');\n\n  // $ExpectType number | null\n  numDefault.validateSync('');\n\n  //\n  const numDefaultRequired = number().nullable().required().default(3);\n\n  // $ExpectType number\n  numDefaultRequired.cast('');\n\n  // $ExpectType number\n  numDefaultRequired.validateSync(null);\n\n  // $ExpectType number | undefined\n  number().strip().cast(undefined);\n\n  // $ExpectType number | undefined\n  number().strip().strip(false).cast(undefined);\n\n  // $ExpectType 1 | undefined\n  number().notRequired().concat(number<1>()).cast('');\n\n  // $ExpectType 1 | null\n  number<1>().notRequired().concat(number().nullable().default(2)).cast('');\n\n  // $ExpectType never\n  number<2>().concat(number<1>().defined()).cast('');\n\n  // $ExpectType never\n  number<2>().concat(number<1>()).cast('');\n}\n\ndate: {\n  const dtRequired = date().required();\n\n  // $ExpectType Date\n  dtRequired.cast(undefined);\n\n  // $ExpectType Date | null\n  dtRequired.nullable().cast(undefined);\n\n  // $ExpectType Date\n  dtRequired.nullable().nonNullable().cast(undefined);\n\n  //\n  const dtOptional = date().optional();\n\n  // $ExpectType Date | undefined\n  dtOptional.cast(undefined);\n\n  // $ExpectType Date\n  dtOptional.defined().cast(undefined);\n\n  //\n  const dtNullableOptional = date().nullable().optional();\n\n  // $ExpectType Date | null | undefined\n  dtNullableOptional.cast('');\n\n  // $ExpectType Date\n  dtNullableOptional.required().validateSync('');\n\n  //\n  //\n  const dtNullable = date().nullable();\n\n  // $ExpectType Date | null | undefined\n  dtNullable.validateSync('');\n\n  const dtDefined = date().default(() => new Date());\n\n  // $ExpectType Date\n  const _dtDefined = dtDefined.getDefault();\n\n  const dtDefault = date()\n    .nullable()\n    .default(() => new Date())\n    .nullable()\n    .min(new Date());\n\n  // $ExpectType Date | null\n  dtDefault.cast('');\n\n  // $ExpectType Date | null\n  dtDefault.validateSync('');\n\n  //\n  const dtDefaultRequired = date()\n    .nullable()\n    .required()\n    .default(() => new Date());\n\n  // $ExpectType Date\n  dtDefaultRequired.cast('');\n\n  // $ExpectType Date\n  dtDefaultRequired.validateSync(null);\n\n  // $ExpectType Date | undefined\n  date().strip().cast(undefined);\n\n  // $ExpectType Date | undefined\n  date().strip().strip(false).cast(undefined);\n}\n\nbool: {\n  const blRequired = bool().required();\n\n  // $ExpectType NonNullable<boolean | undefined>\n  blRequired.cast(undefined);\n\n  // $ExpectType NonNullable<boolean | undefined> | null\n  blRequired.nullable().cast(undefined);\n\n  // $ExpectType NonNullable<boolean | undefined>\n  blRequired.nullable().nonNullable().cast(undefined);\n\n  //\n  const blOptional = bool().optional();\n\n  // $ExpectType boolean | undefined\n  blOptional.cast(undefined);\n\n  // $ExpectType boolean\n  blOptional.defined().cast(undefined);\n\n  //\n  const blNullableOptional = bool().nullable().optional();\n\n  // $ExpectType boolean | null | undefined\n  blNullableOptional.cast('');\n\n  // $ExpectType NonNullable<boolean | null | undefined>\n  blNullableOptional.required().validateSync('');\n\n  //\n  //\n  const blNullable = bool().nullable();\n\n  // $ExpectType boolean | null | undefined\n  blNullable.validateSync('');\n\n  const blDefined = bool().default(false);\n\n  // $ExpectType false\n  blDefined.getDefault();\n\n  // $ExpectType false | undefined\n  bool().isFalse().cast(undefined);\n\n  // $ExpectType true | undefined\n  bool().isTrue().cast(undefined);\n\n  const blDefault = bool().nullable().default(true).nullable();\n\n  // $ExpectType boolean | null\n  blDefault.cast('');\n\n  // $ExpectType boolean | null\n  blDefault.validateSync('');\n\n  //\n  const blDefaultRequired = bool().nullable().required().default(true);\n\n  // $ExpectType NonNullable<boolean | null | undefined>\n  blDefaultRequired.cast('');\n\n  // $ExpectType NonNullable<boolean | null | undefined>\n  blDefaultRequired.validateSync(null);\n\n  // $ExpectType boolean | undefined\n  bool().strip().cast(undefined);\n\n  // $ExpectType boolean | undefined\n  bool().strip().strip(false).cast(undefined);\n}\n\nLazy: {\n  const l = lazy(() => string().default('asfasf'));\n\n  // $ExpectType string\n  l.cast(null);\n\n  const l2 = lazy((v) =>\n    v ? string().default('asfasf') : number().required(),\n  );\n\n  // $ExpectType string | number\n  l2.cast(null);\n}\n\nArray: {\n  const arrRequired = array().required();\n\n  // $ExpectType any[]\n  arrRequired.cast(undefined);\n\n  // $ExpectType any[] | null\n  arrRequired.nullable().cast(undefined);\n\n  // $ExpectType any[]\n  arrRequired.nullable().nonNullable().cast(undefined);\n\n  //\n  const arrOptional = array().optional();\n\n  // $ExpectType any[] | undefined\n  arrOptional.cast(undefined);\n\n  // $ExpectType any[]\n  arrOptional.defined().cast(undefined);\n\n  //\n  const arrNullableOptional = array().nullable().optional();\n\n  // $ExpectType any[] | null | undefined\n  arrNullableOptional.cast('');\n\n  // $ExpectType any[]\n  arrNullableOptional.required().validateSync('');\n\n  //\n  //\n  const arrNullable = array().nullable();\n\n  // $ExpectType any[] | null | undefined\n  arrNullable.validateSync('');\n\n  const arrDefined = array().default(() => [] as unknown[]);\n\n  // $ExpectType unknown[]\n  arrDefined.getDefault();\n\n  const arrDefault = array()\n    .optional()\n    .default(() => [] as unknown[])\n    .nullable()\n    .min(1);\n\n  // $ExpectType any[] | null\n  arrDefault.cast('');\n\n  // $ExpectType any[] | null\n  arrDefault.validateSync('');\n\n  //\n  const arrDefaultRequired = array()\n    .nullable()\n    .required()\n    .default(() => [] as unknown[]);\n\n  // $ExpectType any[]\n  arrDefaultRequired.cast('');\n\n  // $ExpectType any[]\n  arrDefaultRequired.validateSync(null);\n\n  array().default<string[]>(() => []);\n\n  // $ExpectType (string | undefined)[] | undefined\n  array(string()).cast(null);\n\n  // $ExpectType (string | undefined)[] | null\n  array().defined().nullable().of(string()).cast(null);\n\n  // $ExpectType string[] | undefined\n  array(string().required()).validateSync(null);\n\n  // $ExpectType string[]\n  array(string().default('')).required().validateSync(null);\n\n  // $ExpectType string[] | undefined\n  array(string().default('')).validateSync(null);\n\n  // $ExpectType string[] | null | undefined\n  array(string().default('')).nullable().validateSync(null);\n\n  // $ExpectType (string | null)[] | undefined\n  array(string().nullable().default('')).validateSync(null);\n\n  // $ExpectType number[]\n  array()\n    .default([] as number[])\n    .getDefault();\n\n  // $ExpectType (string | null)[] | null\n  array(string().nullable().default(''))\n    .nullable()\n    .default(() => [] as string[])\n    .validateSync(null);\n\n  // $ExpectType string[] | undefined\n  array(lazy(() => string().default(''))).validateSync(null);\n\n  const numList = [1, 2];\n\n  // $ExpectType number[]\n  array(number()).default(numList).getDefault();\n\n  // $ExpectType (number | undefined)[]\n  array(number()).concat(array(number()).required()).validateSync([]);\n\n  // $ExpectType any[] | undefined\n  array().strip().cast(undefined);\n\n  // $ExpectType any[] | undefined\n  array().strip().strip(false).cast(undefined);\n\n  ArrayConcat: {\n    const arrReq = array(number()).required();\n\n    // $ExpectType (number | undefined)[]\n    const _c1 = array(number()).concat(arrReq).validateSync([]);\n  }\n}\n\nTuple: {\n  // $ExpectType [number, string | undefined, { age: number; }] | undefined\n  tuple([\n    number().defined(),\n    string(),\n    object({ age: number().required() }),\n  ]).cast([3, 4]);\n\n  const tplRequired = tuple([\n    string().required(),\n    string().required(),\n  ]).required();\n\n  // $ExpectType [string, string]\n  tplRequired.cast(undefined);\n\n  // $ExpectType [string, string] | null\n  tplRequired.nullable().cast(undefined);\n\n  // $ExpectType [string, string]\n  tplRequired.nullable().nonNullable().cast(undefined);\n\n  //\n  const tplOptional = tuple([\n    string().required(),\n    string().required(),\n  ]).optional();\n\n  // $ExpectType [string, string] | undefined\n  tplOptional.cast(undefined);\n\n  // $ExpectType [string, string]\n  tplOptional.defined().cast(undefined);\n\n  //\n  const tplNullableOptional = tuple([string().required(), string().required()])\n    .nullable()\n    .optional();\n\n  // $ExpectType [string, string] | null | undefined\n  tplNullableOptional.cast('');\n\n  // $ExpectType [string, string]\n  tplNullableOptional.required().validateSync('');\n\n  //\n  const tplNullable = tuple([\n    string().required(),\n    string().required(),\n  ]).nullable();\n\n  // $ExpectType [string, string] | null | undefined\n  tplNullable.validateSync('');\n\n  const tplDefined = tuple([string().required(), string().required()]).default(\n    () => ['', ''],\n  );\n\n  // $ExpectType [string, string]\n  tplDefined.getDefault();\n\n  const tplDefault = tuple([string().required(), string().required()])\n    .nullable()\n    .default(['', ''])\n    .nullable();\n\n  // $ExpectType [string, string] | null\n  tplDefault.cast('');\n\n  // $ExpectType [string, string] | null\n  tplDefault.validateSync('');\n\n  // $ExpectType TupleSchema<[string, string], AnyObject, [string, string], \"d\">\n  const tplDefaultRequired = tuple([string().required(), string().required()])\n    .nullable()\n    .required()\n    .default(() => ['', '']);\n\n  // $ExpectType [string, string]\n  tplDefaultRequired.cast('');\n\n  // $ExpectType [string, string]\n  tplDefaultRequired.validateSync(null);\n}\n\nObject: {\n  const objRequired = object().required();\n\n  // $ExpectType {}\n  objRequired.cast(undefined);\n\n  // $ExpectType {} | null\n  objRequired.nullable().cast(undefined);\n\n  // $ExpectType {}\n  objRequired.nullable().nonNullable().cast(undefined);\n\n  //\n  const objOptional = object().optional();\n\n  // FIXME: should not be undefined\n  // $ExpectType {} | undefined\n  objOptional.cast(undefined);\n\n  // $ExpectType {}\n  objOptional.defined().cast(undefined);\n\n  //\n  const objNullableOptional = object().nullable().optional();\n\n  // FIXME: should not be undefined\n  // $ExpectType {} | null | undefined\n  objNullableOptional.cast('');\n\n  // $ExpectType {}\n  objNullableOptional.required().validateSync('');\n\n  //\n  //\n  const objNullable = object().nullable();\n\n  // $ExpectType {} | null\n  objNullable.validateSync('');\n\n  const v = object({\n    name: string().defined(),\n    colors: array(string().defined()).required(),\n  }).nullable();\n\n  // $ExpectType { name: string; colors: string[]; } | null\n  v.cast({});\n\n  interface Person {\n    name: string;\n  }\n\n  const _person: ObjectSchema<Person> = object({ name: string().defined() });\n\n  const a1 = object({\n    list: array(number().required()).required(),\n    nested: array(\n      object({\n        name: string().default(''),\n      }),\n    ),\n  })\n    .required()\n    .validateSync(undefined);\n\n  // $ExpectType number[]\n  a1.list;\n\n  // $ExpectType string | undefined\n  a1.nested?.[0].name;\n\n  // $ExpectType string\n  a1.nested![0].name;\n\n  const obj = object({\n    string: string<'foo'>().defined(),\n    number: number().default(1),\n    removed: number().strip().default(0),\n    ref: ref('string'),\n    nest: object({\n      other: string(),\n    }),\n    nullObject: object({\n      other: string(),\n    }).default(null),\n    lazy: lazy(() => number().defined()),\n  });\n\n  const cast1 = obj.cast({});\n\n  let _f = obj.getDefault();\n\n  // $ExpectType string | undefined\n  cast1!.nest!.other;\n\n  // $ExpectType \"foo\"\n  cast1!.string;\n\n  // @ts-expect-error Removed doesn't exist\n  cast1!.removed;\n\n  // $ExpectType number\n  cast1!.number;\n\n  // $ExpectType string\n  string().strip().default('').cast('');\n\n  // $ExpectType { string?: string | undefined; }\n  const _cast2 = object({\n    string: string().strip().strip(false),\n  }).cast(undefined);\n\n  //\n  // Object Defaults\n  //\n  const dflt1 = obj.getDefault();\n\n  // $ExpectType 1\n  dflt1.number;\n\n  // $ExpectType undefined\n  dflt1.ref;\n\n  // $ExpectType undefined\n  dflt1.lazy;\n\n  // $ExpectType undefined\n  dflt1.string;\n\n  // $ExpectType undefined\n  dflt1.nest.other;\n\n  // $ExpectType null\n  dflt1.nullObject;\n\n  const merge = object({\n    field: string().required(),\n    other: string().default(''),\n  }).shape({\n    field: number().default(1),\n    name: string(),\n  });\n\n  // $ExpectType { name?: string | undefined; other: string; field: number; }\n  merge.cast({});\n\n  // $ExpectType number\n  merge.cast({}).field;\n\n  // $ExpectType string\n  merge.cast({}).other;\n\n  Concat: {\n    const obj1 = object({\n      field: string().required(),\n      other: string().default(''),\n    });\n\n    const obj2 = object({\n      field: number().default(1),\n      name: string(),\n    }).nullable();\n\n    // $ExpectType { name?: string | undefined; other: string; field: number; } | null\n    obj1.concat(obj2).cast('');\n\n    // $ExpectType { name?: string | undefined; other: string; field: number; }\n    obj1.nullable().concat(obj2.nonNullable()).cast('');\n\n    // $ExpectType { field: 1; other: \"\"; name: undefined; }\n    obj1.nullable().concat(obj2.nonNullable()).getDefault();\n\n    // $ExpectType null\n    obj1.concat(obj2.default(null)).getDefault();\n\n    const optionalNonDefaultedObj = object({\n      nested: object({\n        h: number().required(),\n      })\n        .default(undefined)\n        .optional(),\n    });\n\n    // $ExpectType { h: number; } | undefined\n    optionalNonDefaultedObj.cast({}).nested;\n  }\n\n  SchemaOfDate: {\n    type Employee = {\n      hire_date: Date;\n      name: string;\n    };\n\n    const _t: ObjectSchema<Employee> = object({\n      name: string().defined(),\n      hire_date: date().defined(),\n    });\n  }\n\n  SchemaOfDateArray: {\n    type EmployeeWithPromotions = {\n      promotion_dates: Date[];\n      name: string;\n    };\n\n    const _t: ObjectSchema<EmployeeWithPromotions> = object({\n      name: string().defined(),\n      promotion_dates: array().of(date().defined()).defined(),\n    });\n  }\n\n  SchemaOfFileArray: {\n    type DocumentWithFullHistory = {\n      history?: File[];\n      name: string;\n    };\n\n    const _t: ObjectSchema<DocumentWithFullHistory> = object({\n      name: string().defined(),\n      history: array().of(mixed<File>().defined()),\n    });\n  }\n\n  ObjectPick: {\n    const schema = object({\n      age: number(),\n      name: string().required(),\n    })\n      .nullable()\n      .required();\n\n    // $ExpectType number | undefined\n    schema.pick(['age']).validateSync({ age: '1' }).age;\n\n    // $ExpectType { age?: number | undefined; }\n    schema.pick(['age']).validateSync({ age: '1' });\n  }\n\n  ObjectOmit: {\n    const schema = object({\n      age: number(),\n      name: string().required(),\n    })\n      .nullable()\n      .required();\n\n    // $ExpectType string\n    schema.omit(['age']).validateSync({ name: '1' }).name;\n\n    // $ExpectType string | undefined\n    schema.omit(['age']).partial().validateSync({ name: '1' }).name;\n\n    // $ExpectType { name: string; }\n    schema.omit(['age']).validateSync({ name: '1' });\n  }\n\n  ObjectPartial: {\n    const schema = object({\n      // age: number(),\n      name: string().required(),\n      lazy: lazy(() => number().defined()),\n      address: object()\n        .shape({\n          line1: string().required(),\n          zip: number().required().strip(),\n        })\n        .default(undefined),\n    }).nullable();\n\n    const partial = schema.partial();\n\n    // $ExpectType string | undefined\n    partial.validateSync({})!.name;\n\n    // $ExpectType string\n    partial.validateSync({})!.address!.line1;\n\n    // $ExpectType number | undefined\n    partial.validateSync({})!.lazy;\n\n    const deepPartial = schema.deepPartial();\n\n    // $ExpectType string | undefined\n    deepPartial.validateSync({})!.name;\n\n    // $ExpectType string | undefined\n    deepPartial.validateSync({})!.address!.line1;\n\n    // $ExpectType number | undefined\n    deepPartial.validateSync({})!.lazy;\n  }\n}\n\n// Conditions: {\n//   // $ExpectType NumberSchema<number | undefined, AnyObject, undefined, \"\"> | StringSchema<string, AnyObject, undefined, \"\">\n//   string().when('foo', ([foo], schema) => (foo ? schema.required() : number()));\n\n//   // $ExpectType StringSchema<string | undefined, AnyObject, undefined, \"\">\n//   string()\n//     .when('foo', ([foo], schema) => (foo ? schema.required() : schema))\n//     .when('foo', ([foo], schema) => (foo ? schema.required() : schema));\n\n//   // $ExpectType NumberSchema<number | undefined, AnyObject, undefined, \"\"> | StringSchema<string, AnyObject, undefined, \"\">\n//   string().when('foo', {\n//     is: true,\n//     then: () => number(),\n//     otherwise: (s) => s.required(),\n//   });\n\n//   const result = object({\n//     foo: bool().defined(),\n//     polyField: mixed<string>().when('foo', {\n//       is: true,\n//       then: () => number(),\n//       otherwise: (s) => s.required(),\n//     }),\n//   }).cast({ foo: true, polyField: '1' });\n\n//   // $ExpectType { polyField?: string | number | undefined; foo: boolean; }\n//   result;\n\n//   mixed()\n//     .when('foo', ([foo]) => (foo ? string() : number()))\n//     .min(1);\n// }\n\nTypeAssigning: {\n  const _schema: ObjectSchema<{\n    mtime?: Date | null | undefined;\n    toJSON: () => any;\n  }> = object({\n    mtime: date().nullable(),\n    toJSON: mixed<() => any>().required(),\n  });\n}\n\nreach: {\n  const obj = object({\n    string: string<'foo'>().defined(),\n    number: number().default(1),\n    removed: number().strip(),\n    ref: ref<'foo'>('string'),\n    nest: array(\n      object({\n        other: string(),\n      }),\n    ),\n    nullObject: object({\n      other: string(),\n    }).default(null),\n    lazy: lazy(() => number().defined()),\n  });\n\n  // $ExpectType ISchema<string | undefined, AnyObject, any, any> | Reference<string | undefined>\n  const _1 = reach(obj, 'nest[0].other' as const);\n\n  // $ExpectType Reference<{ other?: string | undefined; } | undefined> | ISchema<{ other?: string | undefined; } | undefined, AnyObject, any, any>\n  const _2 = reach(obj, 'nest[0]' as const);\n\n  // $ExpectType Reference<\"foo\"> | ISchema<\"foo\", AnyObject, any, any>\n  const _3 = reach(obj, 'ref');\n}\n\naddMethod: {\n  addMethod(Schema, 'foo', function () {\n    return this.clone();\n  });\n\n  addMethod(string, 'foo', function () {\n    return this.clone();\n  });\n}\n"
  },
  {
    "path": "test/util/parseIsoDate.ts",
    "content": "/**\n * This file is a modified version of the test file from the following repository:\n * Date.parse with progressive enhancement for ISO 8601 <https://github.com/csnover/js-iso8601>\n * NON-CONFORMANT EDITION.\n * © 2011 Colin Snover <http://zetafleet.com>\n * Released under MIT license.\n */\n\nimport { describe, test, expect } from 'vitest';\nimport { parseIsoDate } from '../../src/util/parseIsoDate';\n\nconst sixHours = 6 * 60 * 60 * 1000;\nconst sixHoursThirty = sixHours + 30 * 60 * 1000;\nconst epochLocalTime = new Date(1970, 0, 1, 0, 0, 0, 0).valueOf();\n\ndescribe('plain date (no time)', () => {\n  describe('valid dates', () => {\n    test('Unix epoch', () => {\n      const result = parseIsoDate('1970-01-01');\n      expect(result).toBe(epochLocalTime);\n    });\n    test('2001', () => {\n      const result = parseIsoDate('2001');\n      const expected = new Date(2001, 0, 1, 0, 0, 0, 0).valueOf();\n      expect(result).toBe(expected);\n    });\n    test('2001-02', () => {\n      const result = parseIsoDate('2001-02');\n      const expected = new Date(2001, 1, 1, 0, 0, 0, 0).valueOf();\n      expect(result).toBe(expected);\n    });\n    test('2001-02-03', () => {\n      const result = parseIsoDate('2001-02-03');\n      const expected = new Date(2001, 1, 3, 0, 0, 0, 0).valueOf();\n      expect(result).toBe(expected);\n    });\n    test('-002001', () => {\n      const result = parseIsoDate('-002001');\n      const expected = new Date(-2001, 0, 1, 0, 0, 0, 0).valueOf();\n      expect(result).toBe(expected);\n    });\n    test('-002001-02', () => {\n      const result = parseIsoDate('-002001-02');\n      const expected = new Date(-2001, 1, 1, 0, 0, 0, 0).valueOf();\n      expect(result).toBe(expected);\n    });\n    test('-002001-02-03', () => {\n      const result = parseIsoDate('-002001-02-03');\n      const expected = new Date(-2001, 1, 3, 0, 0, 0, 0).valueOf();\n      expect(result).toBe(expected);\n    });\n    test('+010000-02', () => {\n      const result = parseIsoDate('+010000-02');\n      const expected = new Date(10000, 1, 1, 0, 0, 0, 0).valueOf();\n      expect(result).toBe(expected);\n    });\n    test('+010000-02-03', () => {\n      const result = parseIsoDate('+010000-02-03');\n      const expected = new Date(10000, 1, 3, 0, 0, 0, 0).valueOf();\n      expect(result).toBe(expected);\n    });\n    test('-010000-02', () => {\n      const result = parseIsoDate('-010000-02');\n      const expected = new Date(-10000, 1, 1, 0, 0, 0, 0).valueOf();\n      expect(result).toBe(expected);\n    });\n    test('-010000-02-03', () => {\n      const result = parseIsoDate('-010000-02-03');\n      const expected = new Date(-10000, 1, 3, 0, 0, 0, 0).valueOf();\n      expect(result).toBe(expected);\n    });\n  });\n\n  describe('invalid dates', () => {\n    test('invalid YYYY (non-digits)', () => {\n      expect(parseIsoDate('asdf')).toBeNaN();\n    });\n    test('invalid YYYY-MM-DD (non-digits)', () => {\n      expect(parseIsoDate('1970-as-df')).toBeNaN();\n    });\n    test('invalid YYYY-MM- (extra hyphen)', () => {\n      expect(parseIsoDate('1970-01-')).toBe(epochLocalTime);\n    });\n    test('invalid YYYY-MM-DD (missing hyphens)', () => {\n      expect(parseIsoDate('19700101')).toBe(epochLocalTime);\n    });\n    test('ambiguous YYYY-MM/YYYYYY (missing plus/minus or hyphen)', () => {\n      expect(parseIsoDate('197001')).toBe(epochLocalTime);\n    });\n  });\n});\n\ndescribe('date-time', () => {\n  describe('no time zone', () => {\n    test('2001-02-03T04:05', () => {\n      const result = parseIsoDate('2001-02-03T04:05');\n      const expected = new Date(2001, 1, 3, 4, 5, 0, 0).valueOf();\n      expect(result).toBe(expected);\n    });\n    test('2001-02-03T04:05:06', () => {\n      const result = parseIsoDate('2001-02-03T04:05:06');\n      const expected = new Date(2001, 1, 3, 4, 5, 6, 0).valueOf();\n      expect(result).toBe(expected);\n    });\n    test('2001-02-03T04:05:06.007', () => {\n      const result = parseIsoDate('2001-02-03T04:05:06.007');\n      const expected = new Date(2001, 1, 3, 4, 5, 6, 7).valueOf();\n      expect(result).toBe(expected);\n    });\n  });\n\n  describe('Z time zone', () => {\n    test('2001-02-03T04:05Z', () => {\n      const result = parseIsoDate('2001-02-03T04:05Z');\n      const expected = Date.UTC(2001, 1, 3, 4, 5, 0, 0);\n      expect(result).toBe(expected);\n    });\n    test('2001-02-03T04:05:06Z', () => {\n      const result = parseIsoDate('2001-02-03T04:05:06Z');\n      const expected = Date.UTC(2001, 1, 3, 4, 5, 6, 0);\n      expect(result).toBe(expected);\n    });\n    test('2001-02-03T04:05:06.007Z', () => {\n      const result = parseIsoDate('2001-02-03T04:05:06.007Z');\n      const expected = Date.UTC(2001, 1, 3, 4, 5, 6, 7);\n      expect(result).toBe(expected);\n    });\n  });\n\n  describe('offset time zone', () => {\n    test('2001-02-03T04:05-00:00', () => {\n      const result = parseIsoDate('2001-02-03T04:05-00:00');\n      const expected = Date.UTC(2001, 1, 3, 4, 5, 0, 0);\n      expect(result).toBe(expected);\n    });\n    test('2001-02-03T04:05:06-00:00', () => {\n      const result = parseIsoDate('2001-02-03T04:05:06-00:00');\n      const expected = Date.UTC(2001, 1, 3, 4, 5, 6, 0);\n      expect(result).toBe(expected);\n    });\n    test('2001-02-03T04:05:06.007-00:00', () => {\n      const result = parseIsoDate('2001-02-03T04:05:06.007-00:00');\n      const expected = Date.UTC(2001, 1, 3, 4, 5, 6, 7);\n      expect(result).toBe(expected);\n    });\n\n    test('2001-02-03T04:05+00:00', () => {\n      const result = parseIsoDate('2001-02-03T04:05+00:00');\n      const expected = Date.UTC(2001, 1, 3, 4, 5, 0, 0);\n      expect(result).toBe(expected);\n    });\n    test('2001-02-03T04:05:06+00:00', () => {\n      const result = parseIsoDate('2001-02-03T04:05:06+00:00');\n      const expected = Date.UTC(2001, 1, 3, 4, 5, 6, 0);\n      expect(result).toBe(expected);\n    });\n    test('2001-02-03T04:05:06.007+00:00', () => {\n      const result = parseIsoDate('2001-02-03T04:05:06.007+00:00');\n      const expected = Date.UTC(2001, 1, 3, 4, 5, 6, 7);\n      expect(result).toBe(expected);\n    });\n\n    test('2001-02-03T04:05-06:30', () => {\n      const result = parseIsoDate('2001-02-03T04:05-06:30');\n      const expected = Date.UTC(2001, 1, 3, 4, 5, 0, 0) + sixHoursThirty;\n      expect(result).toBe(expected);\n    });\n    test('2001-02-03T04:05:06-06:30', () => {\n      const result = parseIsoDate('2001-02-03T04:05:06-06:30');\n      const expected = Date.UTC(2001, 1, 3, 4, 5, 6, 0) + sixHoursThirty;\n      expect(result).toBe(expected);\n    });\n    test('2001-02-03T04:05:06.007-06:30', () => {\n      const result = parseIsoDate('2001-02-03T04:05:06.007-06:30');\n      const expected = Date.UTC(2001, 1, 3, 4, 5, 6, 7) + sixHoursThirty;\n      expect(result).toBe(expected);\n    });\n\n    test('2001-02-03T04:05+06:30', () => {\n      const result = parseIsoDate('2001-02-03T04:05+06:30');\n      const expected = Date.UTC(2001, 1, 3, 4, 5, 0, 0) - sixHoursThirty;\n      expect(result).toBe(expected);\n    });\n    test('2001-02-03T04:05:06+06:30', () => {\n      const result = parseIsoDate('2001-02-03T04:05:06+06:30');\n      const expected = Date.UTC(2001, 1, 3, 4, 5, 6, 0) - sixHoursThirty;\n      expect(result).toBe(expected);\n    });\n    test('2001-02-03T04:05:06.007+06:30', () => {\n      const result = parseIsoDate('2001-02-03T04:05:06.007+06:30');\n      const expected = Date.UTC(2001, 1, 3, 4, 5, 6, 7) - sixHoursThirty;\n      expect(result).toBe(expected);\n    });\n  });\n\n  describe('incomplete dates', () => {\n    test('2001T04:05:06.007', () => {\n      const result = parseIsoDate('2001T04:05:06.007');\n      const expected = new Date(2001, 0, 1, 4, 5, 6, 7).valueOf();\n      expect(result).toBe(expected);\n    });\n    test('2001-02T04:05:06.007', () => {\n      const result = parseIsoDate('2001-02T04:05:06.007');\n      const expected = new Date(2001, 1, 1, 4, 5, 6, 7).valueOf();\n      expect(result).toBe(expected);\n    });\n\n    test('-010000T04:05', () => {\n      const result = parseIsoDate('-010000T04:05');\n      const expected = new Date(-10000, 0, 1, 4, 5, 0, 0).valueOf();\n      expect(result).toBe(expected);\n    });\n    test('-010000-02T04:05', () => {\n      const result = parseIsoDate('-010000-02T04:05');\n      const expected = new Date(-10000, 1, 1, 4, 5, 0, 0).valueOf();\n      expect(result).toBe(expected);\n    });\n    test('-010000-02-03T04:05', () => {\n      const result = parseIsoDate('-010000-02-03T04:05');\n      const expected = new Date(-10000, 1, 3, 4, 5, 0, 0).valueOf();\n      expect(result).toBe(expected);\n    });\n  });\n\n  describe('invalid date-times', () => {\n    test('missing T', () => {\n      expect(parseIsoDate('1970-01-01 00:00:00')).toBe(epochLocalTime);\n    });\n    test('too many characters in millisecond part', () => {\n      expect(parseIsoDate('1970-01-01T00:00:00.000000')).toBe(epochLocalTime);\n    });\n    test('comma instead of dot', () => {\n      expect(parseIsoDate('1970-01-01T00:00:00,000')).toBe(epochLocalTime);\n    });\n    test('missing colon in timezone part', () => {\n      const subject = '1970-01-01T00:00:00+0630';\n      expect(parseIsoDate(subject)).toBe(Date.parse(subject));\n    });\n    test('missing colon in time part', () => {\n      expect(parseIsoDate('1970-01-01T0000')).toBe(epochLocalTime);\n    });\n    test('msec with missing seconds', () => {\n      expect(parseIsoDate('1970-01-01T00:00.000')).toBeNaN();\n    });\n  });\n});\n"
  },
  {
    "path": "test/yup.js",
    "content": "import { describe, it, expect, test } from 'vitest';\nimport reach, { getIn } from '../src/util/reach';\n\nimport {\n  addMethod,\n  object,\n  array,\n  string,\n  lazy,\n  number,\n  boolean,\n  date,\n  Schema,\n  ObjectSchema,\n  ArraySchema,\n  StringSchema,\n  NumberSchema,\n  BooleanSchema,\n  DateSchema,\n  mixed,\n  MixedSchema,\n  tuple,\n} from '../src';\n\ndescribe('Yup', function () {\n  it('cast should not assert on undefined', () => {\n    expect(() => string().cast(undefined)).not.toThrowError();\n  });\n\n  it('cast should assert on undefined cast results', () => {\n    expect(() =>\n      string()\n        .defined()\n        .transform(() => undefined)\n        .cast('foo'),\n    ).toThrowError(\n      'The value of field could not be cast to a value that satisfies the schema type: \"string\".',\n    );\n  });\n\n  it('cast should respect assert option', () => {\n    expect(() => string().cast(null)).toThrowError();\n\n    expect(() => string().cast(null, { assert: false })).not.toThrowError();\n  });\n\n  it('should getIn correctly', async () => {\n    let num = number();\n    let shape = object({ 'num-1': num });\n    let inst = object({\n      num: number().max(4),\n\n      nested: object({\n        arr: array().of(shape),\n      }),\n    });\n\n    const value = { nested: { arr: [{}, { 'num-1': 2 }] } };\n    let { schema, parent, parentPath } = getIn(\n      inst,\n      'nested.arr[1].num-1',\n      value,\n    );\n\n    expect(schema).toBe(num);\n    expect(parentPath).toBe('num-1');\n    expect(parent).toBe(value.nested.arr[1]);\n  });\n\n  it('should getIn array correctly', async () => {\n    let num = number();\n    let shape = object({ 'num-1': num });\n    let inst = object({\n      num: number().max(4),\n\n      nested: object({\n        arr: array().of(shape),\n      }),\n    });\n\n    const value = {\n      nested: {\n        arr: [{}, { 'num-1': 2 }],\n      },\n    };\n\n    const { schema, parent, parentPath } = getIn(inst, 'nested.arr[1]', value);\n\n    expect(schema).toBe(shape);\n    expect(parentPath).toBe('1');\n    expect(parent).toBe(value.nested.arr);\n  });\n\n  it('should REACH correctly', async () => {\n    let num = number();\n    let shape = object({ num });\n\n    let inst = object({\n      num: number().max(4),\n\n      nested: tuple([\n        string(),\n        object({\n          arr: array().of(shape),\n        }),\n      ]),\n    });\n\n    expect(reach(inst, '')).toBe(inst);\n\n    expect(reach(inst, 'nested[1].arr[0].num')).toBe(num);\n    expect(reach(inst, 'nested[1].arr[].num')).toBe(num);\n    expect(reach(inst, 'nested[1].arr.num')).toBe(num);\n    expect(reach(inst, 'nested[1].arr[1].num')).toBe(num);\n    expect(reach(inst, 'nested[1].arr[1]')).toBe(shape);\n\n    expect(() => reach(inst, 'nested.arr[1].num')).toThrowError(\n      'Yup.reach cannot implicitly index into a tuple type. the path part \".nested\" must contain an index to the tuple element, e.g. \".nested[0]\"',\n    );\n\n    await expect(reach(inst, 'nested[1].arr[0].num').isValid(5)).resolves.toBe(\n      true,\n    );\n  });\n\n  it('should REACH conditionally correctly', async function () {\n    let num = number().oneOf([4]),\n      inst = object().shape({\n        num: number().max(4),\n        nested: object().shape({\n          arr: array().when('$bar', function ([bar]) {\n            return bar !== 3\n              ? array().of(number())\n              : array().of(\n                  object().shape({\n                    foo: number(),\n                    num: number().when('foo', ([foo]) => {\n                      if (foo === 5) return num;\n                    }),\n                  }),\n                );\n          }),\n        }),\n      });\n\n    let context = { bar: 3 };\n    let value = {\n      bar: 3,\n      nested: {\n        arr: [{ foo: 5 }, { foo: 3 }],\n      },\n    };\n\n    let options = {};\n    options.parent = value.nested.arr[0];\n    options.value = options.parent.num;\n    expect(reach(inst, 'nested.arr.num', value).resolve(options)).toBe(num);\n    expect(reach(inst, 'nested.arr[].num', value).resolve(options)).toBe(num);\n\n    options.context = context;\n    expect(reach(inst, 'nested.arr.num', value, context).resolve(options)).toBe(\n      num,\n    );\n    expect(\n      reach(inst, 'nested.arr[].num', value, context).resolve(options),\n    ).toBe(num);\n    expect(\n      reach(inst, 'nested.arr[0].num', value, context).resolve(options),\n    ).toBe(num);\n\n    // // should fail b/c item[1] is used to resolve the schema\n    options.parent = value.nested.arr[1];\n    options.value = options.parent.num;\n    expect(\n      reach(inst, 'nested[\"arr\"][1].num', value, context).resolve(options),\n    ).not.toBe(num);\n\n    let reached = reach(inst, 'nested.arr[].num', value, context);\n\n    await expect(\n      reached.validate(5, { context, parent: { foo: 4 } }),\n    ).resolves.toBeDefined();\n\n    await expect(\n      reached.validate(5, { context, parent: { foo: 5 } }),\n    ).rejects.toThrowError(/one of the following/);\n  });\n\n  it('should reach through lazy', async () => {\n    let types = {\n      1: object({ foo: string() }),\n      2: object({ foo: number() }),\n    };\n\n    await expect(\n      object({\n        x: array(lazy((val) => types[val.type])),\n      })\n        .strict()\n        .validate({\n          x: [\n            { type: 1, foo: '4' },\n            { type: 2, foo: '5' },\n          ],\n        }),\n    ).rejects.toThrowError(/must be a `number` type/);\n  });\n\n  describe('addMethod', () => {\n    it('extending Schema should make method accessible everywhere', () => {\n      addMethod(Schema, 'foo', () => 'here');\n\n      expect(string().foo()).toBe('here');\n    });\n\n    test.each([\n      ['mixed', mixed],\n      ['object', object],\n      ['array', array],\n      ['string', string],\n      ['number', number],\n      ['boolean', boolean],\n      ['date', date],\n    ])('should work with factories: %s', (_msg, factory) => {\n      addMethod(factory, 'foo', () => 'here');\n\n      expect(factory().foo()).toBe('here');\n    });\n\n    test.each([\n      ['mixed', MixedSchema],\n      ['object', ObjectSchema],\n      ['array', ArraySchema],\n      ['string', StringSchema],\n      ['number', NumberSchema],\n      ['boolean', BooleanSchema],\n      ['date', DateSchema],\n    ])('should work with classes: %s', (_msg, ctor) => {\n      addMethod(ctor, 'foo', () => 'here');\n\n      expect(new ctor().foo()).toBe('here');\n    });\n  });\n});\n"
  },
  {
    "path": "test-setup.mjs",
    "content": "import { beforeAll } from 'vitest';\nimport { SynchronousPromise } from 'synchronous-promise';\nimport * as yup from './src/index.ts';\n\nbeforeAll(() => {\n  if (global.YUP_USE_SYNC) {\n    const { Schema } = yup;\n    const { validateSync } = Schema.prototype;\n\n    Schema.prototype.validate = function (value, options = {}) {\n      return new SynchronousPromise((resolve, reject) => {\n        let result;\n        try {\n          result = validateSync.call(this, value, options);\n        } catch (err) {\n          reject(err);\n        }\n\n        resolve(result);\n      });\n    };\n  }\n});\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"extends\": \"@4c/tsconfig/web\",\n  \"compilerOptions\": {\n    \"rootDir\": \"src\",\n    \"strictFunctionTypes\": true\n  },\n  \"include\": [\"src/**/*.ts\"]\n}\n"
  },
  {
    "path": "vitest.config.ts",
    "content": "import { defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n  test: {\n    environment: 'node',\n    setupFiles: ['./test-setup.mjs'],\n    include: ['test/**/*.{js,ts}'],\n    exclude: [\n      'test/helpers.ts',\n      'test/.eslintrc.js',\n      'test/**/.eslintrc.js',\n      'test/types/types.ts',\n    ],\n    globals: false,\n    projects: [\n      {\n        extends: true,\n        test: {\n          name: 'async',\n        },\n        define: {\n          'global.YUP_USE_SYNC': false,\n        },\n      },\n      {\n        extends: true,\n        test: {\n          name: 'sync',\n        },\n        define: {\n          'global.YUP_USE_SYNC': true,\n        },\n      },\n    ],\n  },\n});\n"
  }
]