@squiz/dx-json-schema-lib 1.39.1-alpha.0 → 1.39.1-alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- package/.npm/_logs/{2023-06-21T21_57_08_768Z-debug-0.log → 2023-06-22T05_23_22_241Z-debug-0.log} +15 -15
- package/jsonCompiler.ts +1 -0
- package/lib/JsonValidationService.d.ts +1 -1
- package/lib/JsonValidationService.js +7 -0
- package/lib/JsonValidationService.js.map +1 -1
- package/lib/manifest/v1/JobV1.d.ts +192 -0
- package/lib/manifest/v1/JobV1.js +9 -0
- package/lib/manifest/v1/JobV1.js.map +1 -0
- package/lib/manifest/v1/JobV1.json +88 -0
- package/lib/manifest/v1/JobV1.spec.d.ts +1 -0
- package/lib/manifest/v1/JobV1.spec.js +75 -0
- package/lib/manifest/v1/JobV1.spec.js.map +1 -0
- package/lib/manifest/v1/__test__/schemas/badFunctionInputJob.json +25 -0
- package/lib/manifest/v1/__test__/schemas/nonObjectFunctionInputJob.json +25 -0
- package/lib/manifest/v1/__test__/schemas/validJob.json +25 -0
- package/lib/manifest/v1/manifestModels.d.ts +1 -0
- package/lib/manifest/v1/manifestModels.js +2 -1
- package/lib/manifest/v1/manifestModels.js.map +1 -1
- package/lib/manifest/v1/manifestSchemas.d.ts +2 -1
- package/lib/manifest/v1/manifestSchemas.js +3 -1
- package/lib/manifest/v1/manifestSchemas.js.map +1 -1
- package/lib/manifest/v1/v1.json +26 -7
- package/package.json +2 -2
- package/src/JsonValidationService.ts +9 -1
- package/src/manifest/v1/JobV1.json +88 -0
- package/src/manifest/v1/JobV1.spec.ts +110 -0
- package/src/manifest/v1/JobV1.ts +447 -0
- package/src/manifest/v1/__test__/schemas/badFunctionInputJob.json +25 -0
- package/src/manifest/v1/__test__/schemas/nonObjectFunctionInputJob.json +25 -0
- package/src/manifest/v1/__test__/schemas/validJob.json +25 -0
- package/src/manifest/v1/manifestModels.ts +1 -0
- package/src/manifest/v1/manifestSchemas.ts +2 -1
- package/src/manifest/v1/v1.json +26 -14
- package/tsconfig.tsbuildinfo +1 -1
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"manifestSchemas.js","sourceRoot":"","sources":["../../../src/manifest/v1/manifestSchemas.ts"],"names":[],"mappings":";;;;;;AAAA,wDAA2B;
|
1
|
+
{"version":3,"file":"manifestSchemas.js","sourceRoot":"","sources":["../../../src/manifest/v1/manifestSchemas.ts"],"names":[],"mappings":";;;;;;AAAA,wDAA2B;AAGlB,aAHF,iBAAE,CAGE;AAFX,8DAAiC;AAEpB,gBAFN,oBAAK,CAEM"}
|
package/lib/manifest/v1/v1.json
CHANGED
@@ -4,15 +4,28 @@
|
|
4
4
|
"title": "ComponentManifest",
|
5
5
|
"additionalProperties": false,
|
6
6
|
"properties": {
|
7
|
-
"$schema": {
|
7
|
+
"$schema": {
|
8
|
+
"type": "string",
|
9
|
+
"description": "the manifest schema version"
|
10
|
+
},
|
8
11
|
"namespace": {
|
9
12
|
"type": "string",
|
10
13
|
"description": "Namespace of the component",
|
11
14
|
"$ref": "#/definitions/name-pattern"
|
12
15
|
},
|
13
|
-
"name": {
|
14
|
-
|
15
|
-
|
16
|
+
"name": {
|
17
|
+
"type": "string",
|
18
|
+
"description": "Name of the component",
|
19
|
+
"$ref": "#/definitions/name-pattern"
|
20
|
+
},
|
21
|
+
"displayName": {
|
22
|
+
"type": "string",
|
23
|
+
"description": "Display name of the component"
|
24
|
+
},
|
25
|
+
"description": {
|
26
|
+
"type": "string",
|
27
|
+
"description": "Description of the component"
|
28
|
+
},
|
16
29
|
"mainFunction": {
|
17
30
|
"type": "string",
|
18
31
|
"description": "Name of the main function to be executed at the root of the access url"
|
@@ -84,7 +97,9 @@
|
|
84
97
|
"additionalProperties": false,
|
85
98
|
"description": "The HtmlResponse type is for returning html content. The response out of the function must be a string. This response object also includes references to resources (staticFiles) the component needs to execute correctly. It is up to the integrating system to respect this.",
|
86
99
|
"properties": {
|
87
|
-
"responseType": {
|
100
|
+
"responseType": {
|
101
|
+
"const": "html"
|
102
|
+
},
|
88
103
|
"staticFiles": {
|
89
104
|
"type": "array",
|
90
105
|
"description": "A list of static resources that are required for the component to execute correctly",
|
@@ -251,8 +266,12 @@
|
|
251
266
|
"type": "object",
|
252
267
|
"additionalProperties": false,
|
253
268
|
"properties": {
|
254
|
-
"responseType": {
|
255
|
-
|
269
|
+
"responseType": {
|
270
|
+
"const": "json"
|
271
|
+
},
|
272
|
+
"definition": {
|
273
|
+
"$ref": "http://json-schema.org/draft-07/schema#"
|
274
|
+
},
|
256
275
|
"headers": {
|
257
276
|
"title": "ResponseHeaders",
|
258
277
|
"type": "object",
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@squiz/dx-json-schema-lib",
|
3
|
-
"version": "1.39.1-alpha.
|
3
|
+
"version": "1.39.1-alpha.1",
|
4
4
|
"description": "",
|
5
5
|
"main": "lib/index.js",
|
6
6
|
"scripts": {
|
@@ -31,5 +31,5 @@
|
|
31
31
|
"@squiz/json-schema-library": "7.4.7",
|
32
32
|
"ts-brand": "0.0.2"
|
33
33
|
},
|
34
|
-
"gitHead": "
|
34
|
+
"gitHead": "16b9f02b751a923a71f96684bd46c781fc97dcbc"
|
35
35
|
}
|
@@ -11,6 +11,7 @@ import FormattedText from './formatted-text/v1/formattedText.json';
|
|
11
11
|
import PageContentsSchema from './pageContents/v1/pageContents.json';
|
12
12
|
|
13
13
|
import v1 from './manifest/v1/v1.json';
|
14
|
+
import JobV1 from './manifest/v1/JobV1.json';
|
14
15
|
import { SchemaValidationError, ValidationData, ValidationDataMap } from './errors/SchemaValidationError';
|
15
16
|
import { Draft07, JSONError, JSONSchema, Draft, DraftConfig } from '@squiz/json-schema-library';
|
16
17
|
|
@@ -152,6 +153,9 @@ v1Schema.addRemoteSchema('/MatrixAssetSchema.json', MatrixAssetSchema);
|
|
152
153
|
v1Schema.addRemoteSchema('http://json-schema.org/draft-07/schema', Draft07Schema);
|
153
154
|
v1Schema.addRemoteSchema('http://json-schema.org/draft-07/schema#', Draft07Schema);
|
154
155
|
|
156
|
+
const jobV1Schema = new Draft07(JobV1, defaultConfig);
|
157
|
+
jobV1Schema.addRemoteSchema('/DxComponentInputSchema.json', ComponentInputSchema.getSchema());
|
158
|
+
|
155
159
|
export const ComponentInputMetaSchema: MetaSchemaInput = {
|
156
160
|
root: DxComponentInputSchema,
|
157
161
|
remotes: {
|
@@ -282,12 +286,16 @@ export class JSONSchemaService<P extends AnyPrimitiveType, R extends AnyResolvab
|
|
282
286
|
}
|
283
287
|
|
284
288
|
export class JsonValidationService {
|
285
|
-
validateManifest(manifest: unknown, version: 'v1') {
|
289
|
+
validateManifest(manifest: unknown, version: 'v1' | 'JobV1') {
|
286
290
|
switch (version) {
|
287
291
|
case 'v1': {
|
288
292
|
const validationResult = v1Schema.validate(manifest);
|
289
293
|
return processValidationResult(validationResult);
|
290
294
|
}
|
295
|
+
case 'JobV1': {
|
296
|
+
const validationResult = jobV1Schema.validate(manifest);
|
297
|
+
return processValidationResult(validationResult);
|
298
|
+
}
|
291
299
|
|
292
300
|
default:
|
293
301
|
throw new SchemaValidationError('Invalid manifest version');
|
@@ -0,0 +1,88 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
3
|
+
"type": "object",
|
4
|
+
"title": "JobManifest",
|
5
|
+
"additionalProperties": false,
|
6
|
+
"properties": {
|
7
|
+
"$schema": {
|
8
|
+
"type": "string",
|
9
|
+
"description": "the manifest schema version"
|
10
|
+
},
|
11
|
+
"name": {
|
12
|
+
"type": "string",
|
13
|
+
"description": "Name of the job",
|
14
|
+
"$ref": "#/definitions/name-pattern"
|
15
|
+
},
|
16
|
+
"displayName": {
|
17
|
+
"type": "string",
|
18
|
+
"description": "Display name of the job"
|
19
|
+
},
|
20
|
+
"description": {
|
21
|
+
"type": "string",
|
22
|
+
"description": "Description of the job"
|
23
|
+
},
|
24
|
+
"mainFunction": {
|
25
|
+
"type": "string",
|
26
|
+
"description": "Name of the main function to be executed at the root of the access url"
|
27
|
+
},
|
28
|
+
"version": {
|
29
|
+
"type": "string",
|
30
|
+
"description": "Semver version number",
|
31
|
+
"minLength": 5,
|
32
|
+
"maxLength": 14,
|
33
|
+
"pattern": "^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)$"
|
34
|
+
},
|
35
|
+
"timeout": {
|
36
|
+
"type": "number",
|
37
|
+
"description": "Timeout in seconds before a job is stopped (min 5s, max 8h)",
|
38
|
+
"minimum": 5,
|
39
|
+
"maximum": 28800
|
40
|
+
},
|
41
|
+
"concurrency": {
|
42
|
+
"type": "number",
|
43
|
+
"description": "The number of these jobs that can be run at once",
|
44
|
+
"minimum": 1
|
45
|
+
},
|
46
|
+
"functions": {
|
47
|
+
"type": "array",
|
48
|
+
"minItems": 0,
|
49
|
+
"items": {
|
50
|
+
"title": "JobFunction",
|
51
|
+
"description": "Job function definition, this object provides the runtime with input validation and what to execute",
|
52
|
+
"type": "object",
|
53
|
+
"properties": {
|
54
|
+
"name": {
|
55
|
+
"type": "string",
|
56
|
+
"$ref": "#/definitions/name-pattern",
|
57
|
+
"description": "Function name"
|
58
|
+
},
|
59
|
+
"entry": {
|
60
|
+
"type": "string",
|
61
|
+
"description": "File path to the javascript file to execute. The file path must be relative to the manifest file and cannot be in a folder above the manifest file."
|
62
|
+
},
|
63
|
+
"input": {
|
64
|
+
"$ref": "DxComponentInputSchema.json"
|
65
|
+
}
|
66
|
+
},
|
67
|
+
"required": ["name", "entry", "input"]
|
68
|
+
}
|
69
|
+
}
|
70
|
+
},
|
71
|
+
"required": [
|
72
|
+
"name",
|
73
|
+
"displayName",
|
74
|
+
"description",
|
75
|
+
"version",
|
76
|
+
"functions",
|
77
|
+
"$schema",
|
78
|
+
"mainFunction",
|
79
|
+
"concurrency",
|
80
|
+
"timeout"
|
81
|
+
],
|
82
|
+
"definitions": {
|
83
|
+
"name-pattern": {
|
84
|
+
"type": "string",
|
85
|
+
"pattern": "^[a-z][a-z0-9_\\-]+$"
|
86
|
+
}
|
87
|
+
}
|
88
|
+
}
|
@@ -0,0 +1,110 @@
|
|
1
|
+
import { readFile } from 'fs/promises';
|
2
|
+
import { resolve } from 'path';
|
3
|
+
import { SchemaValidationError } from '../../errors/SchemaValidationError';
|
4
|
+
import { JsonValidationService } from '../../JsonValidationService';
|
5
|
+
|
6
|
+
const NAME_PATTERN = '^[a-z][a-z0-9_\\-]+$';
|
7
|
+
|
8
|
+
async function fetchTestManifest(filename: string) {
|
9
|
+
const contents = await readFile(resolve(__dirname, '__test__', 'schemas', filename), {
|
10
|
+
encoding: 'utf-8',
|
11
|
+
});
|
12
|
+
return JSON.parse(contents);
|
13
|
+
}
|
14
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
15
|
+
function expectToThrowErrorMatchingTypeAndMessage(received: Function, errorType: Function, message: string) {
|
16
|
+
let error: null | Error = null;
|
17
|
+
|
18
|
+
try {
|
19
|
+
received();
|
20
|
+
} catch (e: any) {
|
21
|
+
error = e;
|
22
|
+
}
|
23
|
+
|
24
|
+
expect(error).toBeDefined();
|
25
|
+
expect(error?.message).toEqual(message);
|
26
|
+
expect(error).toBeInstanceOf(errorType);
|
27
|
+
}
|
28
|
+
|
29
|
+
describe('manifest/JobV1', () => {
|
30
|
+
let validationService: JsonValidationService;
|
31
|
+
|
32
|
+
beforeAll(() => {
|
33
|
+
validationService = new JsonValidationService();
|
34
|
+
});
|
35
|
+
|
36
|
+
it('succeeds on a valid manifest', async () => {
|
37
|
+
const manifest = await fetchTestManifest('validJob.json');
|
38
|
+
expect(validationService.validateManifest(manifest, 'JobV1')).toBeTruthy();
|
39
|
+
});
|
40
|
+
|
41
|
+
it('errors on invalid property types in function input', async () => {
|
42
|
+
const manifest = await fetchTestManifest('badFunctionInputJob.json');
|
43
|
+
|
44
|
+
expectToThrowErrorMatchingTypeAndMessage(
|
45
|
+
() => {
|
46
|
+
validationService.validateManifest(manifest, 'JobV1');
|
47
|
+
},
|
48
|
+
SchemaValidationError,
|
49
|
+
'failed validation: Value `wrongType` at `#/functions/0/input/properties/something/type` does not match any schema',
|
50
|
+
);
|
51
|
+
});
|
52
|
+
|
53
|
+
it('errors on non-object top level input', async () => {
|
54
|
+
const manifest = await fetchTestManifest('nonObjectFunctionInputJob.json');
|
55
|
+
expectToThrowErrorMatchingTypeAndMessage(
|
56
|
+
() => {
|
57
|
+
validationService.validateManifest(manifest, 'JobV1');
|
58
|
+
},
|
59
|
+
SchemaValidationError,
|
60
|
+
'failed validation: Expected value at `#/functions/0/input/type` to be `object`, but value given is `string`',
|
61
|
+
);
|
62
|
+
});
|
63
|
+
|
64
|
+
describe.each(['_my-name', '-my-name', 'MyName', 'myName', '0my-name'])(
|
65
|
+
'fails name-pattern validation for %s',
|
66
|
+
(propertyValue) => {
|
67
|
+
it.each(['name'])(`fails validation for manifests with %s of ${propertyValue}`, async (propertyName) => {
|
68
|
+
const manifest = await fetchTestManifest('validJob.json');
|
69
|
+
|
70
|
+
expectToThrowErrorMatchingTypeAndMessage(
|
71
|
+
() => {
|
72
|
+
validationService.validateManifest(
|
73
|
+
{
|
74
|
+
...manifest,
|
75
|
+
[propertyName]: propertyValue,
|
76
|
+
},
|
77
|
+
'JobV1',
|
78
|
+
);
|
79
|
+
},
|
80
|
+
SchemaValidationError,
|
81
|
+
`failed validation: Value in \`#/${propertyName}\` should match \`${NAME_PATTERN}\`, but received \`${propertyValue}\``,
|
82
|
+
);
|
83
|
+
});
|
84
|
+
|
85
|
+
it('fails validation for manifests with function names of %s', async () => {
|
86
|
+
const manifest = await fetchTestManifest('validJob.json');
|
87
|
+
|
88
|
+
expectToThrowErrorMatchingTypeAndMessage(
|
89
|
+
() => {
|
90
|
+
validationService.validateManifest(
|
91
|
+
{
|
92
|
+
...manifest,
|
93
|
+
functions: [
|
94
|
+
{
|
95
|
+
name: propertyValue,
|
96
|
+
entry: 'main.js',
|
97
|
+
input: {},
|
98
|
+
},
|
99
|
+
],
|
100
|
+
},
|
101
|
+
'JobV1',
|
102
|
+
);
|
103
|
+
},
|
104
|
+
SchemaValidationError,
|
105
|
+
`failed validation: Value in \`#/functions/0/name\` should match \`${NAME_PATTERN}\`, but received \`${propertyValue}\``,
|
106
|
+
);
|
107
|
+
});
|
108
|
+
},
|
109
|
+
);
|
110
|
+
});
|