json-schema-library 11.1.0 → 11.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/.mocharc.js +1 -0
  2. package/CHANGELOG.md +11 -0
  3. package/README.md +21 -13
  4. package/bowtie/.editorconfig +21 -0
  5. package/bowtie/.prettierrc +6 -0
  6. package/bowtie/BOWTIE.md +54 -0
  7. package/bowtie/Dockerfile +6 -0
  8. package/bowtie/bowtie-api.ts +101 -0
  9. package/bowtie/bowtie-jlib.ts +150 -0
  10. package/bowtie/bowtie.test.ts +267 -0
  11. package/bowtie/package.json +11 -0
  12. package/bowtie/tsconfig.json +12 -0
  13. package/dist/index.cjs +1 -1
  14. package/dist/index.d.cts +66 -503
  15. package/dist/index.d.mts +66 -503
  16. package/dist/index.mjs +1 -1
  17. package/dist/jlib.js +2 -13
  18. package/dist/remotes/index.cjs +1 -0
  19. package/dist/remotes/index.d.cts +7 -0
  20. package/dist/remotes/index.d.mts +7 -0
  21. package/dist/remotes/index.mjs +1 -0
  22. package/dist/types-B2wwNWyo.d.cts +513 -0
  23. package/dist/types-BhTU1l2h.d.mts +513 -0
  24. package/index.ts +0 -3
  25. package/package.json +14 -8
  26. package/src/Draft.ts +1 -1
  27. package/src/Keyword.ts +2 -3
  28. package/src/SchemaNode.ts +9 -0
  29. package/src/compileSchema.test.ts +52 -0
  30. package/src/compileSchema.ts +53 -3
  31. package/src/draft04/keywords/$ref.ts +22 -14
  32. package/src/draft04/keywords/exclusiveMaximum.ts +14 -0
  33. package/src/draft04/keywords/exclusiveMinimum.ts +14 -0
  34. package/src/draft04/validateSchema.test.ts +20 -0
  35. package/src/draft04.ts +2 -2
  36. package/src/draft06/keywords/$ref.ts +15 -5
  37. package/src/draft06.ts +2 -2
  38. package/src/draft07.ts +2 -2
  39. package/src/draft2019-09/keywords/$ref.test.ts +3 -1
  40. package/src/draft2019-09/keywords/$ref.ts +44 -30
  41. package/src/draft2019-09/keywords/additionalItems.ts +33 -10
  42. package/src/draft2019-09/keywords/items.ts +32 -10
  43. package/src/draft2019-09/keywords/unevaluatedItems.ts +19 -6
  44. package/src/draft2019-09/methods/getData.ts +1 -1
  45. package/src/draft2019-09/validateSchema.test.ts +28 -0
  46. package/src/draft2019.ts +1 -1
  47. package/src/draft2020.ts +1 -1
  48. package/src/errors/errors.ts +4 -0
  49. package/src/formats/formats.ts +35 -28
  50. package/src/formats/hyperjump.d.ts +172 -0
  51. package/src/keywords/$ref.ts +50 -17
  52. package/src/keywords/oneOf.test.ts +3 -3
  53. package/src/keywords/properties.ts +1 -1
  54. package/src/keywords/propertyDependencies.ts +1 -1
  55. package/src/methods/getData.ts +1 -1
  56. package/src/settings.ts +27 -1
  57. package/src/validateNode.ts +4 -1
  58. package/tsconfig.json +11 -4
  59. package/tsconfig.test.json +9 -2
  60. package/tsdown.config.ts +1 -1
  61. package/Dockerfile +0 -6
  62. package/bowtie_jlib.js +0 -140
  63. package/remotes/draft04.json +0 -150
  64. package/remotes/draft06.json +0 -155
  65. package/remotes/draft07.json +0 -155
  66. package/remotes/draft2019-09.json +0 -42
  67. package/remotes/draft2019-09_meta_applicator.json +0 -53
  68. package/remotes/draft2019-09_meta_content.json +0 -14
  69. package/remotes/draft2019-09_meta_core.json +0 -54
  70. package/remotes/draft2019-09_meta_format.json +0 -11
  71. package/remotes/draft2019-09_meta_meta-data.json +0 -34
  72. package/remotes/draft2019-09_meta_validation.json +0 -95
  73. package/remotes/draft2020-12.json +0 -55
  74. package/remotes/draft2020-12_meta_applicator.json +0 -45
  75. package/remotes/draft2020-12_meta_content.json +0 -14
  76. package/remotes/draft2020-12_meta_core.json +0 -48
  77. package/remotes/draft2020-12_meta_format_annotation.json +0 -11
  78. package/remotes/draft2020-12_meta_format_assertion.json +0 -11
  79. package/remotes/draft2020-12_meta_meta_data.json +0 -34
  80. package/remotes/draft2020-12_meta_unevaluated.json +0 -12
  81. package/remotes/draft2020-12_meta_validation.json +0 -87
  82. package/remotes/index.ts +0 -48
