项目作者: nullpub

项目描述 :
Generate JsonSchema and TypeScript types at the same time
高级语言: TypeScript
项目地址: git://github.com/nullpub/jsonschema.git
创建时间: 2020-12-02T21:10:01Z
项目社区:https://github.com/nullpub/jsonschema

开源协议:

下载


This Library is now hosted directly in functional. For the latest version look there.

JsonSchema for Deno Coverage Status

A library for constructing JsonSchemas and TypeScript types simultaneously.

Usage

This library is a collection of combinators that can be used to construct
json schemas and their associated TypeScript types at the same time. It follows
the pattern laid down by gcanti in io-ts. Following is the simple usage case:

  1. import * as J from "https://deno.land/x/jsonschema/jsonschema.ts";
  2. /**
  3. * Declare the type using json_schema combinators
  4. */
  5. const MyType = J.type({
  6. foo: J.partial({
  7. bar: J.array(J.literal(1, 2)),
  8. }),
  9. });
  10. /**
  11. * Derive the TypeScript from the JsonSchema instance
  12. * Equivalent to:
  13. *
  14. * type MyType = {
  15. * foo: Partial<{
  16. * bar: readonly (1 | 2)[];
  17. * }>;
  18. * }
  19. */
  20. type MyType = J.TypeOf<typeof MyType>;
  21. /**
  22. * Print the stringified json schema
  23. * Equivalent to:
  24. *
  25. * {
  26. * "definitions": {},
  27. * "properties": {
  28. * "foo": {
  29. * "properties": {
  30. * "bar": {
  31. * "items": {
  32. * "enum": [
  33. * 1,
  34. * 2
  35. * ]
  36. * },
  37. * "type": "array"
  38. * }
  39. * },
  40. * "type": "object"
  41. * }
  42. * },
  43. * "required": [
  44. * "foo"
  45. * ],
  46. * "type": "object"
  47. * }
  48. */
  49. console.log(JSON.stringify(J.print(MyType)));

There is also an export of a Schemable for use with fun.
If you use the functional Schemable make function to create a Schemable you can use
that to generate a jsonschema as well.

  1. import * as J from "https://deno.land/x/jsonschema/jsonschema.ts";
  2. import * as S from "https://deno.land/x/fun@v1.0.0/schemable/schemable.ts";
  3. /**
  4. * Declare the type using schemable combinators
  5. */
  6. const MyType = S.make((s) =>
  7. s.type({
  8. foo: s.partial({
  9. bar: s.array(s.literal(1, 2)),
  10. }),
  11. })
  12. );
  13. /**
  14. * Derive the TypeScript from the Schemable instance
  15. * Equivalent to:
  16. *
  17. * type MyType = {
  18. * foo: Partial<{
  19. * bar: readonly (1 | 2)[];
  20. * }>;
  21. * }
  22. */
  23. type MyType = S.TypeOf<typeof MyType>;
  24. /**
  25. * Generate the JsonSchema from the Schemable
  26. */
  27. const MyTypeJsonSchema = MyType(J.Schemable);
  28. /**
  29. * Print the strigified json schema
  30. * Equivalent to:
  31. *
  32. * {
  33. * "definitions": {},
  34. * "properties": {
  35. * "foo": {
  36. * "properties": {
  37. * "bar": {
  38. * "items": {
  39. * "enum": [
  40. * 1,
  41. * 2
  42. * ]
  43. * },
  44. * "type": "array"
  45. * }
  46. * },
  47. * "type": "object"
  48. * }
  49. * },
  50. * "required": [
  51. * "foo"
  52. * ],
  53. * "type": "object"
  54. * }
  55. */
  56. console.log(JSON.stringify(J.print(MyTypeJsonSchema), null, 2));

As you can see, there is very little difference. The benefit is that
a Schemable can also be used to generate a fun decoder.

