@squiz/dx-json-schema-lib 1.85.0 → 1.85.2
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/README.md +11 -0
- package/jest.integration.config.ts +26 -0
- package/jsonCompiler.ts +35 -2
- package/lib/JsonSchemaService.allOf.spec.js +77 -0
- package/lib/JsonSchemaService.allOf.spec.js.map +1 -1
- package/lib/JsonSchemaService.d.ts +1 -1
- package/lib/JsonSchemaService.js +11 -10
- package/lib/JsonSchemaService.js.map +1 -1
- package/lib/JsonValidationService.d.ts +3 -2
- package/lib/JsonValidationService.js +21 -91
- package/lib/JsonValidationService.js.map +1 -1
- package/lib/defaultDraftConfig.d.ts +2 -0
- package/lib/defaultDraftConfig.js +81 -0
- package/lib/defaultDraftConfig.js.map +1 -0
- package/lib/formatted-text/v1/formattedTextConstants.d.ts +2 -0
- package/lib/formatted-text/v1/formattedTextConstants.js +6 -0
- package/lib/formatted-text/v1/formattedTextConstants.js.map +1 -0
- package/lib/formatted-text/v1/resolveFormattedTextNodes.d.ts +2 -2
- package/lib/formatted-text/v1/resolveFormattedTextNodes.js +4 -3
- package/lib/formatted-text/v1/resolveFormattedTextNodes.js.map +1 -1
- package/lib/formatted-text/v1/resolveFormattedTextNodes.spec.js +13 -0
- package/lib/formatted-text/v1/resolveFormattedTextNodes.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/manifest/userApi/v1/UserApiManifestV1.d.ts +48 -0
- package/lib/manifest/userApi/v1/UserApiManifestV1.js +9 -0
- package/lib/manifest/userApi/v1/UserApiManifestV1.js.map +1 -0
- package/lib/manifest/userApi/v1/UserApiManifestV1.json +76 -0
- package/lib/manifest/userApi/v1/index.d.ts +2 -0
- package/lib/manifest/userApi/v1/index.js +8 -0
- package/lib/manifest/userApi/v1/index.js.map +1 -0
- package/lib/manifest/userApi/v1/integration-fixtures/invalid-endpoint-extra-public.manifest.json +10 -0
- package/lib/manifest/userApi/v1/integration-fixtures/invalid-endpoint-handler-hyphen.manifest.json +9 -0
- package/lib/manifest/userApi/v1/integration-fixtures/invalid-endpoint-handler-leading-digit.manifest.json +9 -0
- package/lib/manifest/userApi/v1/integration-fixtures/invalid-endpoint-method-invalid.manifest.json +9 -0
- package/lib/manifest/userApi/v1/integration-fixtures/invalid-endpoint-missing-method.manifest.json +8 -0
- package/lib/manifest/userApi/v1/integration-fixtures/invalid-endpoint-missing-path.manifest.json +8 -0
- package/lib/manifest/userApi/v1/integration-fixtures/invalid-full-displayName-empty.manifest.json +16 -0
- package/lib/manifest/userApi/v1/integration-fixtures/invalid-full-manifest-not-object.manifest.json +8 -0
- package/lib/manifest/userApi/v1/integration-fixtures/invalid-full-missing-manifest.manifest.json +7 -0
- package/lib/manifest/userApi/v1/integration-fixtures/invalid-full-missing-schema.manifest.json +15 -0
- package/lib/manifest/userApi/v1/integration-fixtures/invalid-full-name-empty.manifest.json +16 -0
- package/lib/manifest/userApi/v1/integration-fixtures/invalid-full-root-extra-property.manifest.json +17 -0
- package/lib/manifest/userApi/v1/integration-fixtures/invalid-nested-manifest-handlerMap.manifest.json +12 -0
- package/lib/manifest/userApi/v1/integration-fixtures/invalid-nested-manifest-name.manifest.json +10 -0
- package/lib/manifest/userApi/v1/integration-fixtures/invalid-resolved-empty-endpoints.manifest.json +4 -0
- package/lib/manifest/userApi/v1/integration-fixtures/invalid-resolved-no-leading-slash.manifest.json +11 -0
- package/lib/manifest/userApi/v1/integration-fixtures/valid-full-each-http-method.manifest.json +18 -0
- package/lib/manifest/userApi/v1/integration-fixtures/valid-full-no-description.manifest.json +16 -0
- package/lib/manifest/userApi/v1/integration-fixtures/valid-full.manifest.json +22 -0
- package/lib/manifest/userApi/v1/integration-fixtures/valid-resolved-slash-path.manifest.json +14 -0
- package/lib/manifest/userApi/v1/integration-fixtures/valid-resolved.manifest.json +14 -0
- package/lib/manifest/userApi/v1/userApiManifest.integration.spec.d.ts +1 -0
- package/lib/manifest/userApi/v1/userApiManifest.integration.spec.js +201 -0
- package/lib/manifest/userApi/v1/userApiManifest.integration.spec.js.map +1 -0
- package/lib/manifest/userApi/v1/userApiManifestValidation.d.ts +16 -0
- package/lib/manifest/userApi/v1/userApiManifestValidation.js +88 -0
- package/lib/manifest/userApi/v1/userApiManifestValidation.js.map +1 -0
- package/lib/manifest/userApi/v1/userApiManifestValidation.spec.d.ts +1 -0
- package/lib/manifest/userApi/v1/userApiManifestValidation.spec.js +237 -0
- package/lib/manifest/userApi/v1/userApiManifestValidation.spec.js.map +1 -0
- package/package.json +11 -1
- package/src/JsonSchemaService.allOf.spec.ts +85 -0
- package/src/JsonSchemaService.ts +5 -4
- package/src/JsonValidationService.ts +9 -96
- package/src/defaultDraftConfig.ts +89 -0
- package/src/formatted-text/v1/formattedTextConstants.ts +2 -0
- package/src/formatted-text/v1/resolveFormattedTextNodes.spec.ts +16 -0
- package/src/formatted-text/v1/resolveFormattedTextNodes.ts +4 -3
- package/src/index.ts +2 -0
- package/src/manifest/userApi/v1/UserApiManifestV1.json +76 -0
- package/src/manifest/userApi/v1/UserApiManifestV1.ts +50 -0
- package/src/manifest/userApi/v1/index.ts +6 -0
- package/src/manifest/userApi/v1/integration-fixtures/invalid-endpoint-extra-public.manifest.json +10 -0
- package/src/manifest/userApi/v1/integration-fixtures/invalid-endpoint-handler-hyphen.manifest.json +9 -0
- package/src/manifest/userApi/v1/integration-fixtures/invalid-endpoint-handler-leading-digit.manifest.json +9 -0
- package/src/manifest/userApi/v1/integration-fixtures/invalid-endpoint-method-invalid.manifest.json +9 -0
- package/src/manifest/userApi/v1/integration-fixtures/invalid-endpoint-missing-method.manifest.json +8 -0
- package/src/manifest/userApi/v1/integration-fixtures/invalid-endpoint-missing-path.manifest.json +8 -0
- package/src/manifest/userApi/v1/integration-fixtures/invalid-full-displayName-empty.manifest.json +16 -0
- package/src/manifest/userApi/v1/integration-fixtures/invalid-full-manifest-not-object.manifest.json +8 -0
- package/src/manifest/userApi/v1/integration-fixtures/invalid-full-missing-manifest.manifest.json +7 -0
- package/src/manifest/userApi/v1/integration-fixtures/invalid-full-missing-schema.manifest.json +15 -0
- package/src/manifest/userApi/v1/integration-fixtures/invalid-full-name-empty.manifest.json +16 -0
- package/src/manifest/userApi/v1/integration-fixtures/invalid-full-root-extra-property.manifest.json +17 -0
- package/src/manifest/userApi/v1/integration-fixtures/invalid-nested-manifest-handlerMap.manifest.json +12 -0
- package/src/manifest/userApi/v1/integration-fixtures/invalid-nested-manifest-name.manifest.json +10 -0
- package/src/manifest/userApi/v1/integration-fixtures/invalid-resolved-empty-endpoints.manifest.json +4 -0
- package/src/manifest/userApi/v1/integration-fixtures/invalid-resolved-no-leading-slash.manifest.json +11 -0
- package/src/manifest/userApi/v1/integration-fixtures/valid-full-each-http-method.manifest.json +18 -0
- package/src/manifest/userApi/v1/integration-fixtures/valid-full-no-description.manifest.json +16 -0
- package/src/manifest/userApi/v1/integration-fixtures/valid-full.manifest.json +22 -0
- package/src/manifest/userApi/v1/integration-fixtures/valid-resolved-slash-path.manifest.json +14 -0
- package/src/manifest/userApi/v1/integration-fixtures/valid-resolved.manifest.json +14 -0
- package/src/manifest/userApi/v1/userApiManifest.integration.spec.ts +265 -0
- package/src/manifest/userApi/v1/userApiManifestValidation.spec.ts +311 -0
- package/src/manifest/userApi/v1/userApiManifestValidation.ts +54 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const userApiManifestValidation_1 = require("./userApiManifestValidation");
|
|
4
|
+
const SchemaValidationError_1 = require("../../../errors/SchemaValidationError");
|
|
5
|
+
describe('user API manifest validation', () => {
|
|
6
|
+
const validResolved = {
|
|
7
|
+
endpoints: [{ path: '/hello', method: 'GET', handler: 'index.hello' }],
|
|
8
|
+
};
|
|
9
|
+
const validFull = {
|
|
10
|
+
$schema: userApiManifestValidation_1.USER_API_MANIFEST_SCHEMA_URL,
|
|
11
|
+
name: 'api',
|
|
12
|
+
displayName: 'API',
|
|
13
|
+
description: '',
|
|
14
|
+
filesDir: 'src',
|
|
15
|
+
entry: 'index.ts',
|
|
16
|
+
manifest: validResolved,
|
|
17
|
+
};
|
|
18
|
+
/** Resolves `#/definitions/resolvedApiManifest` via the full-manifest root schema only. */
|
|
19
|
+
const wrapResolved = (manifestNested) => ({
|
|
20
|
+
...validFull,
|
|
21
|
+
manifest: manifestNested,
|
|
22
|
+
});
|
|
23
|
+
const endpoint = (overrides = {}) => ({
|
|
24
|
+
path: '/r',
|
|
25
|
+
method: 'GET',
|
|
26
|
+
handler: 'handler',
|
|
27
|
+
...overrides,
|
|
28
|
+
});
|
|
29
|
+
const expectResolvedNestedThrows = (manifestNested) => {
|
|
30
|
+
expect(() => (0, userApiManifestValidation_1.validateUserApiFullManifest)(wrapResolved(manifestNested))).toThrow(SchemaValidationError_1.SchemaValidationError);
|
|
31
|
+
};
|
|
32
|
+
const expectFullThrows = (input) => {
|
|
33
|
+
expect(() => (0, userApiManifestValidation_1.validateUserApiFullManifest)(input)).toThrow(SchemaValidationError_1.SchemaValidationError);
|
|
34
|
+
};
|
|
35
|
+
it('surfaces bundled full manifest schema for CDN / tooling', () => {
|
|
36
|
+
expect(userApiManifestValidation_1.USER_API_FULL_MANIFEST_SCHEMA.type).toBe('object');
|
|
37
|
+
expect(typeof userApiManifestValidation_1.USER_API_MANIFEST_SCHEMA_URL).toBe('string');
|
|
38
|
+
expect(userApiManifestValidation_1.USER_API_MANIFEST_SCHEMA_URL).toContain('dx-json-schema-lib');
|
|
39
|
+
expect(userApiManifestValidation_1.USER_API_MANIFEST_SCHEMA_URL).toContain('manifest/userApiManifest');
|
|
40
|
+
});
|
|
41
|
+
describe('nested resolvedApiManifest rules (validated only through validateUserApiFullManifest)', () => {
|
|
42
|
+
it('accepts canonical resolved manifest when nested under manifest', () => {
|
|
43
|
+
expect((0, userApiManifestValidation_1.validateUserApiFullManifest)(wrapResolved(validResolved))).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
it.each(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'])('accepts HTTP method %s', (method) => {
|
|
46
|
+
expect((0, userApiManifestValidation_1.validateUserApiFullManifest)(wrapResolved({
|
|
47
|
+
endpoints: [endpoint({ path: `/m-${method}`, method })],
|
|
48
|
+
}))).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
it('accepts multiple endpoints without extra endpoint fields', () => {
|
|
51
|
+
expect((0, userApiManifestValidation_1.validateUserApiFullManifest)(wrapResolved({
|
|
52
|
+
endpoints: [
|
|
53
|
+
{ path: '/a', method: 'GET', handler: 'a' },
|
|
54
|
+
{ path: '/b', method: 'POST', handler: 'mod.b' },
|
|
55
|
+
],
|
|
56
|
+
}))).toBe(true);
|
|
57
|
+
});
|
|
58
|
+
it('rejects handlerMap on nested manifest (endpoints only)', () => {
|
|
59
|
+
expectResolvedNestedThrows({
|
|
60
|
+
endpoints: [endpoint()],
|
|
61
|
+
handlerMap: { 'index.hello': './handlers/hello.ts' },
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
it('accepts handlers using $ and nested module paths', () => {
|
|
65
|
+
expect((0, userApiManifestValidation_1.validateUserApiFullManifest)(wrapResolved({
|
|
66
|
+
endpoints: [
|
|
67
|
+
endpoint({ handler: '$default' }),
|
|
68
|
+
endpoint({ handler: 'ns.deep_export' }),
|
|
69
|
+
endpoint({ handler: '_private' }),
|
|
70
|
+
],
|
|
71
|
+
}))).toBe(true);
|
|
72
|
+
});
|
|
73
|
+
it('accepts path with only slash', () => {
|
|
74
|
+
expect((0, userApiManifestValidation_1.validateUserApiFullManifest)(wrapResolved({ endpoints: [endpoint({ path: '/' })] }))).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
it('accepts api-builder prototype document (alternate $schema, endpoints-only nested manifest)', () => {
|
|
77
|
+
expect((0, userApiManifestValidation_1.validateUserApiFullManifest)({
|
|
78
|
+
$schema: 'https://raw.githubusercontent.com/user/api-builder-prototype/main/schemas/api-builder.schema.json',
|
|
79
|
+
name: 'test-api',
|
|
80
|
+
displayName: 'Test Api',
|
|
81
|
+
description: 'An API to test the proxy endpoint',
|
|
82
|
+
entry: 'index.ts',
|
|
83
|
+
filesDir: 'src',
|
|
84
|
+
manifest: {
|
|
85
|
+
endpoints: [
|
|
86
|
+
{ path: '/hello/*', method: 'GET', handler: 'hello' },
|
|
87
|
+
{ path: '/add', method: 'GET', handler: 'add' },
|
|
88
|
+
{ path: '/user/:id/:type', method: 'GET', handler: 'user' },
|
|
89
|
+
{ path: '/proxy', method: 'GET', handler: 'proxy' },
|
|
90
|
+
{ path: '/health', method: 'GET', handler: 'health' },
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
})).toBe(true);
|
|
94
|
+
});
|
|
95
|
+
it('rejects empty endpoints array', () => {
|
|
96
|
+
expectResolvedNestedThrows({ endpoints: [] });
|
|
97
|
+
expectFullThrows({
|
|
98
|
+
...validFull,
|
|
99
|
+
manifest: { endpoints: [] },
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
it('accepts nested manifest with only endpoints (no nested name)', () => {
|
|
103
|
+
expect((0, userApiManifestValidation_1.validateUserApiFullManifest)(wrapResolved({
|
|
104
|
+
endpoints: [endpoint()],
|
|
105
|
+
}))).toBe(true);
|
|
106
|
+
});
|
|
107
|
+
it('rejects nested manifest name property (nested root allows only endpoints)', () => {
|
|
108
|
+
expectResolvedNestedThrows({ name: 'nested-id', endpoints: [endpoint()] });
|
|
109
|
+
expectResolvedNestedThrows({ name: '', endpoints: [endpoint()] });
|
|
110
|
+
});
|
|
111
|
+
it('rejects missing endpoints on nested manifest', () => {
|
|
112
|
+
expectResolvedNestedThrows({ name: 'only-name' });
|
|
113
|
+
});
|
|
114
|
+
it('rejects non-array endpoints on nested manifest', () => {
|
|
115
|
+
expectResolvedNestedThrows({ endpoints: {} });
|
|
116
|
+
});
|
|
117
|
+
it('rejects nested manifest root additionalProperties', () => {
|
|
118
|
+
expectResolvedNestedThrows({ ...validResolved, extraKey: true });
|
|
119
|
+
});
|
|
120
|
+
it('rejects extra properties on an endpoint object', () => {
|
|
121
|
+
expectResolvedNestedThrows({
|
|
122
|
+
endpoints: [{ ...endpoint(), unknownFlag: true }],
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
it.each(['path', 'method', 'handler'])('rejects endpoint missing required field %s', (field) => {
|
|
126
|
+
const ep = endpoint();
|
|
127
|
+
const partial = Object.fromEntries(Object.entries(ep).filter(([k]) => k !== field));
|
|
128
|
+
expectResolvedNestedThrows({
|
|
129
|
+
endpoints: [partial],
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
it('accepts minimal endpoint objects (only path/method/handler)', () => {
|
|
133
|
+
expect((0, userApiManifestValidation_1.validateUserApiFullManifest)(wrapResolved({
|
|
134
|
+
endpoints: [{ path: '/x', method: 'GET', handler: 'h' }],
|
|
135
|
+
}))).toBe(true);
|
|
136
|
+
});
|
|
137
|
+
it('rejects paths without a leading slash', () => {
|
|
138
|
+
expectResolvedNestedThrows({
|
|
139
|
+
endpoints: [endpoint({ path: 'no-leading-slash' })],
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
it('rejects invalid HTTP methods', () => {
|
|
143
|
+
expectResolvedNestedThrows({
|
|
144
|
+
endpoints: [endpoint({ method: 'TRACE' })],
|
|
145
|
+
});
|
|
146
|
+
expectResolvedNestedThrows({
|
|
147
|
+
endpoints: [endpoint({ method: 'get' })],
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
it.each([
|
|
151
|
+
{ handler: '', reason: 'empty handler' },
|
|
152
|
+
{ handler: '9start', reason: 'leading digit' },
|
|
153
|
+
{ handler: 'bad-handler', reason: 'hyphen' },
|
|
154
|
+
{ handler: 'a b', reason: 'space' },
|
|
155
|
+
{ handler: '😀', reason: 'non-ASCII' },
|
|
156
|
+
])('rejects invalid handler ($reason)', ({ handler }) => {
|
|
157
|
+
expectResolvedNestedThrows({
|
|
158
|
+
endpoints: [endpoint({ handler })],
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
it('rejects invalid nested manifest object shapes', () => {
|
|
162
|
+
expectFullThrows(wrapResolved({}));
|
|
163
|
+
expectFullThrows({
|
|
164
|
+
...validFull,
|
|
165
|
+
manifest: [],
|
|
166
|
+
});
|
|
167
|
+
expectFullThrows({
|
|
168
|
+
...validFull,
|
|
169
|
+
manifest: 'nested',
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
describe('validateUserApiFullManifest (root document)', () => {
|
|
174
|
+
it('accepts canonical full manifest', () => {
|
|
175
|
+
expect((0, userApiManifestValidation_1.validateUserApiFullManifest)(validFull)).toBe(true);
|
|
176
|
+
});
|
|
177
|
+
it('accepts omission of optional description', () => {
|
|
178
|
+
const { description: _d, ...noDesc } = validFull;
|
|
179
|
+
expect((0, userApiManifestValidation_1.validateUserApiFullManifest)(noDesc)).toBe(true);
|
|
180
|
+
});
|
|
181
|
+
it('accepts endpoints-only nested manifest when root declares name', () => {
|
|
182
|
+
expect((0, userApiManifestValidation_1.validateUserApiFullManifest)({
|
|
183
|
+
...validFull,
|
|
184
|
+
name: 'root-name',
|
|
185
|
+
manifest: {
|
|
186
|
+
endpoints: [{ path: '/e', method: 'GET', handler: 'eh' }],
|
|
187
|
+
},
|
|
188
|
+
})).toBe(true);
|
|
189
|
+
});
|
|
190
|
+
it('rejects missing root $schema', () => {
|
|
191
|
+
const { $schema: _drop, ...withoutSchema } = validFull;
|
|
192
|
+
expectFullThrows(withoutSchema);
|
|
193
|
+
});
|
|
194
|
+
it('rejects empty $schema string', () => {
|
|
195
|
+
expectFullThrows({ ...validFull, $schema: '' });
|
|
196
|
+
});
|
|
197
|
+
it.each([['name'], ['displayName'], ['filesDir'], ['entry'], ['manifest']])('rejects full manifest missing required field %s', (field) => {
|
|
198
|
+
const { [field]: _removed, ...rest } = validFull;
|
|
199
|
+
expectFullThrows(rest);
|
|
200
|
+
});
|
|
201
|
+
it.each([
|
|
202
|
+
['name', ''],
|
|
203
|
+
['displayName', ''],
|
|
204
|
+
['filesDir', ''],
|
|
205
|
+
['entry', ''],
|
|
206
|
+
])('rejects empty string for %s (minLength 1)', (field, value) => {
|
|
207
|
+
expectFullThrows({
|
|
208
|
+
...validFull,
|
|
209
|
+
[field]: value,
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
it('rejects root additionalProperties on full manifest', () => {
|
|
213
|
+
expectFullThrows({ ...validFull, version: '1' });
|
|
214
|
+
});
|
|
215
|
+
it('rejects nested manifest validation failures (delegates to resolved definition)', () => {
|
|
216
|
+
expectFullThrows({
|
|
217
|
+
...validFull,
|
|
218
|
+
manifest: {
|
|
219
|
+
endpoints: [endpoint(), endpoint({ handler: '$default', path: '/other' })],
|
|
220
|
+
badRootKey: true,
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
expectFullThrows({
|
|
224
|
+
...validFull,
|
|
225
|
+
manifest: { endpoints: [] },
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
it('rejects primitives instead of manifest object root', () => {
|
|
229
|
+
expectFullThrows(null);
|
|
230
|
+
expectFullThrows(undefined);
|
|
231
|
+
expectFullThrows([]);
|
|
232
|
+
expectFullThrows('manifest');
|
|
233
|
+
expectFullThrows({});
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
//# sourceMappingURL=userApiManifestValidation.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"userApiManifestValidation.spec.js","sourceRoot":"","sources":["../../../../src/manifest/userApi/v1/userApiManifestValidation.spec.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@squiz/dx-json-schema-lib",
|
|
3
|
-
"version": "1.85.
|
|
3
|
+
"version": "1.85.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./lib/index.d.ts",
|
|
9
|
+
"default": "./lib/index.js"
|
|
10
|
+
},
|
|
11
|
+
"./lib/*": "./lib/*",
|
|
12
|
+
"./src/*": "./src/*",
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
6
15
|
"private": false,
|
|
7
16
|
"publishConfig": {
|
|
8
17
|
"access": "public"
|
|
@@ -11,6 +20,7 @@
|
|
|
11
20
|
"compile": "tsc",
|
|
12
21
|
"precompile": "ts-node jsonCompiler.ts",
|
|
13
22
|
"test": "jest -c jest.config.ts",
|
|
23
|
+
"test:integration": "jest -c jest.integration.config.ts",
|
|
14
24
|
"test:update-snapshots": "jest -c jest.config.ts --updateSnapshot",
|
|
15
25
|
"clean": "rimraf \"tsconfig.tsbuildinfo\" \"./lib\""
|
|
16
26
|
},
|
|
@@ -507,6 +507,91 @@ describe('JSONSchemaService - AllOf SquizLink/SquizImage Data Preservation', ()
|
|
|
507
507
|
});
|
|
508
508
|
});
|
|
509
509
|
|
|
510
|
+
describe('FormattedText in AllOf', () => {
|
|
511
|
+
it('should preserve FormattedText fields in allOf conditions', async () => {
|
|
512
|
+
const schema: JSONSchema = {
|
|
513
|
+
type: 'object',
|
|
514
|
+
properties: {
|
|
515
|
+
content: {
|
|
516
|
+
type: 'object',
|
|
517
|
+
properties: {
|
|
518
|
+
cardType: { type: 'string', enum: ['standard', 'advanced'] },
|
|
519
|
+
},
|
|
520
|
+
allOf: [
|
|
521
|
+
{
|
|
522
|
+
if: {
|
|
523
|
+
properties: { cardType: { const: 'standard' } },
|
|
524
|
+
},
|
|
525
|
+
then: {
|
|
526
|
+
properties: {
|
|
527
|
+
cardBody: {
|
|
528
|
+
type: 'FormattedText',
|
|
529
|
+
},
|
|
530
|
+
},
|
|
531
|
+
},
|
|
532
|
+
},
|
|
533
|
+
],
|
|
534
|
+
},
|
|
535
|
+
},
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
const inputData = {
|
|
539
|
+
content: {
|
|
540
|
+
cardType: 'standard',
|
|
541
|
+
cardBody: [],
|
|
542
|
+
},
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
const result = (await service.resolveInput(inputData, schema)) as any;
|
|
546
|
+
|
|
547
|
+
expect(result.content.cardBody).toBeDefined();
|
|
548
|
+
expect(result.content.cardBody).toEqual([]);
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
it('should preserve FormattedText arrays in allOf conditions', async () => {
|
|
552
|
+
const schema: JSONSchema = {
|
|
553
|
+
type: 'object',
|
|
554
|
+
properties: {
|
|
555
|
+
content: {
|
|
556
|
+
type: 'object',
|
|
557
|
+
properties: {
|
|
558
|
+
cardType: { type: 'string', enum: ['standard', 'advanced'] },
|
|
559
|
+
},
|
|
560
|
+
allOf: [
|
|
561
|
+
{
|
|
562
|
+
if: {
|
|
563
|
+
properties: { cardType: { const: 'standard' } },
|
|
564
|
+
},
|
|
565
|
+
then: {
|
|
566
|
+
properties: {
|
|
567
|
+
texts: {
|
|
568
|
+
type: 'array',
|
|
569
|
+
items: { type: 'FormattedText' },
|
|
570
|
+
},
|
|
571
|
+
},
|
|
572
|
+
},
|
|
573
|
+
},
|
|
574
|
+
],
|
|
575
|
+
},
|
|
576
|
+
},
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
const inputData = {
|
|
580
|
+
content: {
|
|
581
|
+
cardType: 'standard',
|
|
582
|
+
texts: [[{ type: 'text', value: 'hello' }], [{ type: 'text', value: 'world' }]],
|
|
583
|
+
},
|
|
584
|
+
};
|
|
585
|
+
|
|
586
|
+
const result = (await service.resolveInput(inputData, schema)) as any;
|
|
587
|
+
|
|
588
|
+
expect(result.content.texts).toBeDefined();
|
|
589
|
+
expect(result.content.texts).toHaveLength(2);
|
|
590
|
+
expect(result.content.texts[0]).toEqual([{ type: 'text', value: 'hello' }]);
|
|
591
|
+
expect(result.content.texts[1]).toEqual([{ type: 'text', value: 'world' }]);
|
|
592
|
+
});
|
|
593
|
+
});
|
|
594
|
+
|
|
510
595
|
describe('Performance and Efficiency', () => {
|
|
511
596
|
it('should efficiently handle large SquizLink arrays in allOf', async () => {
|
|
512
597
|
const schema: JSONSchema = {
|
package/src/JsonSchemaService.ts
CHANGED
|
@@ -16,7 +16,8 @@ import { draft07Config } from '@squiz/json-schema-library';
|
|
|
16
16
|
import { AnyPrimitiveType, AnyResolvableType, ResolverContext, TypeResolver } from './jsonTypeResolution/TypeResolver';
|
|
17
17
|
import { JsonResolutionError } from './errors/JsonResolutionError';
|
|
18
18
|
import { processValidationResult } from './processValidationResult';
|
|
19
|
-
import { defaultConfig
|
|
19
|
+
import { defaultConfig } from './defaultDraftConfig';
|
|
20
|
+
import { FORMATTED_TEXT_SCHEMA_ID } from './formatted-text/v1/formattedTextConstants';
|
|
20
21
|
|
|
21
22
|
export const ComponentInputMetaSchema: MetaSchemaInput = {
|
|
22
23
|
root: DxComponentInputSchema,
|
|
@@ -278,7 +279,7 @@ export class JSONSchemaService<P extends AnyPrimitiveType, R extends AnyResolvab
|
|
|
278
279
|
}
|
|
279
280
|
|
|
280
281
|
/**
|
|
281
|
-
* Check if the allOf schema contains arrays with primitive types (SquizLink/SquizImage)
|
|
282
|
+
* Check if the allOf schema contains arrays with primitive types (SquizLink/SquizImage/FormattedText)
|
|
282
283
|
* Used to determine if we need to apply data preservation
|
|
283
284
|
*/
|
|
284
285
|
private hasArraysWithPrimitiveTypes(schema: any): boolean {
|
|
@@ -287,9 +288,9 @@ export class JSONSchemaService<P extends AnyPrimitiveType, R extends AnyResolvab
|
|
|
287
288
|
const checkForPrimitiveArrays = (obj: any): boolean => {
|
|
288
289
|
if (!obj || typeof obj !== 'object') return false;
|
|
289
290
|
|
|
290
|
-
// Check if this is an array with SquizLink/SquizImage items
|
|
291
|
+
// Check if this is an array with SquizLink/SquizImage/FormattedText items
|
|
291
292
|
if (obj.type === 'array' && obj.items?.type) {
|
|
292
|
-
return obj.items.type === 'SquizLink' || obj.items.type === 'SquizImage';
|
|
293
|
+
return obj.items.type === 'SquizLink' || obj.items.type === 'SquizImage' || obj.items.type === 'FormattedText';
|
|
293
294
|
}
|
|
294
295
|
|
|
295
296
|
// Recursively check properties
|
|
@@ -3,111 +3,24 @@ import DxContentMetaSchema from './manifest/v1/DxContentMetaSchema.json';
|
|
|
3
3
|
import FormattedText from './formatted-text/v1/formattedText.json';
|
|
4
4
|
|
|
5
5
|
import { SchemaValidationError } from './errors/SchemaValidationError';
|
|
6
|
-
import { Draft07, JSONSchema, Draft
|
|
6
|
+
import { Draft07, JSONSchema, Draft } from '@squiz/json-schema-library';
|
|
7
7
|
|
|
8
8
|
import { draft07Config } from '@squiz/json-schema-library';
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
SquizLinkType,
|
|
16
|
-
TypeResolverBuilder,
|
|
17
|
-
} from '.';
|
|
18
|
-
import { customFormatValidators } from './validators/customFormatValidators';
|
|
19
|
-
import { customKeywordValidators } from './validators/customKeywordValidators';
|
|
9
|
+
import { FORMATTED_TEXT_SCHEMA_ID } from './formatted-text/v1/formattedTextConstants';
|
|
10
|
+
import * as MANIFEST_MODELS from './manifest/v1/manifestModels';
|
|
11
|
+
import { BaseFormattedTextType, ComponentInputFormattedTextType } from './primitiveTypes/FormattedText';
|
|
12
|
+
import { SquizImageType } from './primitiveTypes/SquizImage';
|
|
13
|
+
import { SquizLinkType } from './primitiveTypes/SquizLink';
|
|
14
|
+
import { TypeResolverBuilder } from './jsonTypeResolution/TypeResolverBuilder';
|
|
20
15
|
import {
|
|
21
16
|
ComponentInputMetaSchema,
|
|
22
17
|
JobV1MetaSchema,
|
|
23
18
|
JSONSchemaService,
|
|
24
19
|
ManifestV1MetaSchema,
|
|
25
20
|
} from './JsonSchemaService';
|
|
21
|
+
import { defaultConfig } from './defaultDraftConfig';
|
|
26
22
|
|
|
27
|
-
export
|
|
28
|
-
...draft07Config,
|
|
29
|
-
validateFormat: {
|
|
30
|
-
...draft07Config.validateFormat,
|
|
31
|
-
...customFormatValidators,
|
|
32
|
-
},
|
|
33
|
-
typeKeywords: {
|
|
34
|
-
...draft07Config.typeKeywords,
|
|
35
|
-
array: draft07Config.typeKeywords.array.concat('ui:metadata'),
|
|
36
|
-
object: draft07Config.typeKeywords.object.concat('ui:metadata'),
|
|
37
|
-
boolean: draft07Config.typeKeywords.boolean.concat('ui:metadata'),
|
|
38
|
-
string: draft07Config.typeKeywords.string.concat('ui:metadata'),
|
|
39
|
-
number: draft07Config.typeKeywords.number.concat('ui:metadata'),
|
|
40
|
-
},
|
|
41
|
-
validateKeyword: {
|
|
42
|
-
...draft07Config.validateKeyword,
|
|
43
|
-
...customKeywordValidators,
|
|
44
|
-
},
|
|
45
|
-
errors: {
|
|
46
|
-
...draft07Config.errors,
|
|
47
|
-
enumError(data) {
|
|
48
|
-
let values = '[]';
|
|
49
|
-
|
|
50
|
-
if (data.values && Array.isArray(data.values)) {
|
|
51
|
-
if (data.values.length < 5) {
|
|
52
|
-
values = `[${data.values.join(', ')}]`;
|
|
53
|
-
} else {
|
|
54
|
-
const firstFiveValues = data.values.slice(0, 5);
|
|
55
|
-
values = `[${firstFiveValues.join(', ')}, ... ${data.values.length - 5} more]`;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return {
|
|
60
|
-
type: 'error',
|
|
61
|
-
name: 'EnumError',
|
|
62
|
-
code: 'enum-error',
|
|
63
|
-
message: `Expected given value \`${data.value}\` in ${data.pointer}\` to be one of \`${values}\``,
|
|
64
|
-
data,
|
|
65
|
-
};
|
|
66
|
-
},
|
|
67
|
-
|
|
68
|
-
anyOfError(data) {
|
|
69
|
-
let value = `Value \`${data.value}\` at`;
|
|
70
|
-
|
|
71
|
-
if (typeof data.value == 'object') {
|
|
72
|
-
value = 'Object at';
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (Array.isArray(data.value)) {
|
|
76
|
-
value = 'Array at';
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return {
|
|
80
|
-
type: 'error',
|
|
81
|
-
name: 'AnyOfError',
|
|
82
|
-
code: 'any-of-error',
|
|
83
|
-
message: `${value} \`${data.pointer}\` does not match any schema`,
|
|
84
|
-
data,
|
|
85
|
-
};
|
|
86
|
-
},
|
|
87
|
-
|
|
88
|
-
typeError(data) {
|
|
89
|
-
let value = `${data.value}`;
|
|
90
|
-
|
|
91
|
-
if (data.received == 'object') {
|
|
92
|
-
value = `Object ${JSON.stringify(data.value)}`;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (data.received == 'array') {
|
|
96
|
-
value = `Array ${JSON.stringify(data.value)}`;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const expected = JSON.stringify(data.expected).replace(/"/g, '`');
|
|
100
|
-
|
|
101
|
-
return {
|
|
102
|
-
type: 'error',
|
|
103
|
-
name: 'TypeError',
|
|
104
|
-
code: 'type-error',
|
|
105
|
-
message: `Expected \`${value}\` (${data.received}) in \`${data.pointer}\` to be of type ${expected}`,
|
|
106
|
-
data,
|
|
107
|
-
};
|
|
108
|
-
},
|
|
109
|
-
},
|
|
110
|
-
};
|
|
23
|
+
export { defaultConfig };
|
|
111
24
|
|
|
112
25
|
const FTSchema = new Draft07(FormattedText, defaultConfig);
|
|
113
26
|
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { draft07Config, DraftConfig } from '@squiz/json-schema-library';
|
|
2
|
+
|
|
3
|
+
import { customFormatValidators } from './validators/customFormatValidators';
|
|
4
|
+
import { customKeywordValidators } from './validators/customKeywordValidators';
|
|
5
|
+
|
|
6
|
+
export const defaultConfig: DraftConfig = {
|
|
7
|
+
...draft07Config,
|
|
8
|
+
validateFormat: {
|
|
9
|
+
...draft07Config.validateFormat,
|
|
10
|
+
...customFormatValidators,
|
|
11
|
+
},
|
|
12
|
+
typeKeywords: {
|
|
13
|
+
...draft07Config.typeKeywords,
|
|
14
|
+
array: draft07Config.typeKeywords.array.concat('ui:metadata'),
|
|
15
|
+
object: draft07Config.typeKeywords.object.concat('ui:metadata'),
|
|
16
|
+
boolean: draft07Config.typeKeywords.boolean.concat('ui:metadata'),
|
|
17
|
+
string: draft07Config.typeKeywords.string.concat('ui:metadata'),
|
|
18
|
+
number: draft07Config.typeKeywords.number.concat('ui:metadata'),
|
|
19
|
+
},
|
|
20
|
+
validateKeyword: {
|
|
21
|
+
...draft07Config.validateKeyword,
|
|
22
|
+
...customKeywordValidators,
|
|
23
|
+
},
|
|
24
|
+
errors: {
|
|
25
|
+
...draft07Config.errors,
|
|
26
|
+
enumError(data) {
|
|
27
|
+
let values = '[]';
|
|
28
|
+
|
|
29
|
+
if (data.values && Array.isArray(data.values)) {
|
|
30
|
+
if (data.values.length < 5) {
|
|
31
|
+
values = `[${data.values.join(', ')}]`;
|
|
32
|
+
} else {
|
|
33
|
+
const firstFiveValues = data.values.slice(0, 5);
|
|
34
|
+
values = `[${firstFiveValues.join(', ')}, ... ${data.values.length - 5} more]`;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
type: 'error',
|
|
40
|
+
name: 'EnumError',
|
|
41
|
+
code: 'enum-error',
|
|
42
|
+
message: `Expected given value \`${data.value}\` in ${data.pointer}\` to be one of \`${values}\``,
|
|
43
|
+
data,
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
anyOfError(data) {
|
|
48
|
+
let value = `Value \`${data.value}\` at`;
|
|
49
|
+
|
|
50
|
+
if (typeof data.value == 'object') {
|
|
51
|
+
value = 'Object at';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (Array.isArray(data.value)) {
|
|
55
|
+
value = 'Array at';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
type: 'error',
|
|
60
|
+
name: 'AnyOfError',
|
|
61
|
+
code: 'any-of-error',
|
|
62
|
+
message: `${value} \`${data.pointer}\` does not match any schema`,
|
|
63
|
+
data,
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
typeError(data) {
|
|
68
|
+
let value = `${data.value}`;
|
|
69
|
+
|
|
70
|
+
if (data.received == 'object') {
|
|
71
|
+
value = `Object ${JSON.stringify(data.value)}`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (data.received == 'array') {
|
|
75
|
+
value = `Array ${JSON.stringify(data.value)}`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const expected = JSON.stringify(data.expected).replace(/"/g, '`');
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
type: 'error',
|
|
82
|
+
name: 'TypeError',
|
|
83
|
+
code: 'type-error',
|
|
84
|
+
message: `Expected \`${value}\` (${data.received}) in \`${data.pointer}\` to be of type ${expected}`,
|
|
85
|
+
data,
|
|
86
|
+
};
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
};
|
|
@@ -776,4 +776,20 @@ describe('resolveFormattedNodes', () => {
|
|
|
776
776
|
|
|
777
777
|
expect(result).toEqual(testItem);
|
|
778
778
|
});
|
|
779
|
+
|
|
780
|
+
it('should ignore a FormattedText value which is null', async () => {
|
|
781
|
+
const testSchema = {
|
|
782
|
+
type: 'object',
|
|
783
|
+
properties: {
|
|
784
|
+
myProp: { type: 'FormattedText' },
|
|
785
|
+
},
|
|
786
|
+
};
|
|
787
|
+
const testItem = {
|
|
788
|
+
myProp: null,
|
|
789
|
+
};
|
|
790
|
+
|
|
791
|
+
const result = await resolveFormattedTextNodes(testItem, testSchema, testResolverMap);
|
|
792
|
+
|
|
793
|
+
expect(result).toEqual(testItem);
|
|
794
|
+
});
|
|
779
795
|
});
|
|
@@ -10,6 +10,9 @@ import {
|
|
|
10
10
|
HigherOrderFormattedNodes,
|
|
11
11
|
TextNode,
|
|
12
12
|
} from './formattedText';
|
|
13
|
+
import { FORMATTED_TEXT_SCHEMA_ID } from './formattedTextConstants';
|
|
14
|
+
|
|
15
|
+
export { FORMATTED_TEXT_SCHEMA_ID };
|
|
13
16
|
|
|
14
17
|
export interface FormattedNodeWithChildren {
|
|
15
18
|
children: FormattedNode[];
|
|
@@ -25,8 +28,6 @@ export type ResolverConfig<Nodes extends FormattedNode, Output extends Resolutio
|
|
|
25
28
|
[N in Nodes as N['type']]: Resolver<N, Output>;
|
|
26
29
|
} & { default?: Resolver<FormattedNode, Output> };
|
|
27
30
|
|
|
28
|
-
export const FORMATTED_TEXT_SCHEMA_ID = 'SquizFormattedTextSchema.json';
|
|
29
|
-
|
|
30
31
|
export type ResolvedChildNode<
|
|
31
32
|
DEFAULT_NODES extends FormattedNode,
|
|
32
33
|
CHILD_NODE extends ResolutionOutput<FormattedNode>,
|
|
@@ -62,7 +63,7 @@ export async function resolveFormattedTextNodes<O extends ResolutionOutput<Forma
|
|
|
62
63
|
contentItem,
|
|
63
64
|
(schema, data, pointer) => {
|
|
64
65
|
if (schema.type === 'FormattedText' || schema.$id === FORMATTED_TEXT_SCHEMA_ID) {
|
|
65
|
-
if (
|
|
66
|
+
if (!Array.isArray(data)) {
|
|
66
67
|
return;
|
|
67
68
|
}
|
|
68
69
|
const formattedText = data as FormattedText;
|