package/.mocharc.js CHANGED
@@ -1,4 +1,5 @@
1
1
  process.env.TS_NODE_PROJECT = "./tsconfig.test.json";
2
+ process.env.JLIB_TEST_RUN = "true";
2
3
 
3
4
  module.exports = {
4
5
  "node-option": ["import=tsx"]
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  ## Changelog
2
2
 
3
+ ### v11.3.0
4
+
5
+ - added option 'draft' as fallback for a missing `$schema` id
6
+ - added properties to merge when resolvinf a $ref to `settings.PROPERTIES_TO_MERGE`
7
+
8
+ ### v11.2.0
9
+
10
+ - introduced `throwOnInvalidRef` to abort validation when a $ref cannot be resolved
11
+ - added export of meta-schema for all drafts using `import "json-schema-library/remotes"`
12
+ - added support for format validations: `idn-hostname`, `iri`, `iri-reference`
13
+
3
14
  ### v11.1.0
4
15
 
5
16
  - introduced upcoming keyword `propertyDependenciesKeyword` to package export
package/README.md CHANGED
@@ -58,6 +58,12 @@ type CompileOptions = {
58
58
  remote: SchemaNode;
59
59
  // if format-validations should create errors. Defaults to true
60
60
  formatAssertion: boolean | "meta-schema";
61
+ /** set to true to throw an Error on errors in input schema. Defaults to false */
62
+ throwOnInvalidSchema?: boolean;
63
+ /** set to true to collect unknown keywords of input schema in `node.schemaAnnotations`. Defaults to false */
64
+ withSchemaAnnotations?: boolean;
65
+ /** set to true to throw an Error when encountering an unresolvable ref */
66
+ throwOnInvalidRef?: boolean;
61
67
  // default options for all calls to node.getData()
62
68
  getDataDefaultOptions?: {
63
69
  // Add all properties (required and optional) to the generated data
@@ -110,7 +116,7 @@ const root = compileSchema({ properties: 123 }, { throwOnInvalidSchema: true });
110
116
  // throws Error
111
117
  ```
112
118
 
113
- <details><summary>Example for validation errors</summary>
119
+ <details><summary>Example for schema validation errors</summary>
114
120
 
115
121
  ---
116
122
 
@@ -148,19 +154,21 @@ This collects all JSON Schema keywords not part of the used draft and any custom
148
154
  ---
149
155
 
150
156
  ```ts
151
- const { schemaErrors } = compileSchema({ options: {} }, { withSchemaAnnotations: true });
152
- console.log(schemaErrors[0]);
157
+ const { schemaAnnotations } = compileSchema({ unknown: true }, { withSchemaAnnotations: true });
158
+ console.log(schemaAnnotations[0]);
153
159
  {
154
- type: 'annotation',
155
- code: 'unknown-keyword-warning',
156
- message: "Keyword 'options' is not a valid keyword to draft 'draft-2020-12'",
157
- data: {
158
- pointer: '#/options',
159
- schema: { options: {} },
160
- value: 'options',
161
- draft: 'draft-2020-12'
162
- }
163
- }
160
+ type: "annotation",
161
+ code: "unknown-keyword-warning",
162
+ message: "Keyword 'unknown' is not a valid keyword to draft 'draft-2020-12'",
163
+ data: {
164
+ pointer: "#/unknown",
165
+ schema: {
166
+ unknown: true
167
+ },
168
+ value: "unknown",
169
+ draft: "draft-2020-12"
170
+ }
171
+ }
164
172
  ```
165
173
 
166
174
  ---
@@ -0,0 +1,21 @@
1
+ # EditorConfig helps developers define and maintain consistent
2
+ # coding styles between different editors and IDEs
3
+ # editorconfig.org
4
+
5
+ root = true
6
+
7
+ [*]
8
+ indent_style = space
9
+ indent_size = 4
10
+ end_of_line = lf
11
+ charset = utf-8
12
+ trim_trailing_whitespace = true
13
+ insert_final_newline = true
14
+
15
+ [*.md]
16
+ trim_trailing_whitespace = false
17
+ indent_size = 2
18
+
19
+ [package.json]
20
+ indent_style = space
21
+ indent_size = 2
@@ -0,0 +1,6 @@
1
+ {
2
+ "printWidth": 120,
3
+ "singleQuote": false,
4
+ "bracketSpacing": true,
5
+ "trailingComma": "none"
6
+ }
@@ -0,0 +1,54 @@
1
+ # install
2
+
3
+ brew install bowtie-json-schema/tap/bowtie
4
+ https://docs.bowtie.report/en/stable/implementers/
5
+
6
+ > docker build -t localhost/jlib .
7
+ > bowtie suite -i localhost/jlib https://github.com/json-schema-org/JSON-Schema-Test-Suite/tree/main/tests/draft2020-12 | bowtie summary --show failures
8
+ > bowtie suite -i localhost/jlib https://github.com/json-schema-org/JSON-Schema-Test-Suite/blob/main/tests/draft7 --fail-fast
9
+
10
+ # build
11
+
12
+ docker build -t localhost/jlib .
13
+
14
+ # test without bowtie
15
+
16
+ docker run --rm localhost/jlib
17
+ echo '{"cmd":"start","version":1}' | docker run -i jlib
18
+ echo '{"cmd":"run","seq":1,"case":{"schema":{"type": "string"},"tests":["valid",999]}}' | docker run -i jlib
19
+ echo '{"cmd":"dialect","dialect":"http://json-schema.org/draft-07/schema#"}' | docker run -i jlib
20
+ echo '{"cmd":"stop"}' | docker run -i jlib
21
+
22
+ # test with bowtie
23
+
24
+ > docker build -t localhost/jlib .
25
+ > then:
26
+
27
+ bowtie smoke -i localhost/jlib
28
+ bowtie suite -i localhost/jlib https://github.com/json-schema-org/JSON-Schema-Test-Suite/blob/main/tests/draft7/type.json | bowtie summary --show failures
29
+
30
+ bowtie suite -i localhost/jlib https://github.com/json-schema-org/JSON-Schema-Test-Suite/tree/main/tests/draft4 | bowtie summary --show failures
31
+ bowtie suite -i localhost/jlib https://github.com/json-schema-org/JSON-Schema-Test-Suite/tree/main/tests/draft6 | bowtie summary --show failures
32
+ bowtie suite -i localhost/jlib https://github.com/json-schema-org/JSON-Schema-Test-Suite/tree/main/tests/draft7 | bowtie summary --show failures
33
+ bowtie suite -i localhost/jlib https://github.com/json-schema-org/JSON-Schema-Test-Suite/tree/main/tests/draft2019-09 | bowtie summary --show failures
34
+ bowtie suite -i localhost/jlib https://github.com/json-schema-org/JSON-Schema-Test-Suite/tree/main/tests/draft2020-12 | bowtie summary --show failures
35
+
36
+ bowtie suite -i localhost/jlib https://github.com/json-schema-org/JSON-Schema-Test-Suite/tree/main/tests/draft7 > draft7.json
37
+
38
+ **Fails**
39
+ bowtie suite $(bowtie filter-implementations | sed 's/^/-i /') https://github.com/json-schema-org/JSON-Schema-Test-Suite/tree/main/tests/draft2020-12 >draft2020-12.json
40
+
41
+ bowtie suite $(bowtie filter-implementations | sed 's/^jlib/-i /') https://github.com/json-schema-org/JSON-Schema-Test-Suite/tree/main/tests/draft2020-12 >draft2020-12.json
42
+
43
+ bowtie suite -i localhost/jlib draft7 | bowtie summary
44
+ bowtie suite -i localhost/jlib https://github.com/json-schema-org/JSON-Schema-Test-Suite/blob/main/tests/draft7/type.json | bowtie summary --show failures
45
+ bowtie suite -i localhost/jlib https://github.com/json-schema-org/JSON-Schema-Test-Suite/blob/main/tests/draft7 | bowtie summary --show failures
46
+ bowtie suite -i localhost/jlib draft7 | bowtie summary --show failures
47
+ bowtie validate -i localhost/jlib draft7 | bowtie summary --show failures
48
+
49
+ **Does not finish**
50
+ bowtie run --dialect 7 -i localhost/jlib
51
+ bowtie validate -i localhost/jlib <(printf '{"type": "integer"}') <(printf 37) <(printf '"foo"')
52
+ bowtie run -i localhost/jlib draft7 | bowtie summary --show failures
53
+ bowtie run -i localhost/jlib -V '{"description": "test case 1", "schema": {}, "tests": [{"description": "a test", "instance": {}}]}'
54
+ bowtie run -i localhost/jlib -V --fail-fast
@@ -0,0 +1,6 @@
1
+ FROM node:24-alpine
2
+ COPY . /usr/app
3
+ WORKDIR /usr/app
4
+ RUN npm install --omit=dev
5
+ RUN npm -g install tsm
6
+ CMD ["tsm", "bowtie-jlib.ts"]
@@ -0,0 +1,101 @@
1
+ import readline from "readline/promises";
2
+ import { JsonSchema } from "src/types";
3
+
4
+ export type Dialect =
5
+ | "https://json-schema.org/draft/2020-12/schema"
6
+ | "https://json-schema.org/draft/2019-09/schema"
7
+ | "http://json-schema.org/draft-07/schema#"
8
+ | "http://json-schema.org/draft-06/schema#"
9
+ | "http://json-schema.org/draft-04/schema#"
10
+ | "http://json-schema.org/draft-03/schema#";
11
+
12
+ type StartCmd = {
13
+ cmd: "start";
14
+ version: number;
15
+ };
16
+
17
+ type StartCmdResponse = {
18
+ version: number;
19
+ implementation: {
20
+ /** library language */
21
+ language: "typescript" | "typescript";
22
+ /** library name */
23
+ name: string;
24
+ /** library version */
25
+ version: string;
26
+ homepage: string;
27
+ issues: string;
28
+ source: string;
29
+ dialects: Dialect[];
30
+ /** operating system platform */
31
+ os: string;
32
+ /** operating system version */
33
+ os_version: string;
34
+ /** Node.js version */
35
+ language_version: string;
36
+ };
37
+ };
38
+
39
+ type DialectCommand = {
40
+ cmd: "dialect";
41
+ dialect: Dialect;
42
+ };
43
+
44
+ type DialectCmdResponse = { ok: true };
45
+
46
+ type RunCmd = {
47
+ cmd: "run";
48
+ seq: number;
49
+ // dialect: Dialect;
50
+ case: {
51
+ schema: JsonSchema;
52
+ tests: {
53
+ description: string;
54
+ instance: unknown;
55
+ }[];
56
+ registry: Record<string, JsonSchema>;
57
+ };
58
+ };
59
+
60
+ export type RunCmdResponse = {
61
+ seq: number;
62
+ results: ({ valid: boolean } | ErrorResponse)[];
63
+ };
64
+
65
+ export type ErrorResponse = {
66
+ errored: true;
67
+ context: {
68
+ traceback?: string | undefined;
69
+ message: string | undefined;
70
+ };
71
+ };
72
+
73
+ type StopCommand = {
74
+ cmd: "stop";
75
+ };
76
+
77
+ export type Command = StartCmd | RunCmd | DialectCommand | StopCommand;
78
+ export type CommandResponse = RunCmdResponse | StartCmdResponse | DialectCmdResponse | ErrorResponse | undefined;
79
+
80
+ export type CommandMap = {
81
+ /** Start nxet test run, informing bowtie of suppored draft versions and general metadata */
82
+ start: (args: StartCmd) => Promise<StartCmdResponse>;
83
+ /** Set JSON Schema draft-version of following tests */
84
+ dialect: (args: DialectCommand) => Promise<DialectCmdResponse>;
85
+ /** Run test cases for a specfic schema */
86
+ run: (args: RunCmd) => Promise<RunCmdResponse>;
87
+ /** Finalize test run and exit container */
88
+ stop: (args: StopCommand, stdio?: readline.Interface) => Promise<void>;
89
+ };
90
+
91
+ export const createBowtieError = (message: string, stack?: string): ErrorResponse => ({
92
+ errored: true,
93
+ context: {
94
+ message: message,
95
+ traceback: stack
96
+ }
97
+ });
98
+
99
+ export function sendToBowtie(data?: Record<string, unknown>) {
100
+ console.log(JSON.stringify(data ?? createBowtieError("missing response")));
101
+ }
@@ -0,0 +1,150 @@
1
+ /* json-schema-library bowtie integration (test harness) */
2
+ import readline from "readline/promises";
3
+ import process from "node:process";
4
+ import os from "os";
5
+ import packageJson from "json-schema-library/package.json";
6
+ import { compileSchema, type SchemaNode } from "json-schema-library";
7
+ import { remotes } from "json-schema-library/remotes";
8
+ import {
9
+ createBowtieError,
10
+ type Command,
11
+ type CommandMap,
12
+ type CommandResponse,
13
+ type Dialect,
14
+ RunCmdResponse,
15
+ sendToBowtie
16
+ } from "./bowtie-api";
17
+
18
+ /** track command sequence and abort if something is off */
19
+ let state: "started" | "dialect" | "testing" | "stopped" = "stopped";
20
+ /** current JSON Schema draft version to test */
21
+ let dialect: Dialect;
22
+ /** all meta-schemata added as remtoes */
23
+ let remote: SchemaNode;
24
+
25
+ const cmds: CommandMap = {
26
+ start: async (args) => {
27
+ console.assert(args.version === 1, { args });
28
+ console.assert(state === "stopped");
29
+ state = "started";
30
+
31
+ return {
32
+ version: 1,
33
+ implementation: {
34
+ language: "typescript",
35
+ name: "json-schema-library",
36
+ version: packageJson.version,
37
+ homepage: "https://github.com/sagold/json-schema-library",
38
+ issues: "https://github.com/sagold/json-schema-library/issues",
39
+ source: "https://github.com/sagold/json-schema-library",
40
+
41
+ dialects: [
42
+ "https://json-schema.org/draft/2020-12/schema",
43
+ "https://json-schema.org/draft/2019-09/schema",
44
+ "http://json-schema.org/draft-07/schema#",
45
+ "http://json-schema.org/draft-06/schema#",
46
+ "http://json-schema.org/draft-04/schema#"
47
+ ],
48
+ os: os.platform(),
49
+ os_version: os.release(),
50
+ language_version: process.version
51
+ }
52
+ };
53
+ },
54
+
55
+ dialect: async (args) => {
56
+ console.assert(state === "started");
57
+ state = "dialect";
58
+
59
+ dialect = args.dialect;
60
+ remote = compileSchema({ $schema: dialect });
61
+ remotes.forEach((schema) => remote.addRemoteSchema(schema.$id ?? schema.id, schema));
62
+ return { ok: true };
63
+ },
64
+
65
+ run: async (args) => {
66
+ console.assert(state === "dialect" || state === "testing");
67
+ state = "testing";
68
+
69
+ const node = compileSchema(args.case.schema, { remote, draft: dialect, formatAssertion: false });
70
+ for (const id in args.case.registry) {
71
+ node.addRemoteSchema(id, args.case.registry[id]);
72
+ }
73
+ // run test cases and collect results to be sent back to bowtie
74
+ const results: RunCmdResponse["results"] = args.case.tests.map((test) => {
75
+ try {
76
+ return { valid: node.validate(test.instance).valid };
77
+ } catch (e) {
78
+ return createBowtieError(e.message ?? e, e.stack);
79
+ }
80
+ });
81
+ // response to bowtie for run command
82
+ return { seq: args.seq, results: results };
83
+ },
84
+
85
+ stop: async (_, stdio) => {
86
+ console.assert(state === "testing");
87
+ state = "stopped";
88
+
89
+ if (process.env.JLIB_TEST_RUN !== "true") {
90
+ stdio?.close();
91
+ process.exit(0);
92
+ }
93
+ }
94
+ } as const;
95
+
96
+ export async function runCommand(request: Command, stdio?: readline.Interface) {
97
+ let response: CommandResponse = undefined;
98
+ switch (request.cmd) {
99
+ case "start":
100
+ response = await cmds.start(request);
101
+ break;
102
+ case "dialect":
103
+ response = await cmds.dialect(request);
104
+ break;
105
+ case "run":
106
+ try {
107
+ response = await cmds.run(request);
108
+ return response;
109
+ } catch (error) {
110
+ response = {
111
+ seq: request.seq,
112
+ ...createBowtieError((error as Error).message ?? error, (error as Error).stack)
113
+ };
114
+ }
115
+ break;
116
+ case "stop":
117
+ await cmds.stop(request, stdio);
118
+ break;
119
+ }
120
+ return response;
121
+ }
122
+
123
+ function isCommand(value: unknown): value is Command {
124
+ return value != null && typeof value === "object" && "cmd" in value && cmds[value.cmd as keyof typeof cmds] != null;
125
+ }
126
+
127
+ /** listen for commands to be sent to container */
128
+ async function waitForBowtieCommands() {
129
+ const stdio = readline.createInterface({
130
+ input: process.stdin,
131
+ output: process.stdout,
132
+ terminal: false
133
+ });
134
+ for await (const line of stdio) {
135
+ let response;
136
+ try {
137
+ const request = JSON.parse(line);
138
+ response = isCommand(request)
139
+ ? await runCommand(request, stdio)
140
+ : createBowtieError(`Unsupported command received: '${line}'`);
141
+ } catch (e) {
142
+ response = createBowtieError(`Invalid json received: '${line}': ${(e as Error)?.message}`);
143
+ }
144
+ sendToBowtie(response);
145
+ }
146
+ }
147
+
148
+ if (process.env.JLIB_TEST_RUN !== "true") {
149
+ waitForBowtieCommands();
150
+ }