{"id":20174309,"url":"https://github.com/guiltydolphin/dspv","last_synced_at":"2025-03-03T05:09:37.635Z","repository":{"id":62422102,"uuid":"367339948","full_name":"GuiltyDolphin/dspv","owner":"GuiltyDolphin","description":"JSON parsing for TypeScript with smart type specifications","archived":false,"fork":false,"pushed_at":"2021-07-03T16:56:23.000Z","size":204,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-13T16:18:10.345Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GuiltyDolphin.png","metadata":{"files":{"readme":"README.org","changelog":"CHANGELOG.org","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-05-14T11:20:51.000Z","updated_at":"2021-05-23T19:17:24.000Z","dependencies_parsed_at":"2022-11-01T17:31:47.863Z","dependency_job_id":null,"html_url":"https://github.com/GuiltyDolphin/dspv","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GuiltyDolphin%2Fdspv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GuiltyDolphin%2Fdspv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GuiltyDolphin%2Fdspv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GuiltyDolphin%2Fdspv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GuiltyDolphin","download_url":"https://codeload.github.com/GuiltyDolphin/dspv/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241610996,"owners_count":19990507,"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":[],"created_at":"2024-11-14T01:42:15.070Z","updated_at":"2025-03-03T05:09:37.618Z","avatar_url":"https://github.com/GuiltyDolphin.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"#+TITLE: DSPV - Data-serialisation Processing and Validation\n\nDSPV stands for \"Data-serialisation, Processing, and\nValidation\". DSPV is a module for working with\ndata-serialisation formats such as JSON in JavaScript, and\nmaking it easy to validate and process data straight into\nobjects. DSPV uses TypeScript to ensure that the core is built\nfaithfully, and it is recommended that DSPV be used with\nTypeScript for best results.\n\nDSPV is currently focused on JSON, but the addition of other\nformats such as YAML is on the radar for future.\n\n* Why use this module?\n\nThis module has various benefits, including:\n\n- ability to smartly parse JSON directly into values based on\n  type-like specifications\n- ability to override how basic types (e.g., booleans,\n  numbers) are parsed\n- support for arbitrarily complex schemas that specify how to\n  read JSON into non-standard data structures\n\n* Usage\n\nSchemas map specification names to specifiers that determine\nhow to process data. The default schema provides support for a\nhost of standard types of data (see [[Builtin Specifiers]]).\n\nYou can add new specifications to a schema by using the\n=addSchema= method, as in the following example:\n\n#+BEGIN_SRC typescript\n  class Person {\n      age: number;\n      address: string;\n\n      constructor(age: number, address: string) {\n          this.age = age;\n          this.address = address;\n      }\n  }\n\n  const schemas = Schemas.emptySchemas();\n\n  schemas.addSpec(Person, {\n      description: \"A person with an age and an address\",\n      load: JsonSchema.objectSchema({\n          age: Number,\n          address: String\n      })\n  });\n#+END_SRC\n\nThis adds a specification that can be referenced as =Person=,\nwhich tries to read (=load=) an object with an age field (a\nnumber), and an address field (a string). We can test this out\nby creating a parser and running as follows:\n\n#+BEGIN_SRC typescript\n  const parser = new JsonParser(schemas);\n\n  console.log(parser.parseAsOrThrow('{\"age\": 20, \"address\": \"somewhere on Earth\"}'));\n  // Person { age: 20, address: \"somewhere on Earth\" }\n#+END_SRC\n\nIf we try to give an incorrect age (e.g., a string), or\naddress (e.g., a number,) or gave different fields, we'd be\npresented with a useful error message that incorporates the\n=description=:\n\n#+BEGIN_SRC typescript\n  function tryItOut(text: string) {\n      // 'parseAs' returns an Either value, so we can grab the error message here\n      console.log(parser.parseAs(text, Person).either(err =\u003e err.message, _ =\u003e \"\"));\n  }\n\n  // wrong type for age\n  tryItOut('{\"age\": \"not a number\", \"address\": \"somewhere on Earth\"}');\n  // When trying to read a value for specification: A person with an age and an address\n  // I saw: {\"age\":\"not a number\",\"address\":\"somewhere on Earth\"}\n  // In key: \"age\"\n  // When trying to read a value for specification: number\n  // I saw: \"not a number\"\n  // But this is a string\n\n  // wrong type for address\n  tryItOut('{\"age\": 20, \"address\": 7}');\n  // When trying to read a value for specification: A person with an age and an address\n  // I saw: {\"age\":20,\"address\":7}\n  // In key: \"address\"\n  // When trying to read a value for specification: string\n  // I saw: 7\n  // But this is a number\n\n  // missing a key\n  tryItOut('{\"address\": \"somewhere on Earth\"}');\n  // When trying to read a value for specification: A person with an age and an address\n  // I saw: {\"address\":\"somewhere on Earth\"}\n  // But the following keys are required and were not specified: \"age\"\n\n  // extra key\n  tryItOut('{\"age\": 20, \"address\": \"somewhere on Earth\", \"other key\": 1}');\n  // When trying to read a value for specification: A person with an age and an address\n  // I saw: {\"age\":20,\"address\":\"somewhere on Earth\",\"other key\":1}\n  // But I saw the following keys which are not accepted by the specification: \"other key\"\n#+END_SRC\n\n** Specifiers with arguments\n\nSpecifiers can take arguments, a common example of this is\n=Array= which takes a single spec as an argument which\ndetermines what kinds of things can be in the array. For\nexample, if you wanted to parse an array of booleans, you\ncould do:\n\n#+BEGIN_SRC typescript\n  new JsonParser().parseAsOrThrow(\"[true, false]\", [Array, Boolean]);\n  // [ true, false ]\n#+END_SRC\n\nYou can define your own specifiers that takes arguments by\ndefining =description= and =load= to be functions. Note that\nif either of these functions takes optional arguments, you\nshould specify the =maxArgs= option, which helps provide nicer\nmessages when an incorrect call is made.\n\n#+BEGIN_SRC typescript\n  const myCustomArray = Symbol('myCustomArray');\n\n  const parser = new JsonParser(Schemas.emptySchema().addSpec(myCustomArray, {\n      maxArgs: 2,\n      description: (getDesc) =\u003e (t1, t2 = Boolean) =\u003e `Array of ${getDesc(t1)} and ${getDesc(t2)}`,\n      load: (t1, t2 = Boolean) =\u003e JsonSchema.arraySchema([anyOf, t1, t2], a =\u003e a)\n  }));\n\n  parser.parseAsOrThrow(\"[true, 1, false]\", [myCustomArray, Number]);\n  // [ true, 1, false ]\n\n  parser.parseAsOrThrow('[\"bad\"]', [myCustomArray, Number]);\n  // When trying to read a value for specification: Array of Number and Boolean\n  // I saw: [\"bad\"]\n  // When trying to read a value for specification: [Symbol(anyOf), number, boolean]\n  // I saw: \"bad\"\n  // But this is a string\n\n  parser.parseAsOrThrow('[\"ok\", 7]', [myCustomArray, Number, String]);\n  // [ \"ok\", 7 ]\n\n  parser.parseAsOrThrow(\"[true, 1, false]\", [myCustomArray, Number, String]);\n  // When trying to read a value for specification: Array of Number and String\n  // I saw: [true,1,false]\n  // When trying to read a value for specification: [Symbol(anyOf), number, string]\n  // I saw: true\n  // But this is a boolean\n#+END_SRC\n\n* Builtin Specifiers\n\nThe following specifiers are supported out-of-the-box:\n\n- =anyOf (...TS)= matches if any of the argument specifiers\n  matches. The result is from the first specifier that matches\n- =AnyTy= matches any type of value and returns it literally\n- =Array (T?)= if =T= is not provided, matches an array of any\n  type of value. If =T= is provided as an argument, it matches\n  an array of the given type instead\n- =Boolean= matches a boolean\n- =Map (String, T2?)?= matches an object whose values match\n  =T2=, and returns this as a =Map= from =String= keys to\n  values produced by =T2=. If =T2= is not provided, it\n  defaults to =AnyTy=\n- =null= matches =null=\n- =Number= matches a number\n- =Object (T?)= matches an object whose values match =T= (or\n  =AnyTy= if =T= is not provided)\n- =Set (T?)= the same as =Array(T)= but converts the value to\n  a =Set=\n- =String= matches a string\n- =tuple (...TS)= matches an array whose length must be the\n  same as =TS= and whose every =ith= element matches the =ith=\n  element of =TS=\n\n* Development\n\n** Coverage\n\nTo generate code test coverage, make sure you have access to\nthe =genhtml= tool (e.g., via the [[https://aur.archlinux.org/packages/lcov/][lcov package on AUR]]), then\nrun =make coverage= in the top-level of the project.\n\n** Testing\n\nRun =make test= in the top-level of the project to run the\ntests. If you need to see results for tests that passed, run\n=make test_verbose= or =deno test= instead.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguiltydolphin%2Fdspv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fguiltydolphin%2Fdspv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguiltydolphin%2Fdspv/lists"}