{"id":14156283,"url":"https://github.com/cypress-io/schema-tools","last_synced_at":"2025-08-06T02:32:51.542Z","repository":{"id":37502947,"uuid":"129942548","full_name":"cypress-io/schema-tools","owner":"cypress-io","description":"Validate, sanitize and document JSON schemas","archived":true,"fork":false,"pushed_at":"2023-09-29T17:21:32.000Z","size":1544,"stargazers_count":72,"open_issues_count":30,"forks_count":3,"subscribers_count":29,"default_branch":"master","last_synced_at":"2024-04-14T08:35:36.244Z","etag":null,"topics":["cypress-io","json-schema","schema","utils"],"latest_commit_sha":null,"homepage":null,"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/cypress-io.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-04-17T17:40:30.000Z","updated_at":"2024-01-24T02:37:02.000Z","dependencies_parsed_at":"2022-07-08T16:01:33.845Z","dependency_job_id":"2292d1ed-8a33-4ad4-b8e2-e23e234d03f6","html_url":"https://github.com/cypress-io/schema-tools","commit_stats":{"total_commits":432,"total_committers":13,"mean_commits":33.23076923076923,"dds":"0.29166666666666663","last_synced_commit":"64150637145f1601d4ae320f164225d27b4e2107"},"previous_names":[],"tags_count":65,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cypress-io%2Fschema-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cypress-io%2Fschema-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cypress-io%2Fschema-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cypress-io%2Fschema-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cypress-io","download_url":"https://codeload.github.com/cypress-io/schema-tools/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":215735862,"owners_count":15923388,"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":["cypress-io","json-schema","schema","utils"],"created_at":"2024-08-17T08:05:20.844Z","updated_at":"2024-08-17T08:06:54.555Z","avatar_url":"https://github.com/cypress-io.png","language":"TypeScript","funding_links":[],"categories":["others","📦 Modules/Packages"],"sub_categories":[":curly_loop: Typography"],"readme":"# @cypress/schema-tools [![CircleCI](https://circleci.com/gh/cypress-io/schema-tools.svg?style=svg\u0026circle-token=aa9b52bab9e9216699ba7258929f727b06b13afe)](https://circleci.com/gh/cypress-io/schema-tools) [![renovate-app badge][renovate-badge]][renovate-app]\n\n\u003e Validate, sanitize and document [JSON schemas][json-schema]\n\n## Motivation\n\nExplicit [JSON schemas][json-schema] describing objects passed around in your system are good!\n\n- they are a living testable documentation instead of manual Wiki editing\n- provide examples for tests and integrations\n- validate inputs and outputs of the API calls\n\n## TOC\n\n- [Schemas](#schemas)\n- [Formats](#formats)\n- [API](#api)\n- [Debugging](#debugging), [testing](#testing) and [license](#license)\n\n## Schemas\n\nEach individual schema object should have 3 parts: a version, an example and a [JSON schema][json-schema] describing its properties. See [test/example-schemas.ts](test/example-schemas.ts). Start with a single `ObjectSchema` that describes a particular version of an object\n\n```typescript\nimport { ObjectSchema } from '@cypress/schema-tools'\nconst person100: ObjectSchema = {\n  // has semantic version numbers\n  version: {\n    major: 1,\n    minor: 0,\n    patch: 0,\n  },\n  // JSON schema\n  schema: {\n    type: 'object',\n    title: 'Person',\n    description: 'An example schema describing a person',\n    properties: {\n      name: {\n        type: 'string',\n        format: 'name',\n        description: 'this person needs a name',\n      },\n      age: {\n        type: 'integer',\n        minimum: 0,\n        description: 'Age in years',\n      },\n    },\n    required: ['name', 'age'],\n    // note: you can just use required: true to require all properties\n  },\n  // has typical example\n  example: {\n    name: 'Joe',\n    age: 10,\n  },\n}\n```\n\nYou can have multiple separate versions of the \"Person\" schema, and then combine them into single object.\n\n```typescript\nimport {ObjectSchema, VersionedSchema, versionSchemas} from '@cypress/schema-tools'\nconst person100: ObjectSchema = { ... }\n// maybe added another property\nconst person110: ObjectSchema = { ... }\n// some big changes\nconst person200: ObjectSchema = { ... }\nconst personVersions: VersionedSchema = versionSchemas(person100, person110, person200)\n```\n\nFinally, you probably have \"Person\" versioned schema, and maybe \"Organization\" and maybe some other schemas. So put them into a single collection\n\n```typescript\nimport { SchemaCollection, combineSchemas } from '@cypress/schema-tools'\nexport const schemas: SchemaCollection = combineSchemas(\n  personVersions,\n  organizationVersions,\n)\n```\n\nNow you can use the `schemas` object to validate and sanitize any object.\n\n## Formats\n\nIn addition to the [formats included with JSON-schemas](https://spacetelescope.github.io/understanding-json-schema/reference/string.html#built-in-formats) you can define custom formats that will be used to validate values. Start with a single custom format to describe an UUID for example\n\n```typescript\n// single custom format\nimport { CustomFormat, CustomFormats } from '@cypress/schema-tools'\nconst uuid: CustomFormat = {\n  name: 'uuid', // the name\n  description: 'GUID used through the system',\n  // regular expression to use to validate value\n  detect: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,\n  // (optional) replace actual value with this default value\n  // when using to sanitize an object\n  defaultValue: 'ffffffff-ffff-ffff-ffff-ffffffffffff',\n}\n// export all custom formats, in our case just 1\nexport const formats: CustomFormats = { uuid }\n```\n\nNow every time you use your schemas, pass the formats too so that the validator knows how to check values from custom formats.\n\n```typescript\n// example JSON schema using uuid custom format\nconst employee100: ObjectSchema = {\n  // has semantic version numbers\n  version: {\n    major: 1,\n    minor: 0,\n    patch: 0,\n  },\n  // JSON schema\n  schema: {\n    type: 'object',\n    title: 'Employee',\n    properties: {\n      id: {\n        type: 'string',\n        format: 'uuid',\n      },\n    },\n  },\n  example: {\n    id: 'a368dbfd-08e4-4698-b9a3-b2b660a11835',\n  },\n}\n// employee100 goes into \"schemas\", then\nassertSchema(schemas, formats)('Employee', '1.0.0')(someObject)\n```\n\n## API\n\n- [hasSchema](#hasschema)\n- [documentSchemas](#documentschemas)\n- [validate](#validate)\n- [assertSchema](#assertschema)\n- [trim](#trim)\n- [fill](#fill)\n- [sanitize](#sanitize)\n- [bind](#bind)\n- [SchemaError](#schemaerror)\n- [addProperty](#addproperty)\n- [extend](#extend)\n- [oneOfRegex](#oneofregex)\n\n### hasSchema\n\nReturns `true` if the given schema exists in the collection. Curried function.\n\n```typescript\nimport { hasSchema } from '@cypress/schema-tools'\nimport { schemas } from './schemas'\nhasSchema(schemas, 'Name', '1.0.0') // true\nhasSchema(schemas)('FooBarBaz')('1.0.0') // false\n```\n\n### documentSchemas\n\nYou can document your schemas using provided method. Example code file\n\n```typescript\nimport { documentSchemas } from '@cypress/schema-tools'\nimport { schemas } from './schemas'\nimport { formats } from './formats'\nconsole.log(documentSchemas(schemas, formats))\n```\n\nCall it from your NPM scripts\n\n```json\n{\n  \"scripts\": {\n    \"document\": \"ts-node ./document.ts \u003e schemas.md\"\n  },\n  \"devDependencies\": {\n    \"ts-node\": \"5.0.1\",\n    \"typescript\": \"2.8.1\"\n  }\n}\n```\n\nIf you want to tell where a schema is coming from, you can set package name, which will add a note to the output Markdown\n\n```typescript\nimport { setPackageName, documentSchemas } from '@cypress/schema-tools'\nimport { schemas } from './schemas'\nsetPackageName(schemas, 'my-schemas')\nconsole.log(documentSchemas(schemas, formats))\n// each schema will have a note that it was defined in \"my-schemas\"\n```\n\n### validate\n\nChecks a given object against a schema and returns list of errors if the object does not pass the schema. Returns `true` if the object passes schema, and a list of strings if there are errors (I know, we should use [Either or Validation](http://folktale.origamitower.com/api/v2.1.0/en/folktale.validation.html)).\n\n```ts\nimport { validate } from '@cypress/schema-tools'\n// see example in ./test/example-schemas.ts\nimport { schemas } from './my-schemas'\nimport { formats } from './my-formats'\nconst validatePerson100 = validate(schemas, formats)('person', '1.0.0')\nconst result = validatePerson100(someObject)\nif (result === true) {\n  // all good\n} else {\n  const errorMessage = result.join('\\n')\n  console.error(errorMessage)\n}\n```\n\nTypical validation messages are\n\n```\ndata.createdAt is required\ndata.createdAt must be date-time format\n```\n\nTo stop after finding initial set of errors, pass `greedy = false` flag\n\n```js\nconst validatePerson100 = validate(schemas, formats, false)('person', '1.0.0')\n```\n\n### assertSchema\n\nChecks a given object against schemas (and formats) and throws a [SchemaError](#schemaerror) if the object violates the given schema.\n\n```js\ntry {\n  assertSchema(schemas, formats)('Person', '1.0.0')(object)\n} catch (e) {\n  console.error(e.message)\n  // can also inspect individual fields, see SchemaError\n}\n```\n\nYou can substitute some fields from example object to help with dynamic data. For example, to avoid breaking on invalid `id` value, we can tell `assertSchema` to use `id` value from the example object.\n\n```js\nconst o = {\n  name: 'Mary',\n  age: -1,\n}\nassertSchema(schemas, formats)('Person', '1.0.0', {\n  substitutions: ['age'],\n})(o)\n// everything is good, because the actual object asserted was\n// {name: 'Mary', age: 10}\n```\n\nYou can also limit the error message and omit some properties. Typically the error message with include list of errors, current and example objects, which might create a wall of text. To omit `object` and `example` but leave other fields when forming error message use\n\n```js\nconst o = {\n  name: 'Mary',\n  age: -1,\n}\nassertSchema(schemas, formats)('Person', '1.0.0', {\n  omit: {\n    object: true,\n    example: true,\n  },\n})(o)\n// Error message is much much shorter, only \"errors\" and label will be there\n```\n\nBy default the json schema check is [greedy](https://github.com/mafintosh/is-my-json-valid#greedy-mode-tries-to-validate-as-much-as-possible) but you can limit it via an option\n\n```js\nassertSchema(schemas, formats)('Person', '1.0.0', { greedy: false })\n```\n\n### trim\n\nOften you have an object that has _more_ properties than the schema allows. For example if you have new result that should go to \"older\" clients, you might want to `trim` the result object and then assert schema.\n\n```js\nimport { trim } from '@cypress/schema-tools'\nconst trimPerson = trim(schemas, 'Person', '1.0.0')\nconst person = ... // some result with lots of properties\nconst trimmed = trimPerson(person)\n// trimmed should be valid Person 1.0.0 object\n// if the values are actually matching Person@1.0.0\n// all extra properties should have been removed\n```\n\n### fill\n\nThe opposite of `trim`. Tries to fill missing object properties with explicit default values from the schema. See [test/fill-test.ts](test/fill-test.ts) for example.\n\n### sanitize\n\nIf you schema has dynamic data, like timestamps or uuids, it is impossible to compare objects without first deleting some fields, breaking the schema. To solve this you can mark some properties with format and if that format has a default value, you can replace all dynamic values with default ones.\n\nIn the example below the `name` property has format called `name` like this\n\n```js\nname: {\n  type: 'string',\n  format: 'name'\n}\n```\n\nNow we can sanitize any object which will replace `name` value with default value, but will keep other properties unchanged.\n\n```js\nimport { sanitize, getDefaults } from '@cypress/schema-tools'\nconst name: CustomFormat = {\n  name: 'name',\n  description: 'Custom name format',\n  detect: /^[A-Z][a-z]+$/,\n  defaultValue: 'Buddy',\n}\nconst exampleFormats: CustomFormats = {\n  name,\n}\nconst formatDefaults = getDefaults(exampleFormats)\nconst object = {\n  name: 'joe',\n  age: 21,\n}\nconst sanitizePerson = sanitize(schemas, formatDefaults)('person', '1.0.0')\n// now pass any object with dynamic \"name\" property\nconst result = sanitizePerson(object)\n// result is {name: 'Buddy', age: 21}\n```\n\nFor another example see [test/sanitize-test.ts](test/sanitize-test.ts)\n\n### bind\n\nThere are multiple methods to validate, assert or sanitize an object against a schema. All take schemas and (optional) formats. But a project using schema tools probably has a single collection of schemas that it wants to use again and again. The `bind` method makes it easy to bind the first argument in each function to a schema collection and just call methods with an object later.\n\n```js\nimport { schemas } from './my-schemas'\nimport { formats } from './my-formats'\nimport { bind } from '@cypress/schema-tools'\nconst api = bind({ schemas, formats })\napi.assertSchema('name', '1.0.0')(someObject)\n```\n\nSee [test/bind-test.ts](test/bind-test.ts) for examples\n\n### SchemaError\n\nWhen asserting an object against a schema a custom error is thrown. It is an instance of `Error`, with a very detailed message. It also has additional properties.\n\n- `errors` is the list of strings with individual validation errors\n- `object` the object being validated\n- `example` example object for the schema\n- `schemaName` is the title of the schema, like `Person`\n- `schemaVersion` the version like `1.0.0` of the schema violated, if known.\n\n### addProperty\n\nYou can easily extend existing schema using included `addProperty` function. See [src/actions.ts](src/actions.ts) and [test/add-property-test.ts](test/add-property-test.ts) for examples.\n\n### extend\n\nRather than add a single property at a time, you can simply use `extend(existingSchema, newSchemaObj)`.\n\nThe `existingSchema` will be deep cloned and have the `newSchemaObj` properties merged in.\n\nIf `newSchemaObj.version` is not provided, then the previous schema's semver `minor` property will be bumped by one.\n\nFields like `required` are automatically unioned.\n\nSee [src/actions.ts](src/actions.ts) and [test/extend-schema-test.ts](test/extend-schema-test.ts) for examples.\n\n### oneOfRegex\n\nA little utility function to create a regular expression to match only the given strings.\n\n```js\nimport { oneOfRegex } from '@cypress/schema-tools'\nconst r = oneOfRegex('foo', 'bar')\nr.test('foo') // true\nr.test('bar') // true\nr.toString() // \"/^(foo|bar)$/\"\n```\n\n## Debugging\n\nTo see log messages from this module, run with `DEBUG=schema-tools`\n\n## Testing\n\nUses [ava-ts](https://github.com/andywer/ava-ts#readme) to run Ava test runner directly against TypeScript test files. Use `npm t` to build and test everything in the `test` folder.\n\nTo run a single test file, use command\n\n```\nnpx ava-ts test/\u003cfile-name.ts\u003e\n```\n\nTo update snapshots and use verbose reporter (prints test names)\n\n```\nnpx ava-ts test/\u003cfile-name.ts\u003e --verbose -u\n```\n\n## License\n\nThis project is licensed under the terms of the [MIT license](LICENSE.md).\n\n[renovate-badge]: https://img.shields.io/badge/renovate-app-blue.svg\n[renovate-app]: https://renovateapp.com/\n[json-schema]: http://json-schema.org/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcypress-io%2Fschema-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcypress-io%2Fschema-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcypress-io%2Fschema-tools/lists"}