@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.
Files changed (100) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +11 -0
  3. package/jest.integration.config.ts +26 -0
  4. package/jsonCompiler.ts +35 -2
  5. package/lib/JsonSchemaService.allOf.spec.js +77 -0
  6. package/lib/JsonSchemaService.allOf.spec.js.map +1 -1
  7. package/lib/JsonSchemaService.d.ts +1 -1
  8. package/lib/JsonSchemaService.js +11 -10
  9. package/lib/JsonSchemaService.js.map +1 -1
  10. package/lib/JsonValidationService.d.ts +3 -2
  11. package/lib/JsonValidationService.js +21 -91
  12. package/lib/JsonValidationService.js.map +1 -1
  13. package/lib/defaultDraftConfig.d.ts +2 -0
  14. package/lib/defaultDraftConfig.js +81 -0
  15. package/lib/defaultDraftConfig.js.map +1 -0
  16. package/lib/formatted-text/v1/formattedTextConstants.d.ts +2 -0
  17. package/lib/formatted-text/v1/formattedTextConstants.js +6 -0
  18. package/lib/formatted-text/v1/formattedTextConstants.js.map +1 -0
  19. package/lib/formatted-text/v1/resolveFormattedTextNodes.d.ts +2 -2
  20. package/lib/formatted-text/v1/resolveFormattedTextNodes.js +4 -3
  21. package/lib/formatted-text/v1/resolveFormattedTextNodes.js.map +1 -1
  22. package/lib/formatted-text/v1/resolveFormattedTextNodes.spec.js +13 -0
  23. package/lib/formatted-text/v1/resolveFormattedTextNodes.spec.js.map +1 -1
  24. package/lib/index.d.ts +1 -0
  25. package/lib/index.js +1 -0
  26. package/lib/index.js.map +1 -1
  27. package/lib/manifest/userApi/v1/UserApiManifestV1.d.ts +48 -0
  28. package/lib/manifest/userApi/v1/UserApiManifestV1.js +9 -0
  29. package/lib/manifest/userApi/v1/UserApiManifestV1.js.map +1 -0
  30. package/lib/manifest/userApi/v1/UserApiManifestV1.json +76 -0
  31. package/lib/manifest/userApi/v1/index.d.ts +2 -0
  32. package/lib/manifest/userApi/v1/index.js +8 -0
  33. package/lib/manifest/userApi/v1/index.js.map +1 -0
  34. package/lib/manifest/userApi/v1/integration-fixtures/invalid-endpoint-extra-public.manifest.json +10 -0
  35. package/lib/manifest/userApi/v1/integration-fixtures/invalid-endpoint-handler-hyphen.manifest.json +9 -0
  36. package/lib/manifest/userApi/v1/integration-fixtures/invalid-endpoint-handler-leading-digit.manifest.json +9 -0
  37. package/lib/manifest/userApi/v1/integration-fixtures/invalid-endpoint-method-invalid.manifest.json +9 -0
  38. package/lib/manifest/userApi/v1/integration-fixtures/invalid-endpoint-missing-method.manifest.json +8 -0
  39. package/lib/manifest/userApi/v1/integration-fixtures/invalid-endpoint-missing-path.manifest.json +8 -0
  40. package/lib/manifest/userApi/v1/integration-fixtures/invalid-full-displayName-empty.manifest.json +16 -0
  41. package/lib/manifest/userApi/v1/integration-fixtures/invalid-full-manifest-not-object.manifest.json +8 -0
  42. package/lib/manifest/userApi/v1/integration-fixtures/invalid-full-missing-manifest.manifest.json +7 -0
  43. package/lib/manifest/userApi/v1/integration-fixtures/invalid-full-missing-schema.manifest.json +15 -0
  44. package/lib/manifest/userApi/v1/integration-fixtures/invalid-full-name-empty.manifest.json +16 -0
  45. package/lib/manifest/userApi/v1/integration-fixtures/invalid-full-root-extra-property.manifest.json +17 -0
  46. package/lib/manifest/userApi/v1/integration-fixtures/invalid-nested-manifest-handlerMap.manifest.json +12 -0
  47. package/lib/manifest/userApi/v1/integration-fixtures/invalid-nested-manifest-name.manifest.json +10 -0
  48. package/lib/manifest/userApi/v1/integration-fixtures/invalid-resolved-empty-endpoints.manifest.json +4 -0
  49. package/lib/manifest/userApi/v1/integration-fixtures/invalid-resolved-no-leading-slash.manifest.json +11 -0
  50. package/lib/manifest/userApi/v1/integration-fixtures/valid-full-each-http-method.manifest.json +18 -0
  51. package/lib/manifest/userApi/v1/integration-fixtures/valid-full-no-description.manifest.json +16 -0
  52. package/lib/manifest/userApi/v1/integration-fixtures/valid-full.manifest.json +22 -0
  53. package/lib/manifest/userApi/v1/integration-fixtures/valid-resolved-slash-path.manifest.json +14 -0
  54. package/lib/manifest/userApi/v1/integration-fixtures/valid-resolved.manifest.json +14 -0
  55. package/lib/manifest/userApi/v1/userApiManifest.integration.spec.d.ts +1 -0
  56. package/lib/manifest/userApi/v1/userApiManifest.integration.spec.js +201 -0
  57. package/lib/manifest/userApi/v1/userApiManifest.integration.spec.js.map +1 -0
  58. package/lib/manifest/userApi/v1/userApiManifestValidation.d.ts +16 -0
  59. package/lib/manifest/userApi/v1/userApiManifestValidation.js +88 -0
  60. package/lib/manifest/userApi/v1/userApiManifestValidation.js.map +1 -0
  61. package/lib/manifest/userApi/v1/userApiManifestValidation.spec.d.ts +1 -0
  62. package/lib/manifest/userApi/v1/userApiManifestValidation.spec.js +237 -0
  63. package/lib/manifest/userApi/v1/userApiManifestValidation.spec.js.map +1 -0
  64. package/package.json +11 -1
  65. package/src/JsonSchemaService.allOf.spec.ts +85 -0
  66. package/src/JsonSchemaService.ts +5 -4
  67. package/src/JsonValidationService.ts +9 -96
  68. package/src/defaultDraftConfig.ts +89 -0
  69. package/src/formatted-text/v1/formattedTextConstants.ts +2 -0
  70. package/src/formatted-text/v1/resolveFormattedTextNodes.spec.ts +16 -0
  71. package/src/formatted-text/v1/resolveFormattedTextNodes.ts +4 -3
  72. package/src/index.ts +2 -0
  73. package/src/manifest/userApi/v1/UserApiManifestV1.json +76 -0
  74. package/src/manifest/userApi/v1/UserApiManifestV1.ts +50 -0
  75. package/src/manifest/userApi/v1/index.ts +6 -0
  76. package/src/manifest/userApi/v1/integration-fixtures/invalid-endpoint-extra-public.manifest.json +10 -0
  77. package/src/manifest/userApi/v1/integration-fixtures/invalid-endpoint-handler-hyphen.manifest.json +9 -0
  78. package/src/manifest/userApi/v1/integration-fixtures/invalid-endpoint-handler-leading-digit.manifest.json +9 -0
  79. package/src/manifest/userApi/v1/integration-fixtures/invalid-endpoint-method-invalid.manifest.json +9 -0
  80. package/src/manifest/userApi/v1/integration-fixtures/invalid-endpoint-missing-method.manifest.json +8 -0
  81. package/src/manifest/userApi/v1/integration-fixtures/invalid-endpoint-missing-path.manifest.json +8 -0
  82. package/src/manifest/userApi/v1/integration-fixtures/invalid-full-displayName-empty.manifest.json +16 -0
  83. package/src/manifest/userApi/v1/integration-fixtures/invalid-full-manifest-not-object.manifest.json +8 -0
  84. package/src/manifest/userApi/v1/integration-fixtures/invalid-full-missing-manifest.manifest.json +7 -0
  85. package/src/manifest/userApi/v1/integration-fixtures/invalid-full-missing-schema.manifest.json +15 -0
  86. package/src/manifest/userApi/v1/integration-fixtures/invalid-full-name-empty.manifest.json +16 -0
  87. package/src/manifest/userApi/v1/integration-fixtures/invalid-full-root-extra-property.manifest.json +17 -0
  88. package/src/manifest/userApi/v1/integration-fixtures/invalid-nested-manifest-handlerMap.manifest.json +12 -0
  89. package/src/manifest/userApi/v1/integration-fixtures/invalid-nested-manifest-name.manifest.json +10 -0
  90. package/src/manifest/userApi/v1/integration-fixtures/invalid-resolved-empty-endpoints.manifest.json +4 -0
  91. package/src/manifest/userApi/v1/integration-fixtures/invalid-resolved-no-leading-slash.manifest.json +11 -0
  92. package/src/manifest/userApi/v1/integration-fixtures/valid-full-each-http-method.manifest.json +18 -0
  93. package/src/manifest/userApi/v1/integration-fixtures/valid-full-no-description.manifest.json +16 -0
  94. package/src/manifest/userApi/v1/integration-fixtures/valid-full.manifest.json +22 -0
  95. package/src/manifest/userApi/v1/integration-fixtures/valid-resolved-slash-path.manifest.json +14 -0
  96. package/src/manifest/userApi/v1/integration-fixtures/valid-resolved.manifest.json +14 -0
  97. package/src/manifest/userApi/v1/userApiManifest.integration.spec.ts +265 -0
  98. package/src/manifest/userApi/v1/userApiManifestValidation.spec.ts +311 -0
  99. package/src/manifest/userApi/v1/userApiManifestValidation.ts +54 -0
  100. 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.0",
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 = {
@@ -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, FORMATTED_TEXT_SCHEMA_ID } from '.';
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, DraftConfig } from '@squiz/json-schema-library';
6
+ import { Draft07, JSONSchema, Draft } from '@squiz/json-schema-library';
7
7
 
8
8
  import { draft07Config } from '@squiz/json-schema-library';
9
- import {
10
- BaseFormattedTextType,
11
- ComponentInputFormattedTextType,
12
- FORMATTED_TEXT_SCHEMA_ID,
13
- MANIFEST_MODELS,
14
- SquizImageType,
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 const defaultConfig: DraftConfig = {
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
+ };
@@ -0,0 +1,2 @@
1
+ /** `$id` of the Formatted Text JSON Schema bundled with dx-json-schema-lib. */
2
+ export const FORMATTED_TEXT_SCHEMA_ID = 'SquizFormattedTextSchema.json';
@@ -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 (typeof data === 'string') {
66
+ if (!Array.isArray(data)) {
66
67
  return;
67
68
  }
68
69
  const formattedText = data as FormattedText;