@squiz/dx-json-schema-lib 1.2.13-alpha.1 → 1.2.13-alpha.3

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 (52) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/jest.config.ts +7 -0
  3. package/lib/JsonValidationService.d.ts +4 -6
  4. package/lib/JsonValidationService.js +90 -28
  5. package/lib/JsonValidationService.js.map +1 -1
  6. package/lib/JsonValidationService.spec.js +276 -65
  7. package/lib/JsonValidationService.spec.js.map +1 -1
  8. package/lib/errors/SchemaValidationError.d.ts +1 -1
  9. package/lib/errors/SchemaValidationError.js +8 -1
  10. package/lib/errors/SchemaValidationError.js.map +1 -1
  11. package/lib/formatted-text/v1/formattedText.d.ts +18 -16
  12. package/lib/formatted-text/v1/formattedText.json +59 -88
  13. package/lib/formatted-text/v1/higherOrderFormattedTextToBaseFormattedText.d.ts +8 -0
  14. package/lib/formatted-text/v1/higherOrderFormattedTextToBaseFormattedText.js +21 -0
  15. package/lib/formatted-text/v1/higherOrderFormattedTextToBaseFormattedText.js.map +1 -0
  16. package/lib/formatted-text/v1/higherOrderFormattedTextToBaseFormattedText.spec.d.ts +1 -0
  17. package/lib/formatted-text/v1/higherOrderFormattedTextToBaseFormattedText.spec.js +52 -0
  18. package/lib/formatted-text/v1/higherOrderFormattedTextToBaseFormattedText.spec.js.map +1 -0
  19. package/lib/index.d.ts +1 -0
  20. package/lib/index.js +1 -0
  21. package/lib/index.js.map +1 -1
  22. package/lib/manifest/v1/Draft-07.json +155 -0
  23. package/lib/manifest/v1/DxComponentInputSchema.json +11 -8
  24. package/lib/manifest/v1/DxComponentInputSchema.spec.js +23 -9
  25. package/lib/manifest/v1/DxComponentInputSchema.spec.js.map +1 -1
  26. package/lib/manifest/v1/__test__/schemas/badFunctionInputComponent.json +2 -1
  27. package/lib/manifest/v1/__test__/schemas/badNestedFunctionInput.json +2 -1
  28. package/lib/manifest/v1/__test__/schemas/nonObjectFunctionInputComponent.json +2 -1
  29. package/lib/manifest/v1/__test__/schemas/validComponentJson.json +48 -0
  30. package/lib/manifest/v1/v1.d.ts +5 -7
  31. package/lib/manifest/v1/v1.spec.js +22 -3
  32. package/lib/manifest/v1/v1.spec.js.map +1 -1
  33. package/package.json +4 -3
  34. package/src/JsonValidationService.spec.ts +379 -70
  35. package/src/JsonValidationService.ts +112 -34
  36. package/src/errors/SchemaValidationError.ts +10 -2
  37. package/src/formatted-text/v1/formattedText.json +65 -89
  38. package/src/formatted-text/v1/formattedText.ts +19 -17
  39. package/src/formatted-text/v1/higherOrderFormattedTextToBaseFormattedText.spec.ts +58 -0
  40. package/src/formatted-text/v1/higherOrderFormattedTextToBaseFormattedText.ts +36 -0
  41. package/src/index.ts +1 -0
  42. package/src/manifest/v1/Draft-07.json +155 -0
  43. package/src/manifest/v1/DxComponentInputSchema.json +11 -8
  44. package/src/manifest/v1/DxComponentInputSchema.spec.ts +63 -35
  45. package/src/manifest/v1/__test__/schemas/badFunctionInputComponent.json +2 -1
  46. package/src/manifest/v1/__test__/schemas/badNestedFunctionInput.json +2 -1
  47. package/src/manifest/v1/__test__/schemas/nonObjectFunctionInputComponent.json +2 -1
  48. package/src/manifest/v1/__test__/schemas/validComponentJson.json +48 -0
  49. package/src/manifest/v1/v1.spec.ts +37 -3
  50. package/src/manifest/v1/v1.ts +5 -7
  51. package/tsconfig.json +3 -1
  52. package/tsconfig.tsbuildinfo +1 -1
