{"id":22221936,"url":"https://github.com/fabiospampinato/skex","last_synced_at":"2025-07-27T16:31:49.306Z","repository":{"id":181423761,"uuid":"666007277","full_name":"fabiospampinato/skex","owner":"fabiospampinato","description":"A modern schema validation and filtration library with great TypeScript support.","archived":false,"fork":false,"pushed_at":"2023-09-24T16:28:50.000Z","size":206,"stargazers_count":17,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-11-28T10:41:03.780Z","etag":null,"topics":["filter","filtration","schema","typescript","validate","validation"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fabiospampinato.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"fabiospampinato","custom":"https://www.paypal.me/fabiospampinato"}},"created_at":"2023-07-13T13:45:08.000Z","updated_at":"2023-09-18T20:40:27.000Z","dependencies_parsed_at":null,"dependency_job_id":"7a8b8b51-3028-4041-b6d5-99647af9b482","html_url":"https://github.com/fabiospampinato/skex","commit_stats":null,"previous_names":["fabiospampinato/skex"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabiospampinato%2Fskex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabiospampinato%2Fskex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabiospampinato%2Fskex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabiospampinato%2Fskex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fabiospampinato","download_url":"https://codeload.github.com/fabiospampinato/skex/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227817017,"owners_count":17824200,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["filter","filtration","schema","typescript","validate","validation"],"created_at":"2024-12-02T23:16:17.602Z","updated_at":"2024-12-02T23:16:18.345Z","avatar_url":"https://github.com/fabiospampinato.png","language":"TypeScript","funding_links":["https://github.com/sponsors/fabiospampinato","https://www.paypal.me/fabiospampinato"],"categories":[],"sub_categories":[],"readme":"# Skex\n\nA modern schema validation and filtration library with great TypeScript support.\n\n## Install\n\n```sh\nnpm install --save skex\n```\n\n## APIs\n\n| [Primitive Ops](#primitive-ops) | [Compound Ops](#compound-ops) | [Type Ops](#type-ops) | [Utilities](#utilities)       | [Types](#types)     |\n| ------------------------------- | ----------------------------- | --------------------- | ----------------------------- | ------------------- |\n| [`bigint`](#bigint)             | [`array`](#array)             | [`any`](#any)         | [`serialize`](#serialize)     | [`Infer`](#infer)   |\n| [`boolean`](#boolean)           | [`tuple`](#tuple)             | [`unknown`](#unknown) | [`deserialize`](#deserialize) | [`Schema`](#schema) |\n| [`null`](#null)                 | [`object`](#object)           |                       |                               |                     |\n| [`number`](#number)             | [`record`](#record)           |                       |                               |                     |\n| [`string`](#string)             | [`nillable`](#nillable)       |                       |                               |                     |\n| [`symbol`](#symbol)             | [`nullable`](#nullable)       |                       |                               |                     |\n| [`undefined`](#undefined)       | [`optional`](#optional)       |                       |                               |                     |\n|                                 | [`and`](#and)                 |                       |                               |                     |\n|                                 | [`or`](#or)                   |                       |                               |                     |\n\n## Usage\n\nThis library provides various operators, or \"ops\" for short, which are the building blocks used to construct a schema. A schema is a graph of operators, which are the nodes in this graph. Each operator has various chainable immutable APIs used to customize it, and it can have a default value, a title and a description.\n\nThe main methods that each operator has, which are also the main functionality of this library, are:\n\n- `test`: the test method basically uses a schema as a type guard, it tells you if an arbitrary value matches the schema structurally according to TypeScript, i.e. like in TypeScript extra properties are allowed as long as the type of the schema matches. The input value is not mutated in any way.\n- `filter`: the filter method basically tries to extract the biggest subset of the input value that matches the schema. For example imagine you have a schema for your app's settings, you want to get all the valid settings out of the object, but if there happens to be an invalid setting in the object that shouldn't cause the entire object to be considered invalid. Basically invalid properties are deleted from the input object until what remains is a valid object, or an error is thrown if that's not possible. The input object can be mutated, even if the call ultimately ends up throwing an error.\n- `traverse`: the traverse method allows you to do something for each operator node found traversing the given node. This is fairly powerful but a bit of a niche and escape-hatch kind of feature.\n\nSome basic examples:\n\n```ts\nimport {boolean, number, object, string} from 'skex';\n\n// Let's create a simple schema that matches a number between 0 and 10 inclusive\n\nconst schema1 = number ().min ( 0 ).max ( 10 );\n\n// Schemas are immutable, they are cloned when made more specific\n\nschema1.multipleOf ( 5 ) !== schema1; // =\u003e true\n\n// Almost every operator supports all of the following APIs\n\nschema1.anyOf ([ 1, 2, 3 ]); // Allow only the provided values\nschema1.noneOf ([ 1, 2, 3 ]); // Disallow the provided values\nschema1.nillable (); // Allows for matching also null | undefined\nschema1.nullable (); // Allows for matching also null\nschema1.optional (); // Allows for matching also undefined\n\nschema1.default ( 123 ); // Sets a default value to fallback to when filtering and receiving an invalid input\nschema1.title ( 'Some title' ); // Set a title for this schema\nschema1.description ( 'Some description' ); // Set a description for this schema\n\n// Configuring multiple identical modifiers on the same schema is disallowed and will case the library to throw\n\nschema1.multipleOf ( 5 ).multipleOf ( 10 ); // =\u003e throws an error\n\n// The internal state of each operator can be retrieved\n\nschema1.get (); // =\u003e { min: 0, max: 10 }\nschema1.get ( 'min' ); // =\u003e 0\nschema1.get ( 'max' ); // =\u003e 10\nschema1.get ( 'multipleOf' ); // =\u003e undefined\n\n// Let's test if an arbitrary input matches this schema\n\nschema1.test ( 0 ); // =\u003e true\nschema1.test ( 5 ); // =\u003e true\nschema1.test ( 10 ); // =\u003e true\n\nschema1.test ( 100 ); // =\u003e false\nschema1.test ( -10 ); // =\u003e false\nschema1.test ( 'abc' ); // =\u003e false\n\n// Let's filter an input according to this schema, which for primitive ops effectively means throwing if the input doesn't match\n\nschema1.filter ( 0 ); // =\u003e 0\nschema1.filter ( 5 ); // =\u003e 5\nschema1.filter ( 10 ); // =\u003e 10\n\nschema1.filter ( 100 ); // =\u003e throws an error\nschema1.filter ( -10 ); // =\u003e throws an error\nschema1.filter ( 'abc' ); // =\u003e throws an error\n\n// Let's filter the input according to the schema, like .filter, but without throwing, like .test\n\nconst isFiltered = schema1.filter ( 10, false, true );\n\n// Let's create a more complicated schema for matching settings\n// Notice how every property is also marked as optional, as we don't want to throw out the entire input object if a single one of these properties is missing or invalid\n\nconst schema2 = object ({\n  editor: object ({\n    autosave: object ({\n      enabled: boolean ().default ( true ).description ( 'Whether autosaving is enabled or not' ).optional (),\n      interval: number ().default ( 60_000 ).description ( 'The mount of time to wait between autosaves' ).optional ()\n    }).optional (),\n    cursor: object ({\n      animated: boolean ().default ( false ).description ( 'Whether the cursor should move smoothly between positions or not' ).optional (),\n      blinking: string ().anyOf ([ 'blink', 'smooth', 'phase', 'expand', 'solid' ]).default ( 'blink' ).description ( 'The style used for blinking cursors' ).optional (),\n      style: string ().anyOf ([ 'line', 'block', 'underline' ]).default ( 'line' ).description ( 'The style used for rendering cursors' ).optional ()\n    }).optional ()\n  }).optional ()\n});\n\n// Let's match some objects against this more complicated schema\n\nschema2.test ( {} ); // =\u003e true\n\nschema2.test ({ // =\u003e true\n  editor: {\n    autosave: {\n      enabled: true\n    }\n  }\n});\n\nschema2.test ({ // =\u003e true\n  editor: {\n    cursor: {\n      animated: true,\n      blinking: 'phase',\n      style: 'underline'\n    }\n  },\n  extraProperty: {\n    whatever: true\n  }\n});\n\nschema2.test ({ // false\n  editor: {\n    cursor: {\n      animated: 'nope'\n    }\n  }\n});\n\nschema2.test ({ // false\n  editor: {\n    cursor: {\n      blinking: 'no-blinking'\n    }\n  }\n});\n\n// Let's filter an object against this more complicate schema\n\nconst filtered = schema2.filter ({\n  editor: {\n    cursor: {\n      animated: true,\n      blinking: 'phase',\n      style: 'pixelated'\n    }\n  },\n  extraProperty: {\n    whatever: true\n  }\n});\n// {\n//   editor: {\n//     cursor: {\n//       animated: true,\n//       blinking: 'phase'\n//     }\n//   }\n// }\n\n// Let's traverse this schema\n\nschema2.traverse ( ( child, parent, key ) =\u003e {\n  console.log ( 'current node:', child ); // Callback called once for each operator node (\"child\" here) in the graph\n  console.log ( 'parent node:', parent ); // All nodes have a parent except for the root one being traversed\n  console.log ( 'parent key:', key ); // Some child nodes have a parent but they are not attached on a key on the parent, like schemas passed to the \"and\" operator\n});\n```\n\n## Primitive Ops\n\nPrimitive operators are the leaf nodes in your schema graph, they don't take any other operators as input, they just match a single value.\n\n#### `bigint`\n\nThis op matches a single [BigInt](https://developer.mozilla.org/en-US/docs/Glossary/BigInt).\n\n```ts\nimport {bigint} from 'skex';\n\nbigint (); // Matches a bigint\n\nbigint ().gt ( 5n ); // Matches a bigint that is \u003e 5n\nbigint ().gte ( 5n ); // Matches a bigint that is \u003e= 5n\nbigint ().min ( 5n ); // Matches a bigint that is \u003e= 5n\nbigint ().lt ( 5n ); // Matches a bigint that is \u003c 5n\nbigint ().lte ( 5n ); // Matches a bigint that is \u003c= 5n\nbigint ().max ( 5n ); // Matches a bigint that is \u003c= 5n\nbigint ().multipleOf ( 5n ); // Matches a bigint that is a multiple of 5n\n\nbigint ().anyOf ([ 1n, 2n, 3n ]); // Matches a bigint that is either 1n, 2n or 3n\nbigint ().noneOf ([ 1n, 2n, 3n ]); // Matches a bigint that is neither 1n, 2n nor 3n\nbigint ().nillable (); // Matches bigint | null | undefined\nbigint ().nullable (); // Matches bigint | null\nbigint ().optional (); // Matches bigint | undefined\n```\n\n#### `boolean`\n\nThis op matches a single [Boolean](https://developer.mozilla.org/en-US/docs/Glossary/Boolean).\n\n```ts\nimport {boolean} from 'skex';\n\nboolean (); // Matches a boolean\n\nboolean ().anyOf ([ true ]); // Matches a boolean that is true\nboolean ().noneOf ([ true ]); // Matches a boolean that is not true\nboolean ().nillable (); // Matches boolean | null | undefined\nboolean ().nullable (); // Matches boolean | null\nboolean ().optional (); // Matches boolean | undefined\n```\n\n#### `null`\n\nThis op matches a single [Null](https://developer.mozilla.org/en-US/docs/Glossary/Null).\n\n```ts\nimport {null} from 'skex';\n\nnull (); // Matches null\nnull ().optional (); // Matches null | undefined\n```\n\n#### `number`\n\nThis op matches a single [Number](https://developer.mozilla.org/en-US/docs/Glossary/Number).\n\n```ts\nimport {number} from 'skex';\n\nnumber (); // Matches a number\n\nnumber ().finite (); // Matches a finite number (no Infinity)\nnumber ().gt ( 5 ); // Matches a number that is \u003e 5\nnumber ().gte ( 5 ); // Matches a number that is \u003e= 5\nnumber ().min ( 5 ); // Matches a number that is \u003e= 5\nnumber ().integer (); // Matches an integer\nnumber ().lt ( 5 ); // Matches a number that is \u003c 5\nnumber ().lte ( 5 ); // Matches a number that is \u003c= 5\nnumber ().max ( 5 ); // Matches a number that is \u003c= 5\nnumber ().multipleOf ( 5 ); // Matches a number that is a multiple of 5\n\nnumber ().anyOf ([ 1, 2, 3 ]); // Matches a number that is either 1, 2 or 3\nnumber ().noneOf ([ 1, 2, 3 ]); // Matches a number that is neither 1, 2 nor 3\nnumber ().nillable (); // Matches number | null | undefined\nnumber ().nullable (); // Matches number | null\nnumber ().optional (); // Matches number | undefined\n```\n\n#### `string`\n\nThis op matches a single [String](https://developer.mozilla.org/en-US/docs/Glossary/String).\n\n```ts\nimport {string} from 'skex';\n\nstring (); // Matches a string\n\nstring ().length ( 3 ); // Matches a string of length === 3\nstring ().min ( 3 ); // Matches a string of length \u003c= 3\nstring ().max ( 3 ); // Matches a string of length \u003e= 3\nstring ().matches ( /abc/i ); // Matches a string that matches the regex\nstring ().matches ( isLowercase ); // Matches a string for which this function returns true\n\nstring ().anyOf ([ 'a', 'b', 'c' ]); // Matches a string that is either 'a', 'b' or 'c'\nstring ().noneOf ([ 'a', 'b', 'c' ]); // Matches a string that is neither 'a', 'b' nor 'c'\nstring ().nillable (); // Matches string | null | undefined\nstring ().nullable (); // Matches string | null\nstring ().optional (); // Matches string | undefined\n```\n\n#### `symbol`\n\nThis op matches a single [Symbol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol).\n\n```ts\nimport {symbol} from 'skex';\n\nsymbol (); // Matches a symbol\n\nsymbol ().anyOf ([ Symbol.iterator, Symbol.asyncIterator ]); // Matches a symbol that is either Symbol.iterator or Symbol.asyncIterator\nsymbol ().noneOf ([ Symbol.iterator, Symbol.asyncIterator ]); // Matches a symbol that is neither Symbol.iterator nor Symbol.asyncIterator\nsymbol ().nillable (); // Matches symbol | null | undefined\nsymbol ().nullable (); // Matches symbol | null\nsymbol ().optional (); // Matches symbol | undefined\n```\n\n#### `undefined`\n\nThis op matches a single [Undefined](https://developer.mozilla.org/en-US/docs/Glossary/Undefined).\n\n```ts\nimport {undefined} from 'skex';\n\nundefined (); // Matches undefined\nundefined ().nullable (); // Matches undefined | null\n```\n\n## Compound Ops\n\nCompound operators are the internal nodes in your schema graph, they take as input other operators, and combine them to create more complicated schemas.\n\n#### `array`\n\nThis op matches a single [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array), optionally matching all of its items against another schema.\n\n```ts\nimport {array, number} from 'skex';\n\narray (); // Matches an array with any items\narray ( number () ); // Matches an array with number items\n\narray ().length ( 3 ); // Matches an array of length === 3\narray ().min ( 3 ); // Matches an array of length \u003c= 3\narray ().max ( 3 ); // Matches an array of length \u003e= 3\narray ().items ( number () ); // Matches an array with number items\n\narray ().anyOf ([ [1, 2], ['a', 'b'] ]); // Matches an array that is either [1, 2] or ['a', 'b']\narray ().noneOf ([ [1, 2], ['a', 'b'] ]); // Matches an array that is neither [1, 2] nor ['a', 'b']\narray ().nillable (); // Matches unknown[] | null | undefined\narray ().nullable (); // Matches unknown[] | null\narray ().optional (); // Matches unknown[] | undefined\n```\n\n#### `tuple`\n\nThis op matches a single [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array), but where the exact type and index of each item in the array is matched explicit also.\n\n```ts\nimport {tuple, boolean, number, string} from 'skex';\n\ntuple (); // Matches an array with any items\ntuple ([ number (), string (), boolean () ]); // Matches [number, string, boolean]\ntuple ([ number (), string ().optional () ]) // Matches [number, string] | [number, undefined] | [number]\n\ntuple ().length ( 3 ); // Matches an array of length === 3\ntuple ().min ( 3 ); // Matches an array of length \u003c= 3\ntuple ().max ( 3 ); // Matches an array of length \u003e= 3\ntuple ().items ([ number (), string () ]); // Matches [number, string]\n\ntuple ().anyOf ([ [1, 2], ['a', 'b'] ]); // Matches an array that is either [1, 2] or ['a', 'b']\ntuple ().noneOf ([ [1, 2], ['a', 'b'] ]); // Matches an array that is neither [1, 2] nor ['a', 'b']\ntuple ().nillable (); // Matches unknown[] | null | undefined\ntuple ().nullable (); // Matches unknown[] | null\ntuple ().optional (); // Matches unknown[] | undefined\n```\n\n#### `object`\n\nThis op matches a single [Plain Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object), optionally matching each explicitly provided property with a specific schema.\n\n```ts\nimport {object, number, string} from 'skex';\n\nobject (); // Matches an object with any properties\nobject ({ foo: number ().optional (), bar: string ().optional () }); // Matches { foo?: number, bar?: string }\nobject ().properties ({ foo: number () }); // Matches { foo: number }\n\nobject ().anyOf ([ { foo: 123 }, { bar: 'abc' } ]); // Matches an object that is either { foo: 123 } or { bar: 'abc' }\nobject ().noneOf ([ { foo: 123 }, { bar: 'abc' } ]); // Matches an object that is neither { foo: 123 } nor { bar: 'abc' }\nobject ().nillable (); // Matches {} | null | undefined\nobject ().nullable (); // Matches {} | null\nobject ().optional (); // Matches {} | undefined\n```\n\n#### `record`\n\nThis op matches a single [Plain Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object), where all values, and optionally all keys also, are matches against specific schemas.\n\n```ts\nimport {record, number, string} from 'skex';\n\nrecord (); // Matches an object with any properties\nrecord ( number () ); // Matches a Record\u003cstring, number\u003e\nrecord ( string ().min ( 3 ), number () ); // Matches a Record\u003cstring, number\u003e where keys' lengths are \u003e= 3\n\nrecord ().anyOf ([ { foo: 123 }, { bar: 'abc' } ]); // Matches an object that is either { foo: 123 } or { bar: 'abc' }\nrecord ().noneOf ([ { foo: 123 }, { bar: 'abc' } ]); // Matches an object that is neither { foo: 123 } nor { bar: 'abc' }\nrecord ().nillable (); // Matches Record\u003cstring, unknown\u003e | null | undefined\nrecord ().nullable (); // Matches Record\u003cstring, unknown\u003e | null\nrecord ().optional (); // Matches Record\u003cstring, unknown\u003e | undefined\n```\n\n#### `nillable`\n\nThis op accepts [Undefined](https://developer.mozilla.org/en-US/docs/Glossary/Undefined) and [Null](https://developer.mozilla.org/en-US/docs/Glossary/Null) additionally to the type matched by the provided schema.\n\n```ts\nimport {nillable, number} from 'skex';\n\nnillable ( number () ); // Matches number | null | undefined\n```\n\n#### `nullable`\n\nThis op accepts [Null](https://developer.mozilla.org/en-US/docs/Glossary/Null) additionally to the type matched by the provided schema.\n\n```ts\nimport {nullable, number} from 'skex';\n\nnullable ( number () ); // Matches number | null\n```\n\n#### `optional`\n\nThis op accepts [Undefined](https://developer.mozilla.org/en-US/docs/Glossary/Undefined) additionally to the type matched by the provided schema.\n\n```ts\nimport {optional, number} from 'skex';\n\noptional ( number () ); // Matches number | undefined\n```\n\n#### `and`\n\nThis op matches multiple schemas on the same value at the same time.\n\n```ts\nimport {and, number, object, string} from 'skex';\n\nand ([ string ().matches ( /aaa/ ), string ().matches ( /bbb/ ) ]); // Matches a string that matches both regexes\nand ([ object ({ foo: number () }), object ({ bar: string () }) ]); // Matches { foo: number, bar: string }\n\nand ([ object ({ foo: number () }), object ({ bar: string () }) ]).anyOf ([ { foo: 1, bar: 'a' }, { foo: 2, bar: 'b' } ]); // Matches { foo: number, bar: string } but only if { foo: 1, bar: 'a' } or { foo: 2, bar: 'b' }\nand ([ object ({ foo: number () }), object ({ bar: string () }) ]).noneOf ([ { foo: 1, bar: 'a' }, { foo: 2, bar: 'b' } ]); // Matches { foo: number, bar: string } but only if not { foo: 1, bar: 'a' } nor { foo: 2, bar: 'b' }\nand ([ object ({ foo: number () }), object ({ bar: string () }) ]).nillable (); // Matches { foo: number, bar: string } | null | undefined\nand ([ object ({ foo: number () }), object ({ bar: string () }) ]).nullable (); // Matches { foo: number, bar: string } | null\nand ([ object ({ foo: number () }), object ({ bar: string () }) ]).optional (); // Matches { foo: number, bar: string } | undefined\n```\n\n#### `or`\n\nThis op matches at least one of the provided schemas on the provided value.\n\n```ts\nimport {or, number, string} from 'skex';\n\nor ([ string (), number () ]); // Matches string | number\n\nor ([ string (), number () ]).anyOf ([ 1, 2, 'a', 'b' ]); // Matches a string | number that is either 1, 2, 'a' or 'b'\nor ([ string (), number () ]).noneOf ([ 1, 2, 'a', 'b' ]); // Matches a string | number that is neither 1, 2, 'a' nor 'b'\nor ([ string (), number () ]).nillable (); // Matches string | number | null | undefined\nor ([ string (), number () ]).nullable (); // Matches string | number | null\nor ([ string (), number () ]).optional (); // Matches string | number | undefined\n```\n\n## Type Ops\n\nSpecial primitive operators that match values with a specific TypeScript-only type.\n\n#### `any`\n\nThis op matches any value, and it asserts it's value to be of type `any`.\n\n```ts\nimport {any} from 'skex';\n\nany (); // Matches anything as any\n\nany ().anyOf ([ 1, 2, 3 ]); // Matches anything as any, but allows only 1, 2 or 3\nany ().noneOf ([ 1, 2, 3 ]); // Matches anything as any, but disallows 1, 2 and 3\n```\n\n#### `unknown`\n\nThis op matches any value, and it asserts it's value to be of type `unknown`.\n\n```ts\nimport {unknown} from 'skex';\n\nunknown (); // Matches anything as unknown\n\nunknown ().anyOf ([ 1, 2, 3 ]); // Matches anything as unknown, but allows only 1, 2 or 3\nunknown ().noneOf ([ 1, 2, 3 ]); // Matches anything as unknown, but disallows 1, 2 and 3\n```\n\n## Utilities\n\nUtilities are not operators, so they are not part of your schemas, but they do useful things with your schemas.\n\n#### `serialize`\n\nThis utility serializes an arbitrary schema to a string.\n\nAny schema can be serialized to a string, unless it references symbols or functions, since those can't always be serialized to a string.\n\nAmong other things serialization can be used to pass a schema between different worker threads.\n\n```ts\nimport {serialize, number} from 'skex';\n\nserialize ( number ().min ( 3 ) ); // =\u003e '{\"$$schema\":\"number\",\"$$state\":{\"gte\":3}}'\n```\n\n#### `deserialize`\n\nThis utility deserializes a serialized schema back to into a usable schema.\n\nAny serialized schema can be deserialized, unless you are using custom schema ops (for now).\n\n```ts\nimport {serialize, deserialize, number} from 'skex';\n\nconst serialized = serialize ( number ().min ( 3 ) ); // =\u003e '{\"$$schema\":\"number\",\"$$state\":{\"gte\":3}}'\nconst deserialized = deserialize ( serialized ); // =\u003e Basically a clone of number ().min ( 3 )\n```\n\n## Types\n\nThe following types are provided to better use the library.\n\n#### `Infer`\n\nThis type allows you to extract the type that a schema matches.\n\nBasically it allows you to convert a schema into a type.\n\nInterface:\n\n```ts\ntype Infer\u003cT extends Schema\u003e = ReturnType\u003cT['filter']\u003e;\n```\n\nUsage:\n\n```ts\nimport {number, object, string} from 'skex';\nimport type {Infer} from 'skex';\n\nconst schema = object ({ foo: string (), bar: number ().optional () });\n\ntype Schema = Infer\u003ctypeof schema\u003e; // type Schema = { foo: string, bar?: number }\n```\n\n#### `Schema`\n\nThis type matches the general shape of a schema node.\n\nInterface:\n\n```ts\ntype Schema\u003cT = unknown\u003e = {\n  filter ( value: unknown, defaultable: false, quiet: true ): boolean,\n  filter ( value: unknown, defaultable?: boolean, quiet?: false ): T,\n  filter ( value: unknown, defaultable?: boolean, quiet?: boolean ): T | boolean,\n  get (): Record\u003cstring, unknown\u003e,\n  test ( value: unknown ): value is T,\n  traverse ( traverser: ( child: Schema, parent?: Schema, key?: string | number ) =\u003e void ): void\n};\n```\n\nUsage:\n\n```ts\nimport type {Schema} from 'skex';\n\nconst matchSchema = \u003cT\u003e ( schema: Schema\u003cT\u003e, value: unknown ): value is T =\u003e {\n\n  return schema.test ( value );\n\n};\n```\n\n## Examples\n\nSome example usages of the library.\n\n#### JSON schema\n\nThis schema matches any valid JSON value.\n\n```ts\nimport * as $ from 'skex';\n\nconst primitive = $.or ([ $.boolean (), $.null (), $.number (), $.string () ]);\nconst json = $.or ([ primitive, $.array ( () =\u003e json ), $.record ( () =\u003e json ) ]);\n\njson.test ( '...' );\n```\n\n#### Extract defaults\n\nThis code extracts default values out of a schema. It makes some assumptions, it may need to be tweaked for your use case.\n\n```ts\nconst toDefaults = schema =\u003e {\n  const defaults = {};\n  const values = new Map ();\n  schema.traverse ( ( child, parent, key ) =\u003e {\n    const valueChild = child.get ( 'default' ) || ( parent ? {} : defaults );\n    values.set ( child, valueChild );\n    const valueParent = values.get ( parent );\n    if ( !valueParent || !key ) return;\n    valueParent[key] = valueChild;\n  });\n  return defaults;\n};\n\nconst defaults = toDefault ( schema2 );\n// {\n//   editor: {\n//     autosave: {\n//       enabled: true,\n//       interval: 60000\n//     },\n//     cursor: {\n//       animated: false,\n//       blinking: 'blink',\n//       style: 'line'\n//     }\n//   }\n// }\n```\n\n#### Extract descriptions\n\nThis code extracts descriptions values out of a schema. It makes some assumptions, it may need to be tweaked for your use case.\n\n```ts\nconst toDescriptions = schema =\u003e {\n  const descriptions = {};\n  const values = new Map ();\n  schema.traverse ( ( child, parent, key ) =\u003e {\n    const valueChild = child.get ( 'description' ) || ( parent ? {} : descriptions );\n    values.set ( child, valueChild );\n    const valueParent = values.get ( parent );\n    if ( !valueParent || !key ) return;\n    valueParent[key] = valueChild;\n  });\n  return descriptions;\n};\n\nconst descriptions = toDescriptions ( schema2 );\n// {\n//   editor: {\n//     autosave: {\n//       enabled: 'Whether autosaving is enabled or not',\n//       interval: 'The mount of time to wait between autosaves'\n//     },\n//     cursor: {\n//       animated: 'Whether the cursor should move smoothly between positions or not',\n//       blinking: 'The style used for blinking cursors',\n//       style: 'The style used for rendering cursors'\n//     }\n//   }\n// }\n```\n\n## License\n\nMIT © Fabio Spampinato\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffabiospampinato%2Fskex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffabiospampinato%2Fskex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffabiospampinato%2Fskex/lists"}