{"id":13564833,"url":"https://github.com/ar-nelson/spartan-schema","last_synced_at":"2025-04-04T19:09:00.718Z","repository":{"id":46511340,"uuid":"349290703","full_name":"ar-nelson/spartan-schema","owner":"ar-nelson","description":"Ultra-minimal JSON schemas with Typescript inference","archived":false,"fork":false,"pushed_at":"2023-03-26T19:06:44.000Z","size":121,"stargazers_count":439,"open_issues_count":0,"forks_count":3,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-28T18:15:30.002Z","etag":null,"topics":["json","json-schema","schema"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ar-nelson.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":"2021-03-19T03:37:56.000Z","updated_at":"2025-01-26T17:30:59.000Z","dependencies_parsed_at":"2024-01-14T03:49:03.993Z","dependency_job_id":"49484d57-1ce5-4d35-943d-64551b6e09fc","html_url":"https://github.com/ar-nelson/spartan-schema","commit_stats":{"total_commits":6,"total_committers":1,"mean_commits":6.0,"dds":0.0,"last_synced_commit":"b6441b7f4f66f0817ed36913fb6c0100e6544048"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ar-nelson%2Fspartan-schema","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ar-nelson%2Fspartan-schema/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ar-nelson%2Fspartan-schema/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ar-nelson%2Fspartan-schema/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ar-nelson","download_url":"https://codeload.github.com/ar-nelson/spartan-schema/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247234921,"owners_count":20905854,"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":["json","json-schema","schema"],"created_at":"2024-08-01T13:01:36.709Z","updated_at":"2025-04-04T19:09:00.702Z","avatar_url":"https://github.com/ar-nelson.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","json"],"sub_categories":[],"readme":"# Spartan Schema\n\nAn ultra-minimal, Typescript-compatible alternative to [JSON\nSchema][json-schema], designed as part of [Osmosis][osmosis].\n\n**Spartan Schema is...**\n\n- **Clear**: Spartan Schemas are singificantly simpler than comparable JSON\n  schemas. Here's a schema that will match objects like\n  `{ name: { first: \"Al\", last: \"Yankovic\" }, age: 62 }`:\n\n   ```json\n   {\n     \"schema\": {\n       \"name\": {\n         \"first\": \"string\",\n         \"middle\": [\"optional\", \"string\"],\n         \"last\": \"string\"\n       },\n       \"age\": \"integer\"\n     }\n   }\n   ```\n\n- **Compatible**: Spartan Schema includes `binary` and `date` types, for\n  languages like YAML and MessagePack that support more data types than JSON.\n  The parser expects a JavaScript object, which can be parsed from any JSON-like\n  format, or written directly in JS/TS source.\n\n- **Minimal**: The entire specification fits on a single page. Spartan Schema\n  can describe itself in 20 lines of YAML:\n\n   ```yaml\n   spartan: 1\n   let:\n     EnumValue: [oneof, null, boolean, number, string]\n     Type:\n     - oneof\n     - [enum, null, 'null', boolean, integer, float, number, string, date, binary]\n     - [array, [enum, enum], [ref, EnumValue], [ref, EnumValue]]\n     - [array, [enum, oneof], [ref, Type], [ref, Type]]\n     - [array, [enum, tuple], [ref, Type], [ref, Type]]\n     - [array, [enum, array], [ref, Type], [ref, Type]]\n     - [tuple, [enum, dictionary], [ref, Type]]\n     - [tuple, [enum, ref], string]\n     - - dictionary\n       - - oneof\n         - [tuple, [enum, optional], [ref, Type]]\n         - [ref, Type]\n   schema:\n     spartan: [optional, [enum, 1]]\n     let: [optional, [dictionary, [ref, Type]]]\n     schema: [ref, Type]\n   ```\n\n- **Statically typed**: Spartan Schema uses [Typescript 4.1 recursive\n  conditional types][types] to convert schemas into Typescript type definitions.\n  A schema written directly in source code can be a single source of truth for\n  both compile-time and runtime typechecking.\n\n   ```typescript\n   import { matchesSchema } from 'spartan-schema';\n\n   // Schemas should be defined with 'as const', for typechecking.\n   const personSchema = {\n     schema: {\n       name: {\n         first: 'string',\n         middle: ['optional', 'string'],\n         last: 'string'\n       },\n       age: 'integer'\n     }\n   } as const;\n\n   const isPerson = matchesSchema(personSchema);\n\n   function loadPerson(json: string) {\n     const data = JSON.parse(json);\n     if (!isPerson(data)) {\n       throw new Error(\"JSON data does not match schema\");\n     }\n\n     // The type of `data` is now:\n     //\n     // { name: { first: string, middle?: string, last: string }, age: number }\n     //\n     // This type was derived from `personSchema`!\n\n     console.log(`Hello, ${data.name.first} ${data.name.last}!`);\n   }\n   ```\n\n## Usage\n\nSpartan Schema is compatible with both Node and Deno, and has no dependencies.\n\nThe repository is written in Deno-compatible Typescript. `mod.ts` can be\nimported directly:\n\n```typescript\nimport {\n  Schema,\n  matchesSchema\n} from 'https://deno.land/x/spartanschema/mod.ts';\n```\n\nThe Node module is built with [`dnt`][dnt], and is available on NPM as\n`spartan-schema`:\n\n```typescript\nimport {\n  Schema,\n  matchesSchema\n} from 'spartan-schema';\n```\n\nAll `deno` build commands are documented in the Makefile. To run the test suite\nand build the Node module, just run `make` (requires Deno).\n\n## The Schema Language\n\n### The Root Object\n\nThe root of a Spartan Schema is an object. This object must contain a `\"schema\"`\nproperty, and may optionally contain `\"spartan\"` and `\"let\"` properties. Other\nproperties are allowed, and will be ignored.\n\n- `\"schema\"`: The schema itself. A single schema type.\n- `\"let\"`: An object whose values are schema types. Its properties are defined\n  as *reference types*, which can be accessed with the `\"ref\"` directive type.\n  - For example, `{ \"let\": { \"Foo\": \"string\" }, \"schema\": [\"ref\", \"Foo\"] }` is\n    equivalent to `{ \"schema\": \"string\" }`.\n- `\"spartan\"`: The Spartan Schema major version of this schema. If present, it\n  must be `1`.\n\n### Schema Types\n\n- Primitive types: `\"string\"`, `\"integer\"`, `\"float\"`, `\"number\"`, `\"binary\"`, `\"date\"`,\n  `\"boolean\"`, `null`.\n  - `\"float\"` is an alias for `\"number\"`.\n  - `\"null\"` can also be written as the literal value `null`.\n- Object type: An object whose keys are schema types. Matches an object with\n  all of the included keys, if those keys' values match their schema types.\n  - Unspecified keys are allowed, and will not be checked.\n  - Keys are required by default. To make a key optional, use the directive type\n    `\"optional\"`: `{ \"optionalKey\": [\"optional\", \u003cvalue type\u003e] }`\n- Directive types: Arrays whose first element is a string. The string is the\n  *name* of the directive, and the rest of the array is the directive's\n  *arguments*.\n  - `\"enum\"` takes an argument list of primitive values (strings, numbers,\n    `true`, `false`, `null`) and matches only those exact values.\n  - `\"oneof\"` takes an argument list of schema types and matches anything that\n    matches at least one of those types.\n  - `\"tuple\"` takes an argument list of schema types and matches an array with\n    that exact length, with each element matching the argument at the same\n    index.\n  - `\"array\"` takes an argument list of schema types.\n    - If it has one argument, it matches an array of any length whose elements\n      all match that argument.\n    - If it has more than one argument, it behaves like `\"tuple\"` with\n      a variable-length suffix: given *N* arguments, `\"array\"` matches an array\n      with at least *N - 1* elements, where each of these elements matches the\n      argument of the same index, followed by 0 or more additional elements\n      which match the last argument.\n  - `\"dictionary\"` takes one schema type argument, and matches an object whose\n    values all match this argument.\n  - `\"ref\"` takes one string argument. Its argument must be a key in the root\n    object's `\"let\"` property. A `\"ref\"` is substituted with the value of the\n    `\"let\"` property that it names.\n    - Recursion is allowed, and `\"ref\"`s can be used inside of `\"let\"` to create\n      infinite types.\n  - `\"optional\"` is only allowed as a value of an object type. It takes one\n    schema type argument. It makes its key in the object type optional, with\n    its argument as the value type.\n\n## Comparison to JSON Schema\n\nSpartan Schema is *much less verbose* than JSON Schema, but has more limited\nfeatures.\n\n(Examples taken from https://json-schema.org/learn/miscellaneous-examples.html)\n\n\u003ctable\u003e\n\u003ctr\u003e\u003cth\u003eJSON Schema\u003c/th\u003e\u003cth\u003eSpartan Schema\u003c/th\u003e\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```json\n{\n  \"$id\": \"https://example.com/person.schema.json\",\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"title\": \"Person\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"firstName\": {\n      \"type\": \"string\",\n      \"description\": \"The person's first name.\"\n    },\n    \"lastName\": {\n      \"type\": \"string\",\n      \"description\": \"The person's last name.\"\n    },\n    \"age\": {\n      \"description\": \"Age in years.\",\n      \"type\": \"integer\",\n      \"minimum\": 0\n    }\n  }\n}\n```\n\n\u003c/td\u003e\u003ctd\u003e\n\n```json\n{\n  \"schema\": {\n    \"firstName\": \"string\",\n    \"lastName\": \"string\",\n    \"age\": \"integer\"\n  }\n}\n```\n\nThis schema is much shorter, but does not include names, URLs, or field\ndescriptions, and cannot specify a minimum for `age`.\n\n\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\n\n```json\n{\n  \"$id\": \"https://example.com/arrays.schema.json\",\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"fruits\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"string\"\n      }\n    },\n    \"vegetables\": {\n      \"type\": \"array\",\n      \"items\": { \"$ref\": \"#/$defs/veggie\" }\n    }\n  },\n  \"$defs\": {\n    \"veggie\": {\n      \"type\": \"object\",\n      \"required\": [ \"veggieName\", \"veggieLike\" ],\n      \"properties\": {\n        \"veggieName\": {\n          \"type\": \"string\",\n          \"description\": \"The name of the vegetable.\"\n        },\n        \"veggieLike\": {\n          \"type\": \"boolean\",\n          \"description\": \"Do I like this vegetable?\"\n        }\n      }\n    }\n  }\n}\n```\n\n\u003c/td\u003e\u003ctd\u003e\n\n```json\n{\n  \"let\": {\n    \"Veggie\": {\n      \"veggieName\": \"string\",\n      \"veggieLike\": \"boolean\"\n    }\n  },\n  \"schema\": {\n    \"fruits\": [\"array\", \"string\"],\n    \"vegetables\": [\"array\", [\"ref\", \"Veggie\"]]\n  }\n}\n```\n\nSpartan Schema supports references, using `\"let\"` and `\"ref\"`. All fields are\nrequired unless marked `\"optional\"`.\n\n\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\n## API\n\nSpartan Schema defines only a few functions that operate on schema objects.\nA schema object is made up of plain JavaScript objects and arrays that match the\nSpartan Schema spec.\n\n### type `Schema`\n\nThe type of valid Spartan Schemas.\n\nWhen writing schemas directly in Typescript code, you should not use this type;\ninstead, use `as const` and let Typescript infer the exact type of the schema.\n\n### type `MatchesSchema\u003cS extends Schema\u003e`\n\nGiven a type `S` that describes the exact shape of a `Schema`,\n`MatchesSchema\u003cS\u003e` is the type of values that match that schema.\n\nFor example, `MatchesSchema\u003c{ schema: { foo: \"string\" } }\u003e` is\n`{ foo: string }`.\n\n`MatchesSchema` is a complex recursive type, and can easily cause the Typescript\ncompiler to fail with a \"Type instantiation is excessively deep and possibly\ninfinite\" error. It should only be used on schema types that are 100% statically\nknown.\n\n### type `PathArray`\n\n`type PathArray = readonly (string | number)[]`\n\nA path to a specific location in a JSON document.\n\n### type `SchemaAssertionError`\n\n`{ json, schema, validationErrors, message }`\n\nA detailed error thrown by `assertMatchesSchema` when schema validation fails.\nIncludes the schema, the JSON that didn't match, and the list of validation\nerrors, complete with JSONPath locations in both the schema and the JSON value.\n\n### function `isSchema(schema, errors?)`\n\nA type predicate that checks whether `schema` is a valid Spartan Schema.\n\n`errors` is a mutable array of `{ message, location }` pairs; if it is present\nand `isSchema` returns false, it will be populated with a list of parsing\nerrors.\n\n### function `matchesSchema(schema)(value, errors?)`\n\nA curried function that checks whether `value` matches `schema` and returns\na boolean.\n\nIf `schema` is statically known at typechecking type (defined with `as const`),\nthen the function returned by `matchesSchema(schema)` will be a type predicate.\n\n`errors` is a mutable array of `{ dataPath, schemaPath, message, children? }`\nobjects. If it is present and `matchesSchema` returns false, it will be\npopulated with a list of validation errors.\n\n### function `assertMatchesSchema(schema)(value, message?)`\n\nA curried function that checks whether `value` matches `schema` and throws\na `SchemaAssertionError` if it doesn't.\n\nIf `schema` is statically known at typechecking type (defined with `as const`),\nthen the function returned by `assertMatchesSchema(schema)` will be a type\nassertion function.\n\n`message` is an optional message string to include in the thrown error.\n\n### function `zeroValue(schema)`\n\nReturns the *zero value* of this schema's root type.\n\n| Type           | Zero value                                    |\n| -------------- | --------------------------------------------- |\n| `null`         | `null`                                        |\n| boolean        | `false`                                       |\n| integer, float | `0`                                           |\n| string         | `\"\"`                                          |\n| binary         | `0`-length `Uint8Array`                       |\n| date           | `new Date(0)` (Jan 1, 1970)                   |\n| object         | object populated with properties' zero values |\n| `oneof`        | zero value of first type                      |\n| `enum`         | first enum value                              |\n| `array`        | `[]`                                          |\n| `tuple`        | array populated with elements' zero values    |\n| `dictionary`   | `{}`                                          |\n\nThis function typechecks the schema it receives. If it is passed a known schema\ntype `S` (defined `as const` in a Typescript file), then its return type will\nbe `MatchesSchema\u003cS\u003e`.\n\nMay throw an exception if the schema type is infinitely recursive.\n\n## License\n\nCopyright \u0026copy; 2021-2023 Adam Nelson\n\nSpartan Schema is distributed under the [Blue Oak Model License][blue-oak]. It\nis a MIT/BSD-style license, but with [some clarifying\nimprovements][why-blue-oak] around patents, attribution, and multiple\ncontributors.\n\n[json-schema]: https://json-schema.org\n[osmosis]: https://github.com/ar-nelson/osmosis-js\n[types]: https://www.typescriptlang.org/docs/handbook/2/conditional-types.html\n[dnt]: https://github.com/denoland/dnt\n[blue-oak]: https://blueoakcouncil.org/license/1.0.0\n[why-blue-oak]: https://writing.kemitchell.com/2019/03/09/Deprecation-Notice.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Far-nelson%2Fspartan-schema","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Far-nelson%2Fspartan-schema","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Far-nelson%2Fspartan-schema/lists"}