@takeshape/json-schema 11.52.0 → 11.55.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 (50) hide show
  1. package/dist/__tests__/schema-validator.test.d.ts +1 -0
  2. package/dist/__tests__/schema-validator.test.js +295 -0
  3. package/dist/converters/__tests__/schema-converter.test.d.ts +1 -0
  4. package/dist/converters/__tests__/schema-converter.test.js +1134 -0
  5. package/dist/converters/__tests__/search-shape-schema.json +495 -0
  6. package/dist/converters/index.d.ts +1 -2
  7. package/dist/converters/index.js +1 -16
  8. package/dist/converters/schema-converter.d.ts +0 -1
  9. package/dist/converters/schema-converter.js +540 -643
  10. package/dist/index.d.ts +1 -2
  11. package/dist/index.js +1 -16
  12. package/dist/schema-validator.d.ts +1 -2
  13. package/dist/schema-validator.js +163 -189
  14. package/dist/utils/__tests__/references.test.d.ts +1 -0
  15. package/dist/utils/__tests__/references.test.js +121 -0
  16. package/dist/utils/__tests__/type-utils.test.d.ts +1 -0
  17. package/dist/utils/__tests__/type-utils.test.js +143 -0
  18. package/dist/utils/constants.d.ts +0 -1
  19. package/dist/utils/constants.js +49 -7
  20. package/dist/utils/index.d.ts +4 -5
  21. package/dist/utils/index.js +4 -49
  22. package/dist/utils/keys.d.ts +0 -1
  23. package/dist/utils/keys.js +5 -12
  24. package/dist/utils/references.d.ts +0 -1
  25. package/dist/utils/references.js +56 -57
  26. package/dist/utils/type-utils.d.ts +1 -2
  27. package/dist/utils/type-utils.js +36 -53
  28. package/dist/utils/types.d.ts +0 -1
  29. package/dist/utils/types.js +1 -5
  30. package/package.json +18 -25
  31. package/dist/converters/index.d.ts.map +0 -1
  32. package/dist/converters/schema-converter.d.ts.map +0 -1
  33. package/dist/index.d.ts.map +0 -1
  34. package/dist/schema-validator.d.ts.map +0 -1
  35. package/dist/utils/constants.d.ts.map +0 -1
  36. package/dist/utils/index.d.ts.map +0 -1
  37. package/dist/utils/keys.d.ts.map +0 -1
  38. package/dist/utils/references.d.ts.map +0 -1
  39. package/dist/utils/type-utils.d.ts.map +0 -1
  40. package/dist/utils/types.d.ts.map +0 -1
  41. package/es/converters/index.js +0 -1
  42. package/es/converters/schema-converter.js +0 -654
  43. package/es/index.js +0 -1
  44. package/es/schema-validator.js +0 -207
  45. package/es/utils/constants.js +0 -1
  46. package/es/utils/index.js +0 -4
  47. package/es/utils/keys.js +0 -9
  48. package/es/utils/references.js +0 -66
  49. package/es/utils/type-utils.js +0 -36
  50. package/es/utils/types.js +0 -1
@@ -1,207 +0,0 @@
1
- import { visit } from '@takeshape/util';
2
- import Ajv from 'ajv';
3
- import addFormats from 'ajv-formats';
4
- import get from 'lodash/get';
5
- import isString from 'lodash/isString';
6
- import unset from 'lodash/unset';
7
- export function parseDataPath(instancePath) {
8
- return instancePath.substr(1).split('/');
9
- }
10
- function getData(error, data) {
11
- return get(data, parseDataPath(error.instancePath));
12
- }
13
- function ignoreMissing(error) {
14
- // ignore top level missing errors
15
- return !(error.instancePath === '' && error.keyword === 'required');
16
- }
17
- function ignoreNull(error, data, topLevelSchema) {
18
- return !((error.keyword === 'type' || error.keyword === 'oneOf') && getData(error, data) === null && !isInvalidPropertyRequired(topLevelSchema, error));
19
- }
20
- function getErrorFilter(params, data, schema) {
21
- return error => (!params.ignoreMissing || ignoreMissing(error)) && (!params.ignoreNulls || ignoreNull(error, data, schema));
22
- }
23
- export function isInvalidPropertyRequired(topLevelSchema, error) {
24
- const instancePath = parseDataPath(error.instancePath);
25
- const parentDataPath = instancePath.slice(0, instancePath.length - 1);
26
- const parentSchema = followSchemaPath(topLevelSchema, parentDataPath);
27
- const name = getName(error.instancePath);
28
- if (!parentSchema) {
29
- throw new Error('Unexpected error cannot find parent schema');
30
- }
31
- return isRequired(topLevelSchema, parentSchema, name);
32
- }
33
- function isRequired(topLevelSchema, schema, name) {
34
- const schemas = schema.allOf || schema.anyOf || schema.oneOf || [schema];
35
- return schemas.some(childSchema => followRef(topLevelSchema, childSchema)?.required?.includes(name));
36
- }
37
- function getName(path) {
38
- const parts = parseDataPath(path);
39
- return parts[parts.length - 1];
40
- }
41
- export function refToPath(ref) {
42
- return ref.substring(2).split('/');
43
- }
44
- function followRef(topLevelSchema, schema) {
45
- if (schema.$ref) {
46
- const referencedSchema = get(topLevelSchema, refToPath(schema.$ref));
47
- if (!referencedSchema) {
48
- throw new Error(`Could not resolve ${schema.$ref}`);
49
- }
50
- return referencedSchema;
51
- }
52
- return schema;
53
- }
54
-
55
- /**
56
- * Given a schema object traverse it using a "instancePath" and return the schema at that path
57
- */
58
- export function followSchemaPath(topLevelSchema, instancePath) {
59
- const followPath = (schemaObject, path) => {
60
- const schema = followRef(topLevelSchema, schemaObject);
61
- if (path.length === 0) {
62
- return schema;
63
- }
64
- const combinedSchemas = schema.allOf || schema.anyOf || schema.oneOf;
65
- if (combinedSchemas) {
66
- for (const childSchema of combinedSchemas) {
67
- const result = followPath(childSchema, path);
68
- if (result) {
69
- return result;
70
- }
71
- }
72
- }
73
- const [first, ...rest] = path;
74
- if (schema.items && /^\d+$/.exec(first)) {
75
- return followPath(schema.items, rest);
76
- }
77
- const prop = schema?.properties?.[first];
78
- if (prop) {
79
- return rest.length ? followPath(prop, rest) : prop;
80
- }
81
- };
82
- return followPath(topLevelSchema, instancePath);
83
- }
84
- function isSchemaObject(schema) {
85
- return typeof schema === 'object';
86
- }
87
- function getSchemaWithDefinitions(ajv, id) {
88
- if (id.startsWith('#')) {
89
- const rootSchema = ajv.getSchema('#')?.schema;
90
- if (isSchemaObject(rootSchema)) {
91
- const path = refToPath(id);
92
- const {
93
- definitions
94
- } = rootSchema;
95
- return {
96
- ...get(rootSchema, path),
97
- definitions
98
- };
99
- }
100
- }
101
- return ajv.getSchema(id)?.schema;
102
- }
103
- export function validate(ajv, id, data, options) {
104
- const params = {
105
- ignoreMissing: false,
106
- ignoreNulls: true,
107
- errorsText: false,
108
- ...options
109
- };
110
- let valid = ajv.validate(id, data);
111
- let errors;
112
- if (valid) {
113
- errors = [];
114
- } else {
115
- errors = ajv.errors;
116
- if (params.ignoreNulls || params.ignoreMissing) {
117
- const schema = getSchemaWithDefinitions(ajv, id);
118
- if (isSchemaObject(schema)) {
119
- errors = errors.filter(getErrorFilter(params, data, schema));
120
- valid = errors.length === 0;
121
- }
122
- }
123
- }
124
- const errorsText = params.errorsText && !valid ? ajv.errorsText(errors) : '';
125
- return {
126
- valid,
127
- errors,
128
- errorsText
129
- };
130
- }
131
- export { Ajv };
132
- export function createAjv(options) {
133
- const ajv = new Ajv({
134
- discriminator: true,
135
- allErrors: true,
136
- unevaluated: true,
137
- strict: false,
138
- ...options
139
- });
140
- addFormats(ajv);
141
-
142
- /**
143
- * Formats ingested by Stripe OpenAPI and possibly other — trigger warnings
144
- * in the client when Stripe types are loaded.
145
- */
146
- ajv.addFormat('unix-time', /^[0-9]{10}$/);
147
- ajv.addFormat('decimal', /^[0-9]+\.[0-9]{1,12}$/);
148
- return ajv;
149
- }
150
-
151
- /**
152
- * Determine whether a string is a valid regular expression
153
- */
154
- function isValidRegex(str) {
155
- try {
156
- new RegExp(str, 'u');
157
- return true;
158
- } catch {
159
- return false;
160
- }
161
- }
162
-
163
- /**
164
- * Apply various fixes to the schema to work around AJV issues and bugs.
165
- * See inline comments for more.
166
- */
167
- export function fixSchema(schema) {
168
- visit(schema, ['pattern', 'oneOf'], (value, path) => {
169
- const key = path.slice(-1)[0];
170
- const parent = get(schema, path.slice(0, -1));
171
-
172
- /**
173
- * Fix schema by removing any broken regexes that will cause ajv to throw a compile error.
174
- * It is better to remove the invalid regex rather than forgo validation altogether
175
- * This should be fixed in ajv see the comment here
176
- * https://github.com/ajv-validator/ajv/blob/9f1c3eaa4b91ca17b72b122cdac9b108d1ac30cb/lib/vocabularies/validation/pattern.ts#L21
177
- */
178
- if (key === 'pattern') {
179
- if (parent.type === 'string' && (!isString(value) || !isValidRegex(value))) {
180
- unset(schema, path);
181
- }
182
- }
183
- });
184
- return schema;
185
- }
186
- export function createSchemaValidator(schema, metaSchemas = [], options = {}) {
187
- const schemas = Array.isArray(schema) ? schema : [schema];
188
- const ajv = createAjv({
189
- removeAdditional: true,
190
- ...options
191
- });
192
- if (metaSchemas) {
193
- for (const metaSchema of metaSchemas) {
194
- ajv.addMetaSchema(metaSchema);
195
- }
196
- }
197
- for (const schema of schemas) {
198
- ajv.addSchema(fixSchema(schema));
199
- }
200
- const defaultRef = schemas[0].$id;
201
- if (!defaultRef) {
202
- throw Error('Failed to create schema validator: schema is missing $id');
203
- }
204
- return (data, options) => {
205
- return validate(ajv, defaultRef, data, options);
206
- };
207
- }
@@ -1 +0,0 @@
1
- export const jsonSchema7Keys = ['$id', '$schema', '$ref', '$comment', 'title', 'description', 'default', 'readOnly', 'writeOnly', 'examples', 'multipleOf', 'maximum', 'exclusiveMaximum', 'minimum', 'exclusiveMinimum', 'maxLength', 'minLength', 'pattern', 'additionalItems', 'items', 'maxItems', 'minItems', 'uniqueItems', 'contains', 'maxProperties', 'minProperties', 'required', 'properties', 'patternProperties', 'additionalProperties', 'dependencies', 'propertyNames', 'const', 'enum', 'type', 'format', 'contentMediaType', 'contentEncoding', 'if', 'then', 'else', 'allOf', 'anyOf', 'oneOf', 'not', 'definitions', '$defs'];
package/es/utils/index.js DELETED
@@ -1,4 +0,0 @@
1
- export * from './type-utils';
2
- export * from './types';
3
- export * from './references';
4
- export * from './keys';
package/es/utils/keys.js DELETED
@@ -1,9 +0,0 @@
1
- import pick from 'lodash/pick';
2
- import { jsonSchema7Keys } from './constants';
3
-
4
- /**
5
- * Picks only valid JSON Schema 7 keys from the given schema.
6
- */
7
- export function pickJSONSchema7(schema) {
8
- return pick(schema, jsonSchema7Keys);
9
- }
@@ -1,66 +0,0 @@
1
- import { isAllOfSchema, isAnyOfSchema, isOneOfSchema, isPropertySchema, isRefSchema, isSchema } from './type-utils';
2
- const SCHEMA_DEFINITION_PREFIX = ['#/definitions/', '#/$defs/'];
3
- function collectRef(def, key, collect) {
4
- if (isRefSchema(def)) {
5
- collect(def.$ref, key);
6
- } else if (isSchema(def)) {
7
- collectRefs(def, key, collect);
8
- }
9
- }
10
- function collectRefs(def, key, collect) {
11
- if (isPropertySchema(def)) {
12
- for (const d of Object.values(def.properties)) {
13
- collectRef(d, key, collect);
14
- }
15
- } else if (isAllOfSchema(def)) {
16
- for (const d of def.allOf) {
17
- collectRef(d, key, collect);
18
- }
19
- } else if (isAnyOfSchema(def)) {
20
- for (const d of def.anyOf) {
21
- collectRef(d, key, collect);
22
- }
23
- } else if (isOneOfSchema(def)) {
24
- for (const d of def.oneOf) {
25
- collectRef(d, key, collect);
26
- }
27
- } else if (Array.isArray(def.items)) {
28
- for (const d of def.items) {
29
- collectRef(d, key, collect);
30
- }
31
- } else if (def.items) {
32
- if (isSchema(def.items) && isRefSchema(def.items)) {
33
- collect(def.items.$ref, key);
34
- }
35
- } else if (isRefSchema(def)) {
36
- collect(def.$ref, key);
37
- }
38
- }
39
-
40
- /**
41
- * Get all the definitions that are referenced by other definitions.
42
- */
43
- export function getReferenceMap(definitions) {
44
- const references = new Map();
45
- const addToReferenceMap = (ref, key) => {
46
- const refKey = ref.replace(SCHEMA_DEFINITION_PREFIX[0], '').replace(SCHEMA_DEFINITION_PREFIX[1], '');
47
- const refSet = references.get(key) ?? new Set();
48
-
49
- // Circular reference
50
- if (key === refKey) {
51
- return;
52
- }
53
- refSet.add(refKey);
54
- references.set(key, refSet);
55
- const refDef = definitions[refKey];
56
- if (refDef && isSchema(refDef)) {
57
- collectRefs(refDef, key, addToReferenceMap);
58
- }
59
- };
60
- for (const [key, def] of Object.entries(definitions)) {
61
- if (isSchema(def)) {
62
- collectRefs(def, key, addToReferenceMap);
63
- }
64
- }
65
- return references;
66
- }
@@ -1,36 +0,0 @@
1
- export function isSchema(schema) {
2
- return typeof schema !== 'boolean';
3
- }
4
- export function isOneOfSchema(schema) {
5
- return isSchema(schema) && Array.isArray(schema.oneOf);
6
- }
7
- export function isAnyOfSchema(schema) {
8
- return isSchema(schema) && Array.isArray(schema.anyOf);
9
- }
10
- export function isAllOfSchema(schema) {
11
- return isSchema(schema) && Array.isArray(schema.allOf);
12
- }
13
- export function isUnionSchema(schema) {
14
- return isOneOfSchema(schema) || isAnyOfSchema(schema) || isAllOfSchema(schema);
15
- }
16
- export function isObjectSchema(schema) {
17
- return isSchema(schema) && schema.type === 'object';
18
- }
19
- export function isPropertySchema(schema) {
20
- return isObjectSchema(schema) && typeof schema.properties === 'object';
21
- }
22
- export function isArraySchema(schema) {
23
- return isSchema(schema) && schema.type === 'array';
24
- }
25
- export function isListSchema(schema) {
26
- return isArraySchema(schema) && typeof schema.items === 'object' && !Array.isArray(schema.items);
27
- }
28
- export function isTupleSchema(schema) {
29
- return isArraySchema(schema) && Array.isArray(schema.items);
30
- }
31
- export function isEnumSchema(schema) {
32
- return Boolean(isSchema(schema) && schema.enum);
33
- }
34
- export function isRefSchema(schema) {
35
- return Boolean(isSchema(schema) && schema.$ref);
36
- }
package/es/utils/types.js DELETED
@@ -1 +0,0 @@
1
- export {};