Lastly, this library properly handles recursive types/schemas with the lazy combinator. Unfortunately,
the recursive type must be defined as a typescript type since type inference can’t name recursive types for you.

  1. import * as J from "https://deno.land/x/jsonschema/jsonschema.ts";
  2. type Foo = {
  3. foo?: Foo;
  4. bar: string;
  5. };
  6. const Foo: J.JsonSchema<Foo> = J.lazy("Foo", () =>
  7. J.intersect(J.partial({ foo: Foo }), J.type({ bar: J.string }))
  8. );
  9. console.log(JSON.stringify(J.print(Foo), null, 2));
  10. // Prints
  11. // {
  12. // "$ref": "#/definitions/Foo",
  13. // "definitions": {
  14. // "Foo": {
  15. // "allOf": [
  16. // {
  17. // "properties": {
  18. // "foo": {
  19. // "$ref": "#/definitions/Foo"
  20. // }
  21. // },
  22. // "type": "object"
  23. // },
  24. // {
  25. // "properties": {
  26. // "bar": {
  27. // "type": "string"
  28. // }
  29. // },
  30. // "required": [
  31. // "bar"
  32. // ],
  33. // "type": "object"
  34. // }
  35. // ]
  36. // }
  37. // }
  38. // }

Additionally, mutual recursion is also possible:

  1. import * as J from "https://deno.land/x/jsonschema/jsonschema.ts";
  2. const Bar = J.lazy("Bar", () =>
  3. J.type({
  4. foo: Foo,
  5. })
  6. );
  7. type Bar = J.TypeOf<typeof Bar>;
  8. type Foo = {
  9. bar: Bar[];
  10. baz: string;
  11. };
  12. const Foo: J.JsonSchema<Foo> = J.lazy("Foo", () =>
  13. J.type({
  14. bar: J.array(Bar),
  15. baz: J.string,
  16. })
  17. );
  18. console.log(JSON.stringify(J.print(Foo), null, 2));
  19. // {
  20. // "$ref": "#/definitions/Foo",
  21. // "definitions": {
  22. // "Foo": {
  23. // "properties": {
  24. // "bar": {
  25. // "items": {
  26. // "$ref": "#/definitions/Bar"
  27. // },
  28. // "type": "array"
  29. // },
  30. // "baz": {
  31. // "type": "string"
  32. // }
  33. // },
  34. // "required": [
  35. // "bar",
  36. // "baz"
  37. // ],
  38. // "type": "object"
  39. // },
  40. // "Bar": {
  41. // "properties": {
  42. // "foo": {
  43. // "$ref": "#/definitions/Foo"
  44. // }
  45. // },
  46. // "required": [
  47. // "foo"
  48. // ],
  49. // "type": "object"
  50. // }
  51. // }
  52. // }

Api

Types

Type Notes
JsonSchema<A> An alias of the State Monad that evaluates to a [Json.Type, Json.Definitions]
TypeOf<T> A type extraction tool used to get the TypeScript type representation of a JsonSchema<A>
import * as Json from "./types.ts" Partial TypeScript type implementations of actual Json Schema

Combinators

Combinator Description Example
nullable Takes in a JsonSchema<A> and returns a JsonSchema of the union A and null J.nullable(J.string)
literal Takes in a variadic number of Primitive values and a union of those literals J.literal(1, 2, 3, "a", "b", "c")
string Returns a JsonSchema<string> J.string
number Returns a JsonSchema<number> J.number
boolean Returns a JsonSchema<boolean> J.boolean
type Takes in a Record<string, JsonSchema<any> and returns a JsonSchema object with the same shape with all fields required J.type({ foo: J.string, bar: J.number })
partial Takes in a Record<string, JsonSchema<any> and returns a JsonSchema object with the same shape J.partial({ foo: J.string, bar: J.number })
array Takes in a JsonSchema<A> and returns a JsonSchema<Array<A>> J.array(J.string)
record Takes in a JsonSchema<A> and returns a JsonSchema<Record<string, A>> J.record(J.string)
tuple Takes in a variadic number of args like JsonSchema<string>, JsonSchema<number> and returns a JsonSchema<[string, number]> J.tuple(J.string, J.number)
union Takes in a variadic number of and returns thier union J.union(J.number, J.string)
intersect Takes in exactly two schemas and returns their intersection J.intersect(J.partial({ foo: J.number }), J.type({ bar: J.string }))
sum Takes in a tag and a record of JsonSchema that each contain a key with tag as the name and returns a union of the members J.sum('myTag', { foo: J.type({ myTag: J.literal('foo') })})
lazy Takes in a key and a function that returns a JsonSchema and returs a Json Schema $ref J.lazy('Foo', () => J.type({ foo: J.string }))
print Takes in a JsonSchema<A> and returns the actual Json Schema representation J.print(J.string)

Modules

Schemable is a type from fun schemable that abstracts the combinator pattern used in jsonschema.ts. Effectively, instead of using jsonschema.ts combinators directly, one can define a Schemable instance using the make function from hkts schemable and then derive the actual json schema from that.