@squiz/dx-json-schema-lib 1.79.0 → 1.80.1
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.
- package/CHANGELOG.md +12 -0
- package/jest.config.ts +13 -2
- package/lib/JsonSchemaService.d.ts +34 -0
- package/lib/JsonSchemaService.js +140 -0
- package/lib/JsonSchemaService.js.map +1 -0
- package/lib/JsonSchemaService.spec.d.ts +1 -0
- package/lib/JsonSchemaService.spec.js +1807 -0
- package/lib/JsonSchemaService.spec.js.map +1 -0
- package/lib/JsonValidationService.d.ts +11 -33
- package/lib/JsonValidationService.js +43 -194
- package/lib/JsonValidationService.js.map +1 -1
- package/lib/JsonValidationService.spec.js +19 -1800
- package/lib/JsonValidationService.spec.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/jsonTypeResolution/TypeResolver.d.ts +4 -2
- package/lib/jsonTypeResolution/TypeResolver.js +0 -3
- package/lib/jsonTypeResolution/TypeResolver.js.map +1 -1
- package/lib/jsonTypeResolution/TypeResolver.spec.js +10 -0
- package/lib/jsonTypeResolution/TypeResolver.spec.js.map +1 -1
- package/lib/manifest/v1/DxComponentInputSchema.spec.js +18 -0
- package/lib/manifest/v1/DxComponentInputSchema.spec.js.map +1 -1
- package/lib/manifest/v1/DxContentMetaSchema.json +24 -32
- package/lib/manifest/v1/JobV1.d.ts +23 -18
- package/lib/manifest/v1/__test__/schemas/invalidUiMetadata.json +31 -0
- package/lib/manifest/v1/v1.d.ts +23 -18
- package/lib/manifest/v1/v1.spec.js +3 -66
- package/lib/manifest/v1/v1.spec.js.map +1 -1
- package/lib/primitiveTypes/SquizImage.d.ts +2 -1
- package/lib/primitiveTypes/SquizImage.js.map +1 -1
- package/lib/processValidationResult.d.ts +2 -0
- package/lib/processValidationResult.js +24 -0
- package/lib/processValidationResult.js.map +1 -0
- package/lib/validators/customKeywordValidators.d.ts +2 -0
- package/lib/validators/customKeywordValidators.js +47 -0
- package/lib/validators/customKeywordValidators.js.map +1 -0
- package/lib/validators/customKeywordValidators.spec.d.ts +1 -0
- package/lib/validators/customKeywordValidators.spec.js +100 -0
- package/lib/validators/customKeywordValidators.spec.js.map +1 -0
- package/package.json +2 -5
- package/src/JsonSchemaService.spec.ts +2198 -0
- package/src/JsonSchemaService.ts +159 -0
- package/src/JsonValidationService.spec.ts +26 -2195
- package/src/JsonValidationService.ts +64 -226
- package/src/index.ts +1 -0
- package/src/jsonTypeResolution/TypeResolver.spec.ts +12 -0
- package/src/jsonTypeResolution/TypeResolver.ts +5 -5
- package/src/manifest/v1/DxComponentInputSchema.spec.ts +21 -0
- package/src/manifest/v1/DxContentMetaSchema.json +24 -32
- package/src/manifest/v1/JobV1.ts +23 -23
- package/src/manifest/v1/__test__/schemas/invalidUiMetadata.json +31 -0
- package/src/manifest/v1/v1.spec.ts +3 -73
- package/src/manifest/v1/v1.ts +23 -23
- package/src/primitiveTypes/SquizImage.ts +2 -1
- package/src/processValidationResult.ts +20 -0
- package/src/validators/customKeywordValidators.spec.ts +171 -0
- package/src/validators/customKeywordValidators.ts +53 -0
- package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,159 @@
|
|
1
|
+
import JSONQuery, { Input } from '@sagold/json-query';
|
2
|
+
|
3
|
+
import DxComponentInputSchema from './manifest/v1/DxComponentInputSchema.json';
|
4
|
+
import DxComponentIcons from './manifest/v1/DxComponentIcons.json';
|
5
|
+
import DxContentMetaSchema from './manifest/v1/DxContentMetaSchema.json';
|
6
|
+
import MatrixAssetSchema from './manifest/v1/MatrixAssetSchema.json';
|
7
|
+
|
8
|
+
import Draft07Schema from './manifest/v1/Draft-07.json';
|
9
|
+
|
10
|
+
import JobV1 from './manifest/v1/JobV1.json';
|
11
|
+
import v1 from './manifest/v1/v1.json';
|
12
|
+
import { JSONSchema, Draft } from '@squiz/json-schema-library';
|
13
|
+
|
14
|
+
import { draft07Config } from '@squiz/json-schema-library';
|
15
|
+
import { AnyPrimitiveType, AnyResolvableType, ResolverContext, TypeResolver } from './jsonTypeResolution/TypeResolver';
|
16
|
+
import { JsonResolutionError } from './errors/JsonResolutionError';
|
17
|
+
import { processValidationResult } from './processValidationResult';
|
18
|
+
import { defaultConfig } from '.';
|
19
|
+
|
20
|
+
export const ComponentInputMetaSchema: MetaSchemaInput = {
|
21
|
+
root: DxComponentInputSchema,
|
22
|
+
remotes: {
|
23
|
+
'DxComponentInputSchema.json/DxContentMetaSchema.json': DxContentMetaSchema,
|
24
|
+
},
|
25
|
+
};
|
26
|
+
|
27
|
+
export const RenderInputMetaSchema: MetaSchemaInput = {
|
28
|
+
root: Draft07Schema,
|
29
|
+
};
|
30
|
+
|
31
|
+
export const ManifestV1MetaSchema: MetaSchemaInput = {
|
32
|
+
root: v1,
|
33
|
+
remotes: {
|
34
|
+
'DxComponentInputSchema.json/DxContentMetaSchema.json': DxContentMetaSchema,
|
35
|
+
'/DxComponentInputSchema.json': DxComponentInputSchema,
|
36
|
+
'/DxComponentIcons.json': DxComponentIcons,
|
37
|
+
'/MatrixAssetSchema.json': MatrixAssetSchema,
|
38
|
+
'http://json-schema.org/draft-07/schema': Draft07Schema,
|
39
|
+
'http://json-schema.org/draft-07/schema#': Draft07Schema,
|
40
|
+
},
|
41
|
+
};
|
42
|
+
|
43
|
+
export const JobV1MetaSchema: MetaSchemaInput = {
|
44
|
+
root: JobV1,
|
45
|
+
remotes: {
|
46
|
+
'DxComponentInputSchema.json/DxContentMetaSchema.json': DxContentMetaSchema,
|
47
|
+
'/DxComponentInputSchema.json': DxComponentInputSchema,
|
48
|
+
'http://json-schema.org/draft-07/schema': Draft07Schema,
|
49
|
+
'http://json-schema.org/draft-07/schema#': Draft07Schema,
|
50
|
+
},
|
51
|
+
};
|
52
|
+
|
53
|
+
interface MetaSchemaInput {
|
54
|
+
root: JSONSchema;
|
55
|
+
remotes?: Record<string, JSONSchema>;
|
56
|
+
}
|
57
|
+
/**
|
58
|
+
* A service that can be used to validate and resolve JSON against a schema.
|
59
|
+
*/
|
60
|
+
export class JSONSchemaService<P extends AnyPrimitiveType, R extends AnyResolvableType> {
|
61
|
+
schema: Draft;
|
62
|
+
constructor(private typeResolver: TypeResolver<P, R>, metaSchema: MetaSchemaInput) {
|
63
|
+
this.schema = new Draft(
|
64
|
+
{
|
65
|
+
...defaultConfig,
|
66
|
+
resolveRef: (schema, rootSchema) => this.doResolveRef(schema, rootSchema),
|
67
|
+
validate: (core, data, schema, pointer) => defaultConfig.validate(core, data, schema, pointer),
|
68
|
+
resolveOneOf: (core, data, schema, pointer) => defaultConfig.resolveOneOf(core, data, schema, pointer),
|
69
|
+
},
|
70
|
+
metaSchema.root,
|
71
|
+
);
|
72
|
+
|
73
|
+
for (const [key, value] of Object.entries(metaSchema.remotes || {})) {
|
74
|
+
this.schema.addRemoteSchema(key, value);
|
75
|
+
}
|
76
|
+
|
77
|
+
for (const schema of this.typeResolver.validationSchemaDefinitions) {
|
78
|
+
// Please find a better way of doing this.
|
79
|
+
this.schema.addRemoteSchema(`/${schema.title}.json`, schema as JSONSchema);
|
80
|
+
this.schema.addRemoteSchema(`#/${schema.title}.json`, schema as JSONSchema);
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
private doResolveRef(schema: JSONSchema, rootSchema: JSONSchema): JSONSchema {
|
85
|
+
const initialRef = draft07Config.resolveRef(schema, rootSchema);
|
86
|
+
if (!initialRef) return initialRef;
|
87
|
+
if (!this.typeResolver.isPrimitiveType(initialRef.type)) return initialRef;
|
88
|
+
|
89
|
+
const validationSchemas = this.typeResolver.getValidationSchemaForPrimitive(initialRef.type);
|
90
|
+
// All validation schemas are pre-compiled as remote schemas and are referenced below
|
91
|
+
const fullValidationSchema = {
|
92
|
+
oneOf: validationSchemas.map((schema) => ({ $ref: `${schema.title}.json` })),
|
93
|
+
};
|
94
|
+
return this.schema.compileSchema(fullValidationSchema);
|
95
|
+
}
|
96
|
+
|
97
|
+
/**
|
98
|
+
* Validate an input value against a specified schema
|
99
|
+
* @throws {SchemaValidationError} if the input is invalid
|
100
|
+
* @returns true if the input is valid
|
101
|
+
*/
|
102
|
+
public validateInput(input: unknown, inputSchema: JSONSchema = this.schema.rootSchema): true | never {
|
103
|
+
inputSchema = this.schema.compileSchema(inputSchema);
|
104
|
+
const errors = this.schema.validate(input, inputSchema);
|
105
|
+
return processValidationResult(errors);
|
106
|
+
}
|
107
|
+
|
108
|
+
/**
|
109
|
+
* Resolve an input object by replacing all resolvable shapes with their resolved values
|
110
|
+
* @param input any input object which matches the input schema
|
111
|
+
* @param inputSchema a JSONSchema which provides type information about the input object
|
112
|
+
* @returns the input object with all resolvable shapes resolved
|
113
|
+
*/
|
114
|
+
public async resolveInput(input: Input, inputSchema: JSONSchema, ctx: ResolverContext = {}) {
|
115
|
+
const setters: Array<Promise<(input: Input) => Input>> = [];
|
116
|
+
this.schema.each(
|
117
|
+
input,
|
118
|
+
async (schema, value, pointer) => {
|
119
|
+
// Bug in library for Array item schemas which won't resolve the oneOf schema
|
120
|
+
if (Array.isArray(schema?.oneOf)) {
|
121
|
+
const oldSchema = schema;
|
122
|
+
schema = this.schema.resolveOneOf(value, schema);
|
123
|
+
schema.oneOfSchema = oldSchema;
|
124
|
+
}
|
125
|
+
if (!this.typeResolver.isResolvableSchema(schema)) return;
|
126
|
+
// If its a resolvable schema, it should exist in a oneOf array with other schemas
|
127
|
+
// Including a primitive schema
|
128
|
+
const allPossibleSchemaTitles: Array<string> = schema.oneOfSchema.oneOf.map((o: JSONSchema) =>
|
129
|
+
o.$ref.replace('.json', ''),
|
130
|
+
);
|
131
|
+
|
132
|
+
const primitiveSchema = allPossibleSchemaTitles.find((title) => this.typeResolver.isPrimitiveType(title));
|
133
|
+
if (!primitiveSchema) return;
|
134
|
+
const resolver = this.typeResolver.tryGetResolver(primitiveSchema, schema as any);
|
135
|
+
if (!resolver) return;
|
136
|
+
const setResolvedData = Promise.resolve()
|
137
|
+
.then(() => resolver(value, ctx))
|
138
|
+
.then((resolvedData) => (item: typeof input) => JSONQuery.set(item, pointer, resolvedData, 'replace' as any))
|
139
|
+
.catch((e) => Promise.reject(new JsonResolutionError(e, pointer, value)));
|
140
|
+
setters.push(setResolvedData);
|
141
|
+
},
|
142
|
+
inputSchema,
|
143
|
+
);
|
144
|
+
|
145
|
+
const potentialResolutionErrors = [];
|
146
|
+
for (const resolveResult of await Promise.allSettled(setters)) {
|
147
|
+
if (resolveResult.status === 'rejected') {
|
148
|
+
potentialResolutionErrors.push(resolveResult.reason);
|
149
|
+
continue;
|
150
|
+
}
|
151
|
+
|
152
|
+
input = resolveResult.value(input);
|
153
|
+
}
|
154
|
+
if (potentialResolutionErrors.length) {
|
155
|
+
throw new Error(`Error(s) occurred when resolving JSON:\n${potentialResolutionErrors.join('\n')}`);
|
156
|
+
}
|
157
|
+
return input;
|
158
|
+
}
|
159
|
+
}
|