@@ -1,8 +1,16 @@
1
1
  import { IOutputError } from 'better-ajv-errors';
2
2
 
3
3
  export class SchemaValidationError extends Error {
4
- constructor(validationErrors: IOutputError[], error?: Error) {
5
- super(`failed validation: ${validationErrors.map((e) => e.error).join(', ')}`);
4
+ constructor(validationErrors: IOutputError[] | string, error?: Error) {
5
+ let message: string;
6
+
7
+ if (typeof validationErrors != 'string') {
8
+ message = validationErrors.map((e) => e.error).join(', ');
9
+ } else {
10
+ message = validationErrors;
11
+ }
12
+
13
+ super(`failed validation: ${message}`);
6
14
  this.stack = error?.stack;
7
15
  this.name = 'SchemaValidationError';
8
16
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "type": "array",
4
- "additionalProperties": false,
5
4
  "title": "FormattedText",
6
5
 
7
6
  "items": {
@@ -27,6 +26,7 @@
27
26
  "TextNode": {
28
27
  "type": "object",
29
28
  "additionalProperties": false,
29
+
30
30
  "properties": {
31
31
  "type": { "const": "text" },
32
32
  "value": { "type": "string" }
@@ -34,112 +34,88 @@
34
34
  "required": ["type", "value"]
35
35
  },
36
36
 
37
- "FormattedNode": {
37
+ "FormattingOptions": {
38
38
  "type": "object",
39
+
39
40
  "properties": {
40
- "type": { "type": "string" },
41
- "formattingOptions": {
42
- "type": "object",
43
- "additionalProperties": false,
44
- "properties": {
45
- "alignment": {
46
- "type": "string",
47
- "enum": ["center", "left", "right", "justify"]
48
- }
49
- }
41
+ "alignment": {
42
+ "type": "string",
43
+ "enum": ["center", "left", "right", "justify"]
50
44
  }
51
- },
52
- "required": ["type"],
45
+ }
46
+ },
53
47
 
54
- "additionalProperties": false
48
+ "WithChildrenNode": {
49
+ "type": "array",
50
+ "items": {
51
+ "$ref": "#/definitions/FormattedNodes"
52
+ }
55
53
  },
56
54
 
57
- "FormattedNodeWithChildren": {
55
+ "FormattedTextTag": {
58
56
  "type": "object",
59
57
  "additionalProperties": false,
60
- "allOf": [
61
- { "$ref": "#/definitions/FormattedNode" },
62
- {
63
- "type": "object",
64
- "additionalProperties": false,
65
- "properties": {
66
- "children": {
67
- "type": "array",
68
- "items": {
69
- "$ref": "#/definitions/FormattedNodes"
70
- }
71
- }
72
- },
73
- "required": ["children"]
74
- }
75
- ]
76
- },
77
58
 
78
- "FormattedTextTag": {
79
- "allOf": [
80
- { "$ref": "#/definitions/FormattedNodeWithChildren" },
81
- {
59
+ "properties": {
60
+ "children": {
61
+ "$ref": "#/definitions/WithChildrenNode"
62
+ },
63
+ "formattingOptions": { "$ref": "#/definitions/FormattingOptions" },
64
+ "type": { "const": "tag" },
65
+ "tag": { "type": "string", "minLength": 1 },
66
+ "attributes": {
82
67
  "type": "object",
83
- "additionalProperties": false,
68
+ "additionalProperties": {
69
+ "type": "string"
70
+ }
71
+ },
72
+ "font": {
73
+ "title": "FormattedNodeFontProperties",
74
+ "type": "object",
75
+
84
76
  "properties": {
85
- "type": { "const": "tag" },
86
- "tag": { "type": "string", "minLength": 1 },
87
- "attributes": {
88
- "type": "object",
89
- "additionalProperties": { "type": "string" }
90
- },
91
- "font": {
92
- "title": "FormattedNodeFontProperties",
93
- "type": "object",
94
- "additionalProperties": false,
95
- "properties": {
96
- "bold": { "type": "boolean" },
97
- "underline": { "type": "boolean" },
98
- "italics": { "type": "boolean" },
99
- "color": { "type": "string" },
100
- "size": { "type": "string" },
101
- "fontFamily": { "type": "string" }
102
- }
103
- }
104
- },
105
- "required": ["type", "tag"]
77
+ "bold": { "type": "boolean" },
78
+ "underline": { "type": "boolean" },
79
+ "italics": { "type": "boolean" },
80
+ "color": { "type": "string" },
81
+ "size": { "type": "string" },
82
+ "fontFamily": { "type": "string" }
83
+ }
106
84
  }
107
- ]
85
+ },
86
+ "required": ["type", "tag", "children"]
108
87
  },
109
88
 
110
89
  "FormattedTextLinkToMatrixAsset": {
111
- "allOf": [
112
- { "$ref": "#/definitions/FormattedNodeWithChildren" },
113
- {
114
- "type": "object",
115
- "additionalProperties": false,
116
- "properties": {
117
- "type": { "const": "link-to-matrix-asset" },
118
- "matrixIdentifier": { "type": "string", "minLength": 1 },
119
- "matrixDomain": { "type": "string", "minLength": 1 },
120
- "matrixAssetId": { "type": "string", "minLength": 1 },
121
- "target": { "type": "string", "enum": ["_blank", "_self", "_parent", "_top"] }
122
- },
123
- "required": ["type", "matrixDomain", "matrixAssetId", "target"]
124
- }
125
- ]
90
+ "type": "object",
91
+ "additionalProperties": false,
92
+
93
+ "properties": {
94
+ "children": {
95
+ "$ref": "#/definitions/WithChildrenNode"
96
+ },
97
+ "formattingOptions": { "$ref": "#/definitions/FormattingOptions" },
98
+ "type": { "const": "link-to-matrix-asset" },
99
+ "matrixIdentifier": { "type": "string", "minLength": 1 },
100
+ "matrixDomain": { "type": "string", "minLength": 1 },
101
+ "matrixAssetId": { "type": "string", "minLength": 1 },
102
+ "target": { "type": "string", "enum": ["_blank", "_self", "_parent", "_top"] }
103
+ },
104
+ "required": ["type", "matrixDomain", "matrixAssetId", "target", "children"]
126
105
  },
127
106
 
128
107
  "FormattedTextMatrixImage": {
129
- "allOf": [
130
- { "$ref": "#/definitions/FormattedNode" },
131
- {
132
- "type": "object",
133
- "additionalProperties": false,
134
- "properties": {
135
- "type": { "const": "matrix-image" },
136
- "matrixIdentifier": { "type": "string", "minLength": 1 },
137
- "matrixDomain": { "type": "string", "minLength": 1 },
138
- "matrixAssetId": { "type": "string", "minLength": 1 }
139
- },
140
- "required": ["type", "matrixDomain", "matrixAssetId"]
141
- }
142
- ]
108
+ "type": "object",
109
+ "additionalProperties": false,
110
+
111
+ "properties": {
112
+ "type": { "const": "matrix-image" },
113
+ "matrixIdentifier": { "type": "string", "minLength": 1 },
114
+ "matrixDomain": { "type": "string", "minLength": 1 },
115
+ "matrixAssetId": { "type": "string", "minLength": 1 },
116
+ "formattingOptions": { "$ref": "#/definitions/FormattingOptions" }
117
+ },
118
+ "required": ["type", "matrixDomain", "matrixAssetId"]
143
119
  }
144
120
  }
145
121
  }
@@ -7,38 +7,39 @@
7
7
 
8
8
  export type FormattedNodes = HigherOrderFormattedNodes | BaseFormattedNodes;
9
9
  export type HigherOrderFormattedNodes = FormattedTextLinkToMatrixAsset | FormattedTextMatrixImage;
10
- export type FormattedTextLinkToMatrixAsset = FormattedNodeWithChildren & {
10
+ export type WithChildrenNode = FormattedNodes[];
11
+ export type BaseFormattedNodes = FormattedTextTag | TextNode;
12
+ export type FormattedText = FormattedNodes[];
13
+
14
+ export interface FormattedTextLinkToMatrixAsset {
15
+ children: WithChildrenNode;
16
+ formattingOptions?: FormattingOptions;
11
17
  type: 'link-to-matrix-asset';
12
18
  matrixIdentifier?: string;
13
19
  matrixDomain: string;
14
20
  matrixAssetId: string;
15
21
  target: '_blank' | '_self' | '_parent' | '_top';
16
- };
17
- export type FormattedNodeWithChildren = FormattedNode & {
18
- children: FormattedNodes[];
19
- };
20
- export type FormattedTextMatrixImage = FormattedNode & {
22
+ }
23
+ export interface FormattingOptions {
24
+ alignment?: 'center' | 'left' | 'right' | 'justify';
25
+ [k: string]: unknown;
26
+ }
27
+ export interface FormattedTextMatrixImage {
21
28
  type: 'matrix-image';
22
29
  matrixIdentifier?: string;
23
30
  matrixDomain: string;
24
31
  matrixAssetId: string;
25
- };
26
- export type BaseFormattedNodes = FormattedTextTag | TextNode;
27
- export type FormattedTextTag = FormattedNodeWithChildren & {
32
+ formattingOptions?: FormattingOptions;
33
+ }
34
+ export interface FormattedTextTag {
35
+ children: WithChildrenNode;
36
+ formattingOptions?: FormattingOptions;
28
37
  type: 'tag';
29
38
  tag: string;
30
39
  attributes?: {
31
40
  [k: string]: string;
32
41
  };
33
42
  font?: FormattedNodeFontProperties;
34
- };
35
- export type FormattedText = FormattedNodes[];
36
-
37
- export interface FormattedNode {
38
- type: string;
39
- formattingOptions?: {
40
- alignment?: 'center' | 'left' | 'right' | 'justify';
41
- };
42
43
  }
43
44
  export interface FormattedNodeFontProperties {
44
45
  bold?: boolean;
@@ -47,6 +48,7 @@ export interface FormattedNodeFontProperties {
47
48
  color?: string;
48
49
  size?: string;
49
50
  fontFamily?: string;
51
+ [k: string]: unknown;
50
52
  }
51
53
  export interface TextNode {
52
54
  type: 'text';
@@ -0,0 +1,58 @@
1
+ import { FormattedNodes, HigherOrderFormattedNodes } from './formattedText';
2
+ import {
3
+ HigherOrderFormattedNodesMap,
4
+ higherOrderFormattedTextToBaseFormattedText,
5
+ } from './higherOrderFormattedTextToBaseFormattedText';
6
+
7
+ describe('higherOrderFormattedTextToBaseFormattedText', () => {
8
+ const mockResolvers: HigherOrderFormattedNodesMap = {
9
+ 'link-to-matrix-asset': jest.fn((node: HigherOrderFormattedNodes) => {
10
+ return Promise.resolve({ type: 'text', value: `Link to asset ${node.matrixAssetId}` });
11
+ }),
12
+ 'matrix-image': jest.fn((node: HigherOrderFormattedNodes) => {
13
+ return Promise.resolve({ type: 'text', value: `Image ${node.matrixAssetId}` });
14
+ }),
15
+ };
16
+
17
+ const testFormattedNodes: FormattedNodes = {
18
+ tag: 'p',
19
+ type: 'tag',
20
+ children: [
21
+ { type: 'text', value: 'This is some ' },
22
+ {
23
+ type: 'link-to-matrix-asset',
24
+ matrixIdentifier: 'abc123',
25
+ matrixDomain: 'example.com',
26
+ matrixAssetId: '12345',
27
+ target: '_blank',
28
+ children: [{ type: 'text', value: 'linked text' }],
29
+ },
30
+ { type: 'text', value: ' with an image ' },
31
+ {
32
+ type: 'matrix-image',
33
+ matrixIdentifier: 'abc123',
34
+ matrixDomain: 'example.com',
35
+ matrixAssetId: '54321',
36
+ },
37
+ { type: 'text', value: '.' },
38
+ ],
39
+ };
40
+
41
+ const expectedFormattedNodes: FormattedNodes = {
42
+ tag: 'p',
43
+ type: 'tag',
44
+ children: [
45
+ { type: 'text', value: 'This is some ' },
46
+ { type: 'text', value: 'Link to asset 12345' },
47
+ { type: 'text', value: ' with an image ' },
48
+ { type: 'text', value: 'Image 54321' },
49
+ { type: 'text', value: '.' },
50
+ ],
51
+ };
52
+
53
+ it('should replace higher order nodes with their resolved counterparts', async () => {
54
+ const result = await higherOrderFormattedTextToBaseFormattedText(testFormattedNodes, mockResolvers);
55
+
56
+ expect(result).toEqual(expectedFormattedNodes);
57
+ });
58
+ });
@@ -0,0 +1,36 @@
1
+ import { BaseFormattedNodes, FormattedNodes, HigherOrderFormattedNodes } from './formattedText';
2
+
3
+ export interface FormattedNodeWithChildren {
4
+ children: FormattedNodes[];
5
+ }
6
+
7
+ export type HigherOrderFormattedNodesMap = {
8
+ [key in HigherOrderFormattedNodes['type']]: (node: HigherOrderFormattedNodes) => Promise<BaseFormattedNodes>;
9
+ };
10
+
11
+ export async function higherOrderFormattedTextToBaseFormattedText(
12
+ node: FormattedNodes,
13
+ resolvers: HigherOrderFormattedNodesMap,
14
+ ): Promise<FormattedNodes> {
15
+ if (node.type in resolvers && nodeIsHigherOrder(node)) {
16
+ return await resolvers[node.type](node);
17
+ }
18
+
19
+ if (hasChildren(node)) {
20
+ const updatedChildren = await Promise.all(
21
+ node.children.map((child) => higherOrderFormattedTextToBaseFormattedText(child, resolvers)),
22
+ );
23
+
24
+ return { ...node, children: updatedChildren };
25
+ }
26
+
27
+ return node;
28
+ }
29
+
30
+ function hasChildren(node: any): node is FormattedNodeWithChildren {
31
+ return node && typeof node == 'object' && 'children' in node && Array.isArray(node.children);
32
+ }
33
+
34
+ function nodeIsHigherOrder(node: FormattedNodes): node is HigherOrderFormattedNodes {
35
+ return node.type === 'link-to-matrix-asset' || node.type === 'matrix-image';
36
+ }
package/src/index.ts CHANGED
@@ -3,6 +3,7 @@ export * as MANIFEST_SCHEMAS from './manifest/v1/manifestSchemas';
3
3
 
4
4
  export * as FORMATTED_TEXT_MODELS from './formatted-text/v1/formattedTextModels';
5
5
  export * as FORMATTED_TEXT_SCHEMAS from './formatted-text/v1/formattedTextSchemas';
6
+ export * from './formatted-text/v1/higherOrderFormattedTextToBaseFormattedText';
6
7
 
7
8
  export * as SUB_SCHEMAS from './manifest/v1/subSchemas';
8
9
 
@@ -0,0 +1,155 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "http://json-schema.org/draft-07/schema#",
4
+ "title": "Core schema meta-schema",
5
+ "definitions": {
6
+ "schemaArray": {
7
+ "type": "array",
8
+ "minItems": 1,
9
+ "items": { "$ref": "#" }
10
+ },
11
+ "nonNegativeInteger": {
12
+ "type": "integer",
13
+ "minimum": 0
14
+ },
15
+ "nonNegativeIntegerDefault0": {
16
+ "allOf": [{ "$ref": "#/definitions/nonNegativeInteger" }, { "default": 0 }]
17
+ },
18
+ "simpleTypes": {
19
+ "enum": ["array", "boolean", "integer", "null", "number", "object", "string"]
20
+ },
21
+ "stringArray": {
22
+ "type": "array",
23
+ "items": { "type": "string" },
24
+ "uniqueItems": true,
25
+ "default": []
26
+ }
27
+ },
28
+ "type": ["object", "boolean"],
29
+ "properties": {
30
+ "$id": {
31
+ "type": "string",
32
+ "format": "uri-reference"
33
+ },
34
+ "$schema": {
35
+ "type": "string",
36
+ "format": "uri"
37
+ },
38
+ "$ref": {
39
+ "type": "string",
40
+ "format": "uri-reference"
41
+ },
42
+ "$comment": {
43
+ "type": "string"
44
+ },
45
+ "title": {
46
+ "type": "string"
47
+ },
48
+ "description": {
49
+ "type": "string"
50
+ },
51
+ "default": true,
52
+ "readOnly": {
53
+ "type": "boolean",
54
+ "default": false
55
+ },
56
+ "writeOnly": {
57
+ "type": "boolean",
58
+ "default": false
59
+ },
60
+ "examples": {
61
+ "type": "array",
62
+ "items": true
63
+ },
64
+ "multipleOf": {
65
+ "type": "number",
66
+ "exclusiveMinimum": 0
67
+ },
68
+ "maximum": {
69
+ "type": "number"
70
+ },
71
+ "exclusiveMaximum": {
72
+ "type": "number"
73
+ },
74
+ "minimum": {
75
+ "type": "number"
76
+ },
77
+ "exclusiveMinimum": {
78
+ "type": "number"
79
+ },
80
+ "maxLength": { "$ref": "#/definitions/nonNegativeInteger" },
81
+ "minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
82
+ "pattern": {
83
+ "type": "string",
84
+ "format": "regex"
85
+ },
86
+ "additionalItems": { "$ref": "#" },
87
+ "items": {
88
+ "anyOf": [{ "$ref": "#" }, { "$ref": "#/definitions/schemaArray" }],
89
+ "default": true
90
+ },
91
+ "maxItems": { "$ref": "#/definitions/nonNegativeInteger" },
92
+ "minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
93
+ "uniqueItems": {
94
+ "type": "boolean",
95
+ "default": false
96
+ },
97
+ "contains": { "$ref": "#" },
98
+ "maxProperties": { "$ref": "#/definitions/nonNegativeInteger" },
99
+ "minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
100
+ "required": { "$ref": "#/definitions/stringArray" },
101
+ "additionalProperties": { "$ref": "#" },
102
+ "definitions": {
103
+ "type": "object",
104
+ "additionalProperties": { "$ref": "#" },
105
+ "default": {}
106
+ },
107
+ "properties": {
108
+ "type": "object",
109
+ "additionalProperties": { "$ref": "#" },
110
+ "default": {}
111
+ },
112
+ "patternProperties": {
113
+ "type": "object",
114
+ "additionalProperties": { "$ref": "#" },
115
+ "propertyNames": { "format": "regex" },
116
+ "default": {}
117
+ },
118
+ "dependencies": {
119
+ "type": "object",
120
+ "additionalProperties": {
121
+ "anyOf": [{ "$ref": "#" }, { "$ref": "#/definitions/stringArray" }]
122
+ }
123
+ },
124
+ "propertyNames": { "$ref": "#" },
125
+ "const": true,
126
+ "enum": {
127
+ "type": "array",
128
+ "items": true,
129
+ "minItems": 1,
130
+ "uniqueItems": true
131
+ },
132
+ "type": {
133
+ "anyOf": [
134
+ { "$ref": "#/definitions/simpleTypes" },
135
+ {
136
+ "type": "array",
137
+ "items": { "$ref": "#/definitions/simpleTypes" },
138
+ "minItems": 1,
139
+ "uniqueItems": true
140
+ }
141
+ ]
142
+ },
143
+ "format": { "type": "string" },
144
+ "contentMediaType": { "type": "string" },
145
+ "contentEncoding": { "type": "string" },
146
+ "if": { "$ref": "#" },
147
+ "then": { "$ref": "#" },
148
+ "else": { "$ref": "#" },
149
+ "allOf": { "$ref": "#/definitions/schemaArray" },
150
+ "anyOf": { "$ref": "#/definitions/schemaArray" },
151
+ "oneOf": { "$ref": "#/definitions/schemaArray" },
152
+ "not": { "$ref": "#" }
153
+ },
154
+ "default": true
155
+ }
@@ -4,17 +4,20 @@
4
4
  "title": "DxComponentInputSchema",
5
5
  "description": "Input schema for a DxComponent",
6
6
  "type": "object",
7
- "properties": {
8
- "type": {
9
- "const": "object"
10
- },
11
- "additionalProperties": {
12
- "default": false
13
- }
14
- },
15
7
  "allOf": [
16
8
  {
17
9
  "$ref": "DxContentMetaSchema.json"
10
+ },
11
+ {
12
+ "type": "object",
13
+ "properties": {
14
+ "type": {
15
+ "const": "object"
16
+ },
17
+ "additionalProperties": {
18
+ "default": false
19
+ }
20
+ }
18
21
  }
19
22
  ]
20
23
  }