@takeshape/schema 9.80.3 → 9.81.0
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/dist/api-version.js +0 -9
- package/dist/builtin-schema.js +0 -5
- package/dist/content-schema-transform.js +4 -52
- package/dist/create-input-schema.js +7 -19
- package/dist/enum.js +0 -3
- package/dist/flatten-templates.js +0 -11
- package/dist/get-is-leaf.js +8 -18
- package/dist/index.js +0 -58
- package/dist/interfaces.js +2 -26
- package/dist/layers/layers.js +23 -103
- package/dist/layers/refs.js +26 -69
- package/dist/layers/type-utils.js +11 -43
- package/dist/layers/visitor.js +0 -6
- package/dist/migration/index.js +0 -51
- package/dist/migration/to/v3.0.0.js +31 -45
- package/dist/migration/to/v3.1.0.js +15 -41
- package/dist/migration/to/v3.10.0.js +6 -20
- package/dist/migration/to/v3.11.0.js +8 -20
- package/dist/migration/to/v3.12.0.js +2 -3
- package/dist/migration/to/v3.12.1.js +2 -3
- package/dist/migration/to/v3.12.2.js +2 -3
- package/dist/migration/to/v3.12.3.js +16 -21
- package/dist/migration/to/v3.13.0.js +2 -7
- package/dist/migration/to/v3.14.0.js +2 -3
- package/dist/migration/to/v3.15.0.js +2 -3
- package/dist/migration/to/v3.16.0.js +2 -3
- package/dist/migration/to/v3.17.0.js +4 -9
- package/dist/migration/to/v3.17.1.js +2 -3
- package/dist/migration/to/v3.18.0.js +2 -15
- package/dist/migration/to/v3.18.1.js +2 -7
- package/dist/migration/to/v3.18.2.js +8 -10
- package/dist/migration/to/v3.19.0.js +2 -3
- package/dist/migration/to/v3.2.0.js +2 -3
- package/dist/migration/to/v3.20.0.js +10 -11
- package/dist/migration/to/v3.21.0.js +2 -3
- package/dist/migration/to/v3.22.0.js +4 -9
- package/dist/migration/to/v3.23.0.js +2 -3
- package/dist/migration/to/v3.24.0.js +2 -3
- package/dist/migration/to/v3.25.0.js +2 -3
- package/dist/migration/to/v3.26.0.js +2 -3
- package/dist/migration/to/v3.27.0.js +2 -3
- package/dist/migration/to/v3.28.0.js +2 -3
- package/dist/migration/to/v3.29.0.js +2 -3
- package/dist/migration/to/v3.3.0.js +3 -4
- package/dist/migration/to/v3.30.0.js +2 -3
- package/dist/migration/to/v3.31.0.js +2 -12
- package/dist/migration/to/v3.32.0.js +12 -22
- package/dist/migration/to/v3.33.0.js +2 -3
- package/dist/migration/to/v3.34.0.js +14 -43
- package/dist/migration/to/v3.35.0.js +2 -3
- package/dist/migration/to/v3.36.0.js +6 -10
- package/dist/migration/to/v3.37.0.js +2 -3
- package/dist/migration/to/v3.38.0.js +2 -3
- package/dist/migration/to/v3.39.0.js +6 -13
- package/dist/migration/to/v3.4.0.js +2 -3
- package/dist/migration/to/v3.5.0.js +2 -3
- package/dist/migration/to/v3.5.1.js +2 -3
- package/dist/migration/to/v3.6.0.js +2 -3
- package/dist/migration/to/v3.7.0.js +2 -3
- package/dist/migration/to/v3.8.0.js +2 -3
- package/dist/migration/to/v3.9.0.js +8 -24
- package/dist/migration/utils.js +0 -2
- package/dist/mocks.js +9 -12
- package/dist/models/project-schema.js +0 -34
- package/dist/models/query.js +0 -9
- package/dist/models/service.js +0 -8
- package/dist/models/shape.js +0 -29
- package/dist/project-schema/index.js +1 -105
- package/dist/project-schema/migrate.js +1 -54
- package/dist/refs.js +39 -159
- package/dist/relationships.js +13 -57
- package/dist/scalars.js +0 -1
- package/dist/schema-transform.js +0 -11
- package/dist/schema-util.js +75 -271
- package/dist/schemas/index.js +0 -64
- package/dist/services.js +24 -44
- package/dist/taxonomies.js +0 -13
- package/dist/template-shapes/index.js +1 -8
- package/dist/template-shapes/templates.js +9 -40
- package/dist/template-shapes/types.js +4 -5
- package/dist/template-shapes/where.js +14 -110
- package/dist/types/index.js +0 -4
- package/dist/types/types.js +41 -13
- package/dist/types/utils.js +15 -89
- package/dist/unions.js +8 -38
- package/dist/util/api-indexing.js +2 -19
- package/dist/util/detect-cycles.js +2 -16
- package/dist/util/find-shape-at-path.js +1 -15
- package/dist/util/form-config.js +6 -23
- package/dist/util/get-conflicting-properties.js +7 -17
- package/dist/util/get-return-shape.js +0 -11
- package/dist/util/has-arg.js +0 -6
- package/dist/util/index.js +0 -18
- package/dist/util/merge.js +28 -74
- package/dist/util/patch-schema.js +5 -13
- package/dist/validate.js +15 -234
- package/dist/versions.js +0 -2
- package/dist/workflows.js +0 -15
- package/es/api-version.js +0 -4
- package/es/content-schema-transform.js +4 -38
- package/es/create-input-schema.js +7 -14
- package/es/enum.js +0 -2
- package/es/flatten-templates.js +0 -4
- package/es/get-is-leaf.js +8 -13
- package/es/index.js +1 -0
- package/es/interfaces.js +2 -14
- package/es/layers/layers.js +23 -90
- package/es/layers/refs.js +22 -45
- package/es/layers/type-utils.js +11 -16
- package/es/layers/visitor.js +0 -3
- package/es/migration/to/v3.0.0.js +31 -38
- package/es/migration/to/v3.1.0.js +16 -34
- package/es/migration/to/v3.10.0.js +6 -17
- package/es/migration/to/v3.11.0.js +8 -18
- package/es/migration/to/v3.12.0.js +2 -2
- package/es/migration/to/v3.12.1.js +2 -2
- package/es/migration/to/v3.12.2.js +2 -2
- package/es/migration/to/v3.12.3.js +16 -19
- package/es/migration/to/v3.13.0.js +2 -4
- package/es/migration/to/v3.14.0.js +2 -2
- package/es/migration/to/v3.15.0.js +2 -2
- package/es/migration/to/v3.16.0.js +2 -2
- package/es/migration/to/v3.17.0.js +4 -4
- package/es/migration/to/v3.17.1.js +2 -2
- package/es/migration/to/v3.18.0.js +2 -10
- package/es/migration/to/v3.18.1.js +2 -3
- package/es/migration/to/v3.18.2.js +8 -8
- package/es/migration/to/v3.19.0.js +2 -2
- package/es/migration/to/v3.2.0.js +2 -2
- package/es/migration/to/v3.20.0.js +10 -9
- package/es/migration/to/v3.21.0.js +2 -2
- package/es/migration/to/v3.22.0.js +4 -6
- package/es/migration/to/v3.23.0.js +2 -2
- package/es/migration/to/v3.24.0.js +2 -2
- package/es/migration/to/v3.25.0.js +2 -2
- package/es/migration/to/v3.26.0.js +2 -2
- package/es/migration/to/v3.27.0.js +2 -2
- package/es/migration/to/v3.28.0.js +2 -2
- package/es/migration/to/v3.29.0.js +2 -2
- package/es/migration/to/v3.3.0.js +3 -3
- package/es/migration/to/v3.30.0.js +2 -2
- package/es/migration/to/v3.31.0.js +2 -5
- package/es/migration/to/v3.32.0.js +12 -21
- package/es/migration/to/v3.33.0.js +2 -2
- package/es/migration/to/v3.34.0.js +16 -32
- package/es/migration/to/v3.35.0.js +2 -2
- package/es/migration/to/v3.36.0.js +6 -8
- package/es/migration/to/v3.37.0.js +2 -2
- package/es/migration/to/v3.38.0.js +2 -2
- package/es/migration/to/v3.39.0.js +6 -12
- package/es/migration/to/v3.4.0.js +2 -2
- package/es/migration/to/v3.5.0.js +2 -2
- package/es/migration/to/v3.5.1.js +2 -2
- package/es/migration/to/v3.6.0.js +2 -2
- package/es/migration/to/v3.7.0.js +2 -2
- package/es/migration/to/v3.8.0.js +2 -2
- package/es/migration/to/v3.9.0.js +8 -20
- package/es/mocks.js +10 -6
- package/es/models/project-schema.js +0 -26
- package/es/models/query.js +0 -7
- package/es/models/service.js +0 -6
- package/es/models/shape.js +1 -25
- package/es/project-schema/index.js +0 -5
- package/es/project-schema/migrate.js +3 -51
- package/es/refs.js +40 -96
- package/es/relationships.js +14 -42
- package/es/schema-transform.js +0 -7
- package/es/schema-util.js +75 -180
- package/es/services.js +18 -27
- package/es/taxonomies.js +0 -9
- package/es/template-shapes/index.js +1 -4
- package/es/template-shapes/templates.js +9 -18
- package/es/template-shapes/types.js +3 -4
- package/es/template-shapes/where.js +14 -94
- package/es/types/types.js +43 -10
- package/es/types/utils.js +16 -24
- package/es/unions.js +8 -22
- package/es/util/api-indexing.js +2 -12
- package/es/util/detect-cycles.js +2 -14
- package/es/util/find-shape-at-path.js +2 -12
- package/es/util/form-config.js +7 -19
- package/es/util/get-conflicting-properties.js +8 -14
- package/es/util/get-return-shape.js +0 -8
- package/es/util/has-arg.js +0 -3
- package/es/util/merge.js +28 -55
- package/es/util/patch-schema.js +5 -7
- package/es/validate.js +15 -194
- package/es/workflows.js +0 -6
- package/package.json +5 -5
package/es/validate.js
CHANGED
|
@@ -31,10 +31,8 @@ import pMap from 'p-map';
|
|
|
31
31
|
import { flatten } from 'lodash';
|
|
32
32
|
import { isLatestProjectSchemaJSON } from './project-schema';
|
|
33
33
|
const builtInShapeNames = new Set([...Object.keys(builtInShapes), ...scalars, 'object']);
|
|
34
|
-
|
|
35
34
|
function findDuplicates(items) {
|
|
36
35
|
const seen = {};
|
|
37
|
-
|
|
38
36
|
for (const item of items) {
|
|
39
37
|
if (seen[item.value]) {
|
|
40
38
|
seen[item.value].push(item.path);
|
|
@@ -42,13 +40,11 @@ function findDuplicates(items) {
|
|
|
42
40
|
seen[item.value] = [item.path];
|
|
43
41
|
}
|
|
44
42
|
}
|
|
45
|
-
|
|
46
43
|
return Object.entries(seen).filter(entry => entry[1].length > 1).flatMap(entry => ({
|
|
47
44
|
value: entry[0],
|
|
48
45
|
paths: entry[1]
|
|
49
46
|
}));
|
|
50
47
|
}
|
|
51
|
-
|
|
52
48
|
function checkShapeIds(shapes) {
|
|
53
49
|
const items = Object.entries(shapes).map(entry => ({
|
|
54
50
|
path: ['shapes', entry[0], 'id'],
|
|
@@ -60,7 +56,6 @@ function checkShapeIds(shapes) {
|
|
|
60
56
|
message: `Shapes must have unique ids. "${dupe.value}" is not unique.`
|
|
61
57
|
})));
|
|
62
58
|
}
|
|
63
|
-
|
|
64
59
|
function checkShapeNames(shapes) {
|
|
65
60
|
Object.entries(shapes).map(entry => ({
|
|
66
61
|
path: ['shapes', entry[0], 'id'],
|
|
@@ -72,7 +67,6 @@ function checkShapeNames(shapes) {
|
|
|
72
67
|
message: `Shape.name "${shape.name}" must match key "${name}".`
|
|
73
68
|
}));
|
|
74
69
|
}
|
|
75
|
-
|
|
76
70
|
function checkWorkflowStepNames(workflows) {
|
|
77
71
|
return Object.entries(workflows).flatMap(([name, workflow]) => {
|
|
78
72
|
const items = workflow.steps.map((step, i) => ({
|
|
@@ -86,7 +80,6 @@ function checkWorkflowStepNames(workflows) {
|
|
|
86
80
|
})));
|
|
87
81
|
});
|
|
88
82
|
}
|
|
89
|
-
|
|
90
83
|
function checkWorkflowStepKeys(workflows) {
|
|
91
84
|
const items = Object.entries(workflows).flatMap(([name, workflow]) => workflow.steps.map((step, i) => ({
|
|
92
85
|
path: ['workflows', name, 'steps', i, 'key'],
|
|
@@ -98,10 +91,8 @@ function checkWorkflowStepKeys(workflows) {
|
|
|
98
91
|
message: `Workflow keys must be unique at the schema level. Key "${dupe.value}" is not unique.`
|
|
99
92
|
})));
|
|
100
93
|
}
|
|
101
|
-
|
|
102
94
|
function validateWorkflowVersion(projectSchema) {
|
|
103
95
|
const errors = [];
|
|
104
|
-
|
|
105
96
|
if (projectSchema.apiVersion === LEGACY_API_VERSION && Object.keys(projectSchema.workflows).length) {
|
|
106
97
|
errors.push({
|
|
107
98
|
path: ['workflows'],
|
|
@@ -109,16 +100,12 @@ function validateWorkflowVersion(projectSchema) {
|
|
|
109
100
|
message: `apiVersion ${projectSchema.apiVersion} does not support workflows`
|
|
110
101
|
});
|
|
111
102
|
}
|
|
112
|
-
|
|
113
103
|
return errors;
|
|
114
104
|
}
|
|
115
|
-
|
|
116
105
|
function validateWorkflows(projectSchema) {
|
|
117
106
|
const errors = validateWorkflowVersion(projectSchema);
|
|
118
|
-
|
|
119
107
|
for (const name of Object.keys(projectSchema.shapes)) {
|
|
120
108
|
const shape = projectSchema.shapes[name];
|
|
121
|
-
|
|
122
109
|
if (shape.workflow && shape.workflow !== defaultWorkflow.name && !projectSchema.workflows[shape.workflow]) {
|
|
123
110
|
errors.push({
|
|
124
111
|
type: 'notFound',
|
|
@@ -127,17 +114,13 @@ function validateWorkflows(projectSchema) {
|
|
|
127
114
|
});
|
|
128
115
|
}
|
|
129
116
|
}
|
|
130
|
-
|
|
131
117
|
return errors;
|
|
132
118
|
}
|
|
133
|
-
|
|
134
119
|
function getSemver(schemaVersion) {
|
|
135
120
|
return coerce(schemaVersion) ?? LEGACY_SCHEMA_VERSION;
|
|
136
121
|
}
|
|
137
|
-
|
|
138
122
|
function enumerateBasicResolvers(resolver, path) {
|
|
139
123
|
const results = [];
|
|
140
|
-
|
|
141
124
|
const visit = (resolver, path) => {
|
|
142
125
|
if (isComposeResolver(resolver)) {
|
|
143
126
|
resolver.compose.forEach((resolver, i) => {
|
|
@@ -147,35 +130,27 @@ function enumerateBasicResolvers(resolver, path) {
|
|
|
147
130
|
results.push([resolver, path]);
|
|
148
131
|
}
|
|
149
132
|
};
|
|
150
|
-
|
|
151
133
|
visit(resolver, path);
|
|
152
134
|
return results;
|
|
153
|
-
}
|
|
154
|
-
|
|
135
|
+
}
|
|
155
136
|
|
|
137
|
+
// eslint-disable-next-line complexity
|
|
156
138
|
function validateResolver(projectSchema, basePath, baseResolver) {
|
|
157
139
|
const errors = [];
|
|
158
|
-
|
|
159
140
|
const isValidShapeName = shapeName => {
|
|
160
141
|
var _shape$cache;
|
|
161
|
-
|
|
162
142
|
if (!shapeName) {
|
|
163
143
|
return false;
|
|
164
144
|
}
|
|
165
|
-
|
|
166
145
|
const shape = getShape(projectSchema, shapeName);
|
|
167
|
-
|
|
168
146
|
if (shape !== null && shape !== void 0 && shape.model) {
|
|
169
147
|
return true;
|
|
170
148
|
}
|
|
171
|
-
|
|
172
149
|
return Boolean((shape === null || shape === void 0 ? void 0 : (_shape$cache = shape.cache) === null || _shape$cache === void 0 ? void 0 : _shape$cache.enabled) && shape.loaders);
|
|
173
150
|
};
|
|
174
|
-
|
|
175
151
|
const delegateResolverMissingConfig = (parsed, resolver) => {
|
|
176
152
|
if (parsed.serviceId === 'local') {
|
|
177
153
|
const targetResolver = get(projectSchema, propertyRefItemToResolverPath(getNamespace, parsed));
|
|
178
|
-
|
|
179
154
|
if (!isBasicResolver(targetResolver) && !isComposeResolver(targetResolver)) {
|
|
180
155
|
return {
|
|
181
156
|
type: 'notFound',
|
|
@@ -185,13 +160,10 @@ function validateResolver(projectSchema, basePath, baseResolver) {
|
|
|
185
160
|
}
|
|
186
161
|
}
|
|
187
162
|
};
|
|
188
|
-
|
|
189
163
|
const getNamespace = createGetNamespace(projectSchema);
|
|
190
|
-
|
|
191
164
|
for (const [resolver, path] of enumerateBasicResolvers(baseResolver, basePath)) {
|
|
192
165
|
if (isBasicResolver(resolver)) {
|
|
193
166
|
var _projectSchema$servic;
|
|
194
|
-
|
|
195
167
|
if ('service' in resolver && resolver.service !== 'shapedb' && resolver.service !== 'takeshape' && !((_projectSchema$servic = projectSchema.services) !== null && _projectSchema$servic !== void 0 && _projectSchema$servic[resolver.service])) {
|
|
196
168
|
errors.push({
|
|
197
169
|
type: 'notFound',
|
|
@@ -199,12 +171,10 @@ function validateResolver(projectSchema, basePath, baseResolver) {
|
|
|
199
171
|
message: `Invalid service "${resolver.service}"`
|
|
200
172
|
});
|
|
201
173
|
}
|
|
202
|
-
|
|
203
174
|
if (resolver.shapeName) {
|
|
204
175
|
const {
|
|
205
176
|
shapeName
|
|
206
177
|
} = resolver;
|
|
207
|
-
|
|
208
178
|
if (!isValidShapeName(shapeName)) {
|
|
209
179
|
errors.push({
|
|
210
180
|
type: 'notFound',
|
|
@@ -213,13 +183,10 @@ function validateResolver(projectSchema, basePath, baseResolver) {
|
|
|
213
183
|
});
|
|
214
184
|
}
|
|
215
185
|
}
|
|
216
|
-
|
|
217
186
|
if (resolver.name === 'delegate') {
|
|
218
187
|
const parsed = parsePropertyRef(resolver.to);
|
|
219
|
-
|
|
220
188
|
if (parsed) {
|
|
221
189
|
const error = delegateResolverMissingConfig(parsed, resolver);
|
|
222
|
-
|
|
223
190
|
if (error) {
|
|
224
191
|
errors.push(error);
|
|
225
192
|
}
|
|
@@ -239,41 +206,31 @@ function validateResolver(projectSchema, basePath, baseResolver) {
|
|
|
239
206
|
});
|
|
240
207
|
}
|
|
241
208
|
}
|
|
242
|
-
|
|
243
209
|
return errors;
|
|
244
210
|
}
|
|
245
|
-
|
|
246
211
|
function validateLocalQueryConfig(projectSchema, query, operation, name) {
|
|
247
212
|
const location = operation === 'query' ? 'queries' : 'mutations';
|
|
248
213
|
return validateResolver(projectSchema, [location, name, 'resolver'], query.resolver);
|
|
249
214
|
}
|
|
250
|
-
|
|
251
215
|
const operationProps = [['query', 'queries'], ['mutation', 'mutations']];
|
|
252
|
-
|
|
253
216
|
function validateLocalQueryConfigs(projectSchema) {
|
|
254
217
|
const errors = [];
|
|
255
|
-
|
|
256
218
|
for (const [operation, prop] of operationProps) {
|
|
257
219
|
for (const name of Object.keys(projectSchema[prop])) {
|
|
258
220
|
errors.push(...validateLocalQueryConfig(projectSchema, projectSchema[prop][name], operation, name));
|
|
259
221
|
}
|
|
260
222
|
}
|
|
261
|
-
|
|
262
223
|
return errors;
|
|
263
224
|
}
|
|
264
|
-
|
|
265
225
|
function allowDisconnected(context, status) {
|
|
266
226
|
return Boolean(context.allowDisconnectedLayers) && status !== 'notAvailable';
|
|
267
227
|
}
|
|
268
|
-
|
|
269
228
|
function isValidShapeReference(context, layerState, shapeName) {
|
|
270
229
|
if (layerState.status !== 'ok') {
|
|
271
230
|
return allowDisconnected(context, layerState.status);
|
|
272
231
|
}
|
|
273
|
-
|
|
274
232
|
return Boolean(layerState.schema.shapes[shapeName]);
|
|
275
233
|
}
|
|
276
|
-
|
|
277
234
|
async function validateResolverReferences(context, projectSchema, basePath, baseResolver) {
|
|
278
235
|
const errors = [];
|
|
279
236
|
await pMap(enumerateBasicResolvers(baseResolver, basePath), async ([resolver, path]) => {
|
|
@@ -285,7 +242,6 @@ async function validateResolverReferences(context, projectSchema, basePath, base
|
|
|
285
242
|
const prop = resolver.name === 'graphql:query' ? 'queries' : 'mutations';
|
|
286
243
|
const layerState = await context.resolveLayer(service);
|
|
287
244
|
const valid = layerState.status === 'ok' ? Boolean(layerState.schema[prop][fieldName]) : allowDisconnected(context, layerState.status);
|
|
288
|
-
|
|
289
245
|
if (!valid) {
|
|
290
246
|
const operation = resolver.name === 'graphql:query' ? 'query' : 'mutation';
|
|
291
247
|
errors.push({
|
|
@@ -296,11 +252,9 @@ async function validateResolverReferences(context, projectSchema, basePath, base
|
|
|
296
252
|
}
|
|
297
253
|
} else if (resolver.name === 'delegate') {
|
|
298
254
|
const ref = parsePropertyRef(resolver.to);
|
|
299
|
-
|
|
300
255
|
if (ref && ref.serviceId !== 'local') {
|
|
301
256
|
const layerState = await context.resolveLayer(ref.serviceId);
|
|
302
257
|
const valid = layerState.status === 'ok' ? Boolean(get(layerState.schema, propertyRefItemToPath(value(''), ref))) : allowDisconnected(context, layerState.status);
|
|
303
|
-
|
|
304
258
|
if (!valid) {
|
|
305
259
|
errors.push({
|
|
306
260
|
type: 'notFound',
|
|
@@ -313,7 +267,6 @@ async function validateResolverReferences(context, projectSchema, basePath, base
|
|
|
313
267
|
});
|
|
314
268
|
return errors;
|
|
315
269
|
}
|
|
316
|
-
|
|
317
270
|
async function validateQueryConfig(context, projectSchema, {
|
|
318
271
|
query,
|
|
319
272
|
name,
|
|
@@ -322,16 +275,12 @@ async function validateQueryConfig(context, projectSchema, {
|
|
|
322
275
|
const location = operation === 'query' ? 'queries' : 'mutations';
|
|
323
276
|
return validateResolverReferences(context, projectSchema, [location, name, 'resolver'], query.resolver);
|
|
324
277
|
}
|
|
325
|
-
|
|
326
278
|
async function validateQueryConfigs(context, projectSchema) {
|
|
327
279
|
const isLessThanV3_9_0 = lt(getSemver(projectSchema.schemaVersion), '3.9.0');
|
|
328
|
-
|
|
329
280
|
if (isLessThanV3_9_0) {
|
|
330
281
|
return [];
|
|
331
282
|
}
|
|
332
|
-
|
|
333
283
|
const promises = [];
|
|
334
|
-
|
|
335
284
|
for (const [operation, prop] of operationProps) {
|
|
336
285
|
for (const name of Object.keys(projectSchema[prop])) {
|
|
337
286
|
promises.push(validateQueryConfig(context, projectSchema, {
|
|
@@ -341,16 +290,12 @@ async function validateQueryConfigs(context, projectSchema) {
|
|
|
341
290
|
}));
|
|
342
291
|
}
|
|
343
292
|
}
|
|
344
|
-
|
|
345
293
|
return flatten(await Promise.all(promises));
|
|
346
294
|
}
|
|
347
|
-
|
|
348
295
|
function listShapeJoins(projectSchema) {
|
|
349
296
|
const joins = [];
|
|
350
|
-
|
|
351
297
|
for (const shapeKey of Object.keys(projectSchema.shapes)) {
|
|
352
298
|
const shape = projectSchema.shapes[shapeKey];
|
|
353
|
-
|
|
354
299
|
if (shape.joins) {
|
|
355
300
|
for (const joinRef of Object.keys(shape.joins)) {
|
|
356
301
|
const join = shape.joins[joinRef];
|
|
@@ -362,16 +307,12 @@ function listShapeJoins(projectSchema) {
|
|
|
362
307
|
}
|
|
363
308
|
}
|
|
364
309
|
}
|
|
365
|
-
|
|
366
310
|
return joins;
|
|
367
311
|
}
|
|
368
|
-
|
|
369
312
|
function validateLocalShapeJoinRef(projectSchema, item) {
|
|
370
313
|
const refItem = atRefToRefItem(projectSchema, item.ref);
|
|
371
|
-
|
|
372
314
|
if (refItem.serviceKey === 'local') {
|
|
373
315
|
const shape = refItemToShape(projectSchema, refItem);
|
|
374
|
-
|
|
375
316
|
if (!shape) {
|
|
376
317
|
return [{
|
|
377
318
|
type: 'notFound',
|
|
@@ -380,21 +321,16 @@ function validateLocalShapeJoinRef(projectSchema, item) {
|
|
|
380
321
|
}];
|
|
381
322
|
}
|
|
382
323
|
}
|
|
383
|
-
|
|
384
324
|
return [];
|
|
385
325
|
}
|
|
386
|
-
|
|
387
326
|
function validateLocalShapeJoins(projectSchema) {
|
|
388
327
|
return listShapeJoins(projectSchema).flatMap(item => validateLocalShapeJoinRef(projectSchema, item).concat(validateResolver(projectSchema, item.path.concat('resolver'), item.join.resolver)));
|
|
389
328
|
}
|
|
390
|
-
|
|
391
329
|
async function validateShapeJoinRef(context, projectSchema, item) {
|
|
392
330
|
const refItem = atRefToRefItem(projectSchema, item.ref);
|
|
393
|
-
|
|
394
331
|
if (refItem) {
|
|
395
332
|
const layer = await context.resolveLayer(refItem.serviceKey);
|
|
396
333
|
const valid = isValidRef(context, projectSchema, layer, refItem);
|
|
397
|
-
|
|
398
334
|
if (!valid) {
|
|
399
335
|
return [{
|
|
400
336
|
type: 'notFound',
|
|
@@ -403,32 +339,24 @@ async function validateShapeJoinRef(context, projectSchema, item) {
|
|
|
403
339
|
}];
|
|
404
340
|
}
|
|
405
341
|
}
|
|
406
|
-
|
|
407
342
|
return [];
|
|
408
343
|
}
|
|
409
|
-
|
|
410
344
|
async function validateShapeJoins(context, projectSchema) {
|
|
411
345
|
const promises = [];
|
|
412
|
-
|
|
413
346
|
for (const item of listShapeJoins(projectSchema)) {
|
|
414
347
|
promises.push(validateShapeJoinRef(context, projectSchema, item), validateResolverReferences(context, projectSchema, item.path, item.join.resolver));
|
|
415
348
|
}
|
|
416
|
-
|
|
417
349
|
return flatten(await Promise.all(promises));
|
|
418
350
|
}
|
|
419
|
-
|
|
420
351
|
function validateShapeLoaders(projectSchema, shape) {
|
|
421
352
|
const errors = [];
|
|
422
|
-
|
|
423
353
|
if (shape.loaders) {
|
|
424
354
|
const getNamespace = createGetNamespace(projectSchema);
|
|
425
355
|
const listLoader = shape.loaders.list;
|
|
426
|
-
|
|
427
356
|
if (listLoader) {
|
|
428
357
|
ensureArray(listLoader).forEach((config, i) => {
|
|
429
358
|
const ref = parsePropertyRef(config.query);
|
|
430
359
|
const query = ref && get(projectSchema, propertyRefItemToPath(getNamespace, ref));
|
|
431
|
-
|
|
432
360
|
if (!query) {
|
|
433
361
|
errors.push({
|
|
434
362
|
path: Array.isArray(listLoader) ? ['shapes', shape.name, 'loaders', 'list', i, 'query'] : ['shapes', shape.name, 'loaders', 'list', 'query'],
|
|
@@ -438,13 +366,10 @@ function validateShapeLoaders(projectSchema, shape) {
|
|
|
438
366
|
}
|
|
439
367
|
});
|
|
440
368
|
}
|
|
441
|
-
|
|
442
369
|
const getLoader = shape.loaders.get;
|
|
443
|
-
|
|
444
370
|
if (getLoader) {
|
|
445
371
|
const ref = parsePropertyRef(getLoader.query);
|
|
446
372
|
const query = ref && get(projectSchema, propertyRefItemToPath(getNamespace, ref));
|
|
447
|
-
|
|
448
373
|
if (!query) {
|
|
449
374
|
errors.push({
|
|
450
375
|
path: ['shapes', shape.name, 'loaders', 'get', 'query'],
|
|
@@ -454,10 +379,8 @@ function validateShapeLoaders(projectSchema, shape) {
|
|
|
454
379
|
}
|
|
455
380
|
}
|
|
456
381
|
}
|
|
457
|
-
|
|
458
382
|
return errors;
|
|
459
383
|
}
|
|
460
|
-
|
|
461
384
|
function visitProperties(projectSchema, callback) {
|
|
462
385
|
JSONPath('$..properties.*', projectSchema, (property, _type, {
|
|
463
386
|
path: propertyPath
|
|
@@ -465,28 +388,22 @@ function visitProperties(projectSchema, callback) {
|
|
|
465
388
|
callback(property, propertyPath.slice(3, -2).split(`']['`));
|
|
466
389
|
}, undefined);
|
|
467
390
|
}
|
|
468
|
-
|
|
469
391
|
function validateIndexedShapes(projectSchema) {
|
|
470
392
|
const errors = [];
|
|
471
393
|
const {
|
|
472
394
|
shapes
|
|
473
395
|
} = projectSchema;
|
|
474
|
-
|
|
475
396
|
for (const shape of Object.values(shapes)) {
|
|
476
397
|
const newErrors = validateShapeLoaders(projectSchema, shape);
|
|
477
|
-
|
|
478
398
|
if (newErrors.length) {
|
|
479
399
|
errors.push(...newErrors);
|
|
480
400
|
}
|
|
481
401
|
}
|
|
482
|
-
|
|
483
402
|
let nestedCount = 0;
|
|
484
403
|
visitProperties(projectSchema, (property, propertyPath) => {
|
|
485
404
|
const indexed = property['@indexed'];
|
|
486
|
-
|
|
487
405
|
if (isRecord(indexed) && indexed.nested) {
|
|
488
406
|
nestedCount += 1;
|
|
489
|
-
|
|
490
407
|
if (property.type !== 'array') {
|
|
491
408
|
errors.push({
|
|
492
409
|
path: propertyPath,
|
|
@@ -496,7 +413,6 @@ function validateIndexedShapes(projectSchema) {
|
|
|
496
413
|
}
|
|
497
414
|
}
|
|
498
415
|
});
|
|
499
|
-
|
|
500
416
|
if (nestedCount > 50) {
|
|
501
417
|
errors.push({
|
|
502
418
|
path: ['shapes'],
|
|
@@ -504,24 +420,20 @@ function validateIndexedShapes(projectSchema) {
|
|
|
504
420
|
message: `${nestedCount} nested indexes found`
|
|
505
421
|
});
|
|
506
422
|
}
|
|
507
|
-
|
|
508
423
|
return errors;
|
|
509
424
|
}
|
|
425
|
+
|
|
510
426
|
/**
|
|
511
427
|
* Verify the path has an allOf schema and not just prop named "allOf"
|
|
512
428
|
*/
|
|
513
|
-
|
|
514
|
-
|
|
515
429
|
function isAllOfPath(path) {
|
|
516
430
|
const index = path.indexOf('allOf');
|
|
517
431
|
return index !== -1 && isIntegerLike(path[index + 1]);
|
|
518
432
|
}
|
|
519
|
-
|
|
520
433
|
function validateLocalRefs(projectSchema) {
|
|
521
434
|
const errors = [];
|
|
522
435
|
const shapeNames = new Set([...builtInShapeNames, ...Object.keys(projectSchema.shapes)]);
|
|
523
436
|
const refs = getAllRefs(projectSchema).filter(item => !item.isForeign);
|
|
524
|
-
|
|
525
437
|
for (const item of refs) {
|
|
526
438
|
if (item.template && !isValidTemplate(item.template)) {
|
|
527
439
|
errors.push({
|
|
@@ -530,9 +442,7 @@ function validateLocalRefs(projectSchema) {
|
|
|
530
442
|
message: `Invalid template "${item.template}"`
|
|
531
443
|
});
|
|
532
444
|
}
|
|
533
|
-
|
|
534
445
|
const shapeName = refItemToShapeName(item);
|
|
535
|
-
|
|
536
446
|
if (!shapeNames.has(shapeName)) {
|
|
537
447
|
const invalidRef = get(projectSchema, item.path);
|
|
538
448
|
const path = invalidRef.items ? [...item.path, 'items', '@ref'] : item.path;
|
|
@@ -542,9 +452,9 @@ function validateLocalRefs(projectSchema) {
|
|
|
542
452
|
path,
|
|
543
453
|
message: `Invalid ref "${ref}"`
|
|
544
454
|
});
|
|
545
|
-
}
|
|
546
|
-
|
|
455
|
+
}
|
|
547
456
|
|
|
457
|
+
// Make sure refs inside allOf don't refer to their own Shape
|
|
548
458
|
if (item.path[1] === shapeName && isAllOfPath(item.path)) {
|
|
549
459
|
errors.push({
|
|
550
460
|
type: 'conflict',
|
|
@@ -552,11 +462,9 @@ function validateLocalRefs(projectSchema) {
|
|
|
552
462
|
message: `allOf cannot be self-referential`
|
|
553
463
|
});
|
|
554
464
|
}
|
|
555
|
-
|
|
556
465
|
const parentPath = initial(item.path);
|
|
557
466
|
const parentSchema = get(projectSchema, parentPath);
|
|
558
467
|
const propName = last(item.path);
|
|
559
|
-
|
|
560
468
|
if (propName === '@ref' && parentSchema.$ref) {
|
|
561
469
|
errors.push({
|
|
562
470
|
type: 'conflict',
|
|
@@ -565,10 +473,8 @@ function validateLocalRefs(projectSchema) {
|
|
|
565
473
|
});
|
|
566
474
|
}
|
|
567
475
|
}
|
|
568
|
-
|
|
569
476
|
return errors;
|
|
570
477
|
}
|
|
571
|
-
|
|
572
478
|
function isValidRef(context, projectSchema, layer, item) {
|
|
573
479
|
const {
|
|
574
480
|
serviceKey: layerId
|
|
@@ -577,7 +483,6 @@ function isValidRef(context, projectSchema, layer, item) {
|
|
|
577
483
|
const localShapeExists = Boolean(projectSchema.shapes[shapeName]) || builtInShapeNames.has(shapeName);
|
|
578
484
|
return layerId === 'local' ? localShapeExists : localShapeExists || isValidShapeReference(context, layer, shapeName);
|
|
579
485
|
}
|
|
580
|
-
|
|
581
486
|
async function validateRefs(context, projectSchema) {
|
|
582
487
|
const {
|
|
583
488
|
resolveLayer
|
|
@@ -585,15 +490,12 @@ async function validateRefs(context, projectSchema) {
|
|
|
585
490
|
const errors = [];
|
|
586
491
|
const refs = getAllRefs(projectSchema);
|
|
587
492
|
const layerIds = new Set();
|
|
588
|
-
|
|
589
493
|
for (const item of refs) {
|
|
590
494
|
if (item.serviceKey !== 'local') {
|
|
591
495
|
layerIds.add(item.serviceKey);
|
|
592
496
|
}
|
|
593
497
|
}
|
|
594
|
-
|
|
595
498
|
const layersById = Object.fromEntries(await pMap(layerIds, async layerId => [layerId, await resolveLayer(layerId)]));
|
|
596
|
-
|
|
597
499
|
for (const item of refs) {
|
|
598
500
|
if (item.template && !isValidTemplate(item.template)) {
|
|
599
501
|
errors.push({
|
|
@@ -602,12 +504,10 @@ async function validateRefs(context, projectSchema) {
|
|
|
602
504
|
message: `Invalid template "${item.path}"`
|
|
603
505
|
});
|
|
604
506
|
}
|
|
605
|
-
|
|
606
507
|
const {
|
|
607
508
|
serviceKey: layerId
|
|
608
509
|
} = item;
|
|
609
510
|
const valid = isValidRef(context, projectSchema, layersById[layerId], item);
|
|
610
|
-
|
|
611
511
|
if (!valid) {
|
|
612
512
|
errors.push({
|
|
613
513
|
type: 'notFound',
|
|
@@ -616,10 +516,8 @@ async function validateRefs(context, projectSchema) {
|
|
|
616
516
|
});
|
|
617
517
|
}
|
|
618
518
|
}
|
|
619
|
-
|
|
620
519
|
return errors;
|
|
621
520
|
}
|
|
622
|
-
|
|
623
521
|
function visitShapePropertiesJson(projectSchema, callback) {
|
|
624
522
|
JSONPath('shapes.*.schema.properties.*', projectSchema, (property, _type, {
|
|
625
523
|
path: propertyPath
|
|
@@ -627,16 +525,13 @@ function visitShapePropertiesJson(projectSchema, callback) {
|
|
|
627
525
|
callback(property, propertyPath.slice(3, -2).split(`']['`));
|
|
628
526
|
}, undefined);
|
|
629
527
|
}
|
|
630
|
-
|
|
631
528
|
function validateDirectives(projectSchema) {
|
|
632
529
|
const errors = [];
|
|
633
530
|
visitShapePropertiesJson(projectSchema, (property, propertyPath) => {
|
|
634
531
|
const resolver = property['@resolver'];
|
|
635
|
-
|
|
636
532
|
if (resolver) {
|
|
637
533
|
const propPath = propertyPath.concat('@resolver');
|
|
638
534
|
const resolverErrors = validateResolver(projectSchema, propPath, resolver);
|
|
639
|
-
|
|
640
535
|
if (resolverErrors) {
|
|
641
536
|
errors.push(...resolverErrors);
|
|
642
537
|
}
|
|
@@ -644,7 +539,6 @@ function validateDirectives(projectSchema) {
|
|
|
644
539
|
});
|
|
645
540
|
return errors;
|
|
646
541
|
}
|
|
647
|
-
|
|
648
542
|
function validateOneOfs(projectSchema) {
|
|
649
543
|
const errors = [];
|
|
650
544
|
visitShapePropertiesJson(projectSchema, (property, propertyPath) => {
|
|
@@ -652,7 +546,6 @@ function validateOneOfs(projectSchema) {
|
|
|
652
546
|
const relationship = getRelationship(property);
|
|
653
547
|
const schema = property.items ? property.items : property;
|
|
654
548
|
const isUnion = isUnionSchema(schema);
|
|
655
|
-
|
|
656
549
|
if (schema.oneOf && !relationship && !isUnion && !isEnumLikeSchema(schema)) {
|
|
657
550
|
errors.push({
|
|
658
551
|
type: 'conflict',
|
|
@@ -660,7 +553,6 @@ function validateOneOfs(projectSchema) {
|
|
|
660
553
|
message: `Invalid oneOf must contain only @ref or title + enum/const schemas`
|
|
661
554
|
});
|
|
662
555
|
}
|
|
663
|
-
|
|
664
556
|
if (isUnion && schema.oneOf.length !== uniqBy(schema.oneOf, refSchema => getRefShapeName(projectSchema, refSchema)).length) {
|
|
665
557
|
errors.push({
|
|
666
558
|
type: 'conflict',
|
|
@@ -671,14 +563,12 @@ function validateOneOfs(projectSchema) {
|
|
|
671
563
|
});
|
|
672
564
|
return errors;
|
|
673
565
|
}
|
|
674
|
-
|
|
675
566
|
function validateLocales(projectSchema) {
|
|
676
567
|
const {
|
|
677
568
|
locales,
|
|
678
569
|
defaultLocale
|
|
679
570
|
} = projectSchema;
|
|
680
571
|
const errors = [];
|
|
681
|
-
|
|
682
572
|
if (locales && !locales.includes(defaultLocale)) {
|
|
683
573
|
errors.push({
|
|
684
574
|
type: 'notFound',
|
|
@@ -686,27 +576,21 @@ function validateLocales(projectSchema) {
|
|
|
686
576
|
message: `Default locale "${defaultLocale}" missing from locales`
|
|
687
577
|
});
|
|
688
578
|
}
|
|
689
|
-
|
|
690
579
|
return errors;
|
|
691
580
|
}
|
|
692
|
-
|
|
693
581
|
const importantFields = ['type', '@ref', 'allOf', 'oneOf', 'anyOf', 'extends', 'items', '@tag'];
|
|
694
|
-
|
|
695
582
|
function isSchemaEqual(a, b) {
|
|
696
583
|
return isEqual(pick(a, importantFields), pick(b, importantFields));
|
|
697
584
|
}
|
|
698
|
-
|
|
699
585
|
function matchesInterface(shape, interfaceShape, path) {
|
|
700
586
|
const errors = [];
|
|
701
587
|
const {
|
|
702
588
|
schema
|
|
703
589
|
} = shape;
|
|
704
590
|
const interfaceSchema = interfaceShape.schema;
|
|
705
|
-
|
|
706
591
|
for (const name of Object.keys(interfaceSchema.properties)) {
|
|
707
592
|
const propSchema = schema.properties[name];
|
|
708
593
|
const interfacePropSchema = interfaceSchema.properties[name];
|
|
709
|
-
|
|
710
594
|
if (!propSchema) {
|
|
711
595
|
errors.push({
|
|
712
596
|
type: 'notFound',
|
|
@@ -721,10 +605,8 @@ function matchesInterface(shape, interfaceShape, path) {
|
|
|
721
605
|
});
|
|
722
606
|
} else {
|
|
723
607
|
var _schema$required, _interfaceSchema$requ;
|
|
724
|
-
|
|
725
608
|
const propRequired = Boolean((_schema$required = schema.required) === null || _schema$required === void 0 ? void 0 : _schema$required.includes(name));
|
|
726
609
|
const interfacePropRequired = Boolean((_interfaceSchema$requ = interfaceSchema.required) === null || _interfaceSchema$requ === void 0 ? void 0 : _interfaceSchema$requ.includes(name));
|
|
727
|
-
|
|
728
610
|
if (interfacePropRequired !== propRequired) {
|
|
729
611
|
errors.push({
|
|
730
612
|
type: 'conflict',
|
|
@@ -734,14 +616,11 @@ function matchesInterface(shape, interfaceShape, path) {
|
|
|
734
616
|
}
|
|
735
617
|
}
|
|
736
618
|
}
|
|
737
|
-
|
|
738
619
|
return errors;
|
|
739
620
|
}
|
|
740
|
-
|
|
741
621
|
function validateShapeImplementsInterface(projectSchema, shape, interfaceShapeName, path) {
|
|
742
622
|
const errors = [];
|
|
743
623
|
const interfaceShape = projectSchema.shapes[interfaceShapeName];
|
|
744
|
-
|
|
745
624
|
if (!interfaceShape) {
|
|
746
625
|
errors.push({
|
|
747
626
|
type: 'notFound',
|
|
@@ -754,24 +633,20 @@ function validateShapeImplementsInterface(projectSchema, shape, interfaceShapeNa
|
|
|
754
633
|
path,
|
|
755
634
|
message: `"${shape.name}" cannot implement non-interface "${interfaceShape.name}"`
|
|
756
635
|
});
|
|
757
|
-
} else if (isExtendsSchema(shape.schema)) {
|
|
636
|
+
} else if (isExtendsSchema(shape.schema)) {
|
|
637
|
+
// TODO stricter extends validation needs https://app.shortcut.com/takeshape/story/9783/use-service-schemas-during-schema-validation
|
|
758
638
|
} else if (isObjectSchema(shape.schema) && isObjectSchema(interfaceShape.schema)) {
|
|
759
639
|
const matchErrors = matchesInterface(shape, interfaceShape, ['shapes', shape.name, 'schema', 'properties']);
|
|
760
|
-
|
|
761
640
|
if (matchErrors.length) {
|
|
762
641
|
errors.push(...matchErrors);
|
|
763
642
|
}
|
|
764
643
|
}
|
|
765
|
-
|
|
766
644
|
return errors;
|
|
767
645
|
}
|
|
768
|
-
|
|
769
646
|
function validateInterfaceImplementations(projectSchema) {
|
|
770
647
|
const errors = [];
|
|
771
|
-
|
|
772
648
|
for (const shape of Object.values(projectSchema.shapes)) {
|
|
773
649
|
var _shape$interfaces;
|
|
774
|
-
|
|
775
650
|
if ((_shape$interfaces = shape.interfaces) !== null && _shape$interfaces !== void 0 && _shape$interfaces.length) {
|
|
776
651
|
if (!isObjectSchema(shape.schema) && !isExtendsSchema(shape.schema)) {
|
|
777
652
|
return [{
|
|
@@ -780,24 +655,20 @@ function validateInterfaceImplementations(projectSchema) {
|
|
|
780
655
|
message: `"${shape.name}" must have an object or extends schema to implement interfaces`
|
|
781
656
|
}];
|
|
782
657
|
}
|
|
783
|
-
|
|
784
658
|
for (let i = 0; i < shape.interfaces.length; i++) {
|
|
785
659
|
const path = ['shapes', shape.name, 'interfaces', i];
|
|
786
660
|
const interfaceErrors = validateShapeImplementsInterface(projectSchema, shape, shape.interfaces[i], path);
|
|
787
|
-
|
|
788
661
|
if (interfaceErrors.length) {
|
|
789
662
|
errors.push(...interfaceErrors);
|
|
790
663
|
}
|
|
791
664
|
}
|
|
792
665
|
}
|
|
793
666
|
}
|
|
794
|
-
|
|
795
667
|
return errors;
|
|
796
668
|
}
|
|
797
|
-
|
|
798
669
|
function validateInterfaces(projectSchema) {
|
|
799
|
-
const errors = [];
|
|
800
|
-
|
|
670
|
+
const errors = [];
|
|
671
|
+
// Validate interface shapes must be an object schema with at least one property
|
|
801
672
|
for (const shape of Object.values(projectSchema.shapes)) {
|
|
802
673
|
if (shape.type === 'interface') {
|
|
803
674
|
if (shape.model) {
|
|
@@ -823,27 +694,21 @@ function validateInterfaces(projectSchema) {
|
|
|
823
694
|
}
|
|
824
695
|
}
|
|
825
696
|
}
|
|
826
|
-
|
|
827
697
|
return errors;
|
|
828
698
|
}
|
|
829
|
-
|
|
830
699
|
export function formatError(error) {
|
|
831
700
|
let pathStr = error.instancePath;
|
|
832
701
|
let message = error.message ?? '';
|
|
833
|
-
|
|
834
702
|
if ('missingProperty' in error.params) {
|
|
835
703
|
pathStr = `${pathStr}.${error.params.missingProperty}`;
|
|
836
704
|
}
|
|
837
|
-
|
|
838
705
|
if ('additionalProperty' in error.params) {
|
|
839
706
|
pathStr = `${pathStr}.${error.params.additionalProperty}`;
|
|
840
707
|
message = `${message} "${error.params.additionalProperty}"`;
|
|
841
708
|
}
|
|
842
|
-
|
|
843
709
|
if ('allowedValues' in error.params) {
|
|
844
710
|
message = `${message} "${error.params.allowedValues.join('", "')}"`;
|
|
845
711
|
}
|
|
846
|
-
|
|
847
712
|
const path = pathStr === '' ? [] : pathStr.substr(1).split(/\.|\/|\['|']\./);
|
|
848
713
|
return {
|
|
849
714
|
type: 'json',
|
|
@@ -851,37 +716,29 @@ export function formatError(error) {
|
|
|
851
716
|
path
|
|
852
717
|
};
|
|
853
718
|
}
|
|
854
|
-
|
|
855
719
|
function isValidateReferencesContext(context) {
|
|
856
720
|
return Boolean(context.resolveLayer);
|
|
857
721
|
}
|
|
858
|
-
|
|
859
722
|
const ajv = createAjv();
|
|
860
|
-
|
|
861
723
|
function validateStructure(schemaVersion, context, schema, ref) {
|
|
862
724
|
var _coerce, _ajv$errors;
|
|
863
|
-
|
|
864
725
|
const versionStr = (_coerce = coerce(schemaVersion)) === null || _coerce === void 0 ? void 0 : _coerce.format();
|
|
865
726
|
const relevantSchemas = allProjectSchemas.filter(metaSchema => metaSchema.$id.endsWith(`v${versionStr}#`));
|
|
866
|
-
|
|
867
727
|
for (const relevantSchema of relevantSchemas) {
|
|
868
728
|
if (!ajv.getSchema(relevantSchema.$id)) {
|
|
869
729
|
ajv.addSchema(relevantSchema);
|
|
870
730
|
}
|
|
871
731
|
}
|
|
872
|
-
|
|
873
732
|
ajv.validate(`https://schema.takeshape.io/project-schema/v${versionStr}#${ref ?? ''}`, schema);
|
|
874
733
|
let errors = ((_ajv$errors = ajv.errors) === null || _ajv$errors === void 0 ? void 0 : _ajv$errors.map(formatError)) ?? [];
|
|
875
734
|
const {
|
|
876
735
|
suppressErrorPaths
|
|
877
736
|
} = context;
|
|
878
|
-
|
|
879
737
|
if (errors.length && suppressErrorPaths) {
|
|
880
738
|
errors = errors.filter(error => {
|
|
881
739
|
return !suppressErrorPaths.includes(error.path.join('.'));
|
|
882
740
|
});
|
|
883
741
|
}
|
|
884
|
-
|
|
885
742
|
if (errors.length) {
|
|
886
743
|
return {
|
|
887
744
|
valid: false,
|
|
@@ -889,25 +746,21 @@ function validateStructure(schemaVersion, context, schema, ref) {
|
|
|
889
746
|
errors
|
|
890
747
|
};
|
|
891
748
|
}
|
|
892
|
-
|
|
893
749
|
return {
|
|
894
750
|
valid: true,
|
|
895
751
|
schema: schema,
|
|
896
752
|
errors: undefined
|
|
897
753
|
};
|
|
898
754
|
}
|
|
899
|
-
|
|
900
755
|
function formatValidationResult(context, errors, schema) {
|
|
901
756
|
const {
|
|
902
757
|
suppressErrorPaths
|
|
903
758
|
} = context;
|
|
904
|
-
|
|
905
759
|
if (suppressErrorPaths) {
|
|
906
760
|
errors = errors.filter(error => {
|
|
907
761
|
return !suppressErrorPaths.includes(error.path.join('.'));
|
|
908
762
|
});
|
|
909
763
|
}
|
|
910
|
-
|
|
911
764
|
return errors.length ? {
|
|
912
765
|
valid: false,
|
|
913
766
|
schema: undefined,
|
|
@@ -918,18 +771,15 @@ function formatValidationResult(context, errors, schema) {
|
|
|
918
771
|
errors: undefined
|
|
919
772
|
};
|
|
920
773
|
}
|
|
921
|
-
|
|
922
774
|
function validateSyntax(context, schema) {
|
|
923
775
|
let errors = [];
|
|
924
776
|
errors = errors.concat(checkShapeNames(schema.shapes)).concat(checkShapeIds(schema.shapes)).concat(validateWorkflows(schema)).concat(validateLocalQueryConfigs(schema)).concat(validateLocalRefs(schema)).concat(validateLocalShapeJoins(schema)).concat(validateDirectives(schema)).concat(validateLocales(schema)).concat(checkWorkflowStepNames(schema.workflows)).concat(checkWorkflowStepKeys(schema.workflows)).concat(validateOneOfs(schema)).concat(validateIndexedShapes(schema)).concat(validateInterfaces(schema)).concat(validateInterfaceImplementations(schema));
|
|
925
777
|
return formatValidationResult(context, errors, schema);
|
|
926
778
|
}
|
|
927
|
-
|
|
928
779
|
async function validateReferences(context, schema) {
|
|
929
780
|
const errors = flatten(await Promise.all([validateRefs(context, schema), validateQueryConfigs(context, schema), validateShapeJoins(context, schema)]));
|
|
930
781
|
return formatValidationResult(context, errors, schema);
|
|
931
782
|
}
|
|
932
|
-
|
|
933
783
|
const schemaUndefinedResult = {
|
|
934
784
|
valid: false,
|
|
935
785
|
schema: undefined,
|
|
@@ -948,65 +798,51 @@ const invalidVersionResult = {
|
|
|
948
798
|
message: 'Unknown schema version'
|
|
949
799
|
}]
|
|
950
800
|
};
|
|
951
|
-
|
|
952
801
|
function normalizeSchemaVersion(obj) {
|
|
953
802
|
if (isRecord(obj)) {
|
|
954
803
|
return typeof obj.schemaVersion === 'string' ? obj.schemaVersion : '1';
|
|
955
804
|
}
|
|
956
805
|
}
|
|
957
|
-
|
|
958
806
|
export function validateSchemaSyntax(obj, options = {}) {
|
|
959
807
|
if (isUndefined(obj)) {
|
|
960
808
|
return schemaUndefinedResult;
|
|
961
809
|
}
|
|
962
|
-
|
|
963
810
|
const schemaVersion = normalizeSchemaVersion(obj);
|
|
964
|
-
|
|
965
811
|
if (!schemaVersion) {
|
|
966
812
|
return invalidVersionResult;
|
|
967
813
|
}
|
|
968
|
-
|
|
969
814
|
return validateStructure(schemaVersion, options, obj);
|
|
970
815
|
}
|
|
816
|
+
|
|
971
817
|
/**
|
|
972
818
|
* Validates a schema using a matching validation based on the `schemaVersion` property.
|
|
973
819
|
*/
|
|
974
|
-
|
|
975
820
|
export async function validateSchema(context, obj) {
|
|
976
821
|
if (isUndefined(obj)) {
|
|
977
822
|
return schemaUndefinedResult;
|
|
978
823
|
}
|
|
979
|
-
|
|
980
824
|
const contextWithDefaults = {
|
|
981
825
|
allowDisconnectedLayers: true,
|
|
982
826
|
...context
|
|
983
827
|
};
|
|
984
828
|
const schemaVersion = normalizeSchemaVersion(obj);
|
|
985
|
-
|
|
986
829
|
if (!schemaVersion) {
|
|
987
830
|
return invalidVersionResult;
|
|
988
831
|
}
|
|
989
|
-
|
|
990
832
|
const structuralValidation = validateStructure(schemaVersion, contextWithDefaults, obj);
|
|
991
|
-
|
|
992
833
|
if (!structuralValidation.valid) {
|
|
993
834
|
return structuralValidation;
|
|
994
835
|
}
|
|
995
|
-
|
|
996
836
|
const {
|
|
997
837
|
schema
|
|
998
838
|
} = structuralValidation;
|
|
999
|
-
|
|
1000
839
|
if (!isLatestProjectSchemaJSON(schema)) {
|
|
1001
840
|
return invalidVersionResult;
|
|
1002
841
|
}
|
|
1003
|
-
|
|
1004
842
|
const syntaxValidation = validateSyntax(contextWithDefaults, schema);
|
|
1005
|
-
|
|
1006
843
|
if (!syntaxValidation.valid || !isValidateReferencesContext(contextWithDefaults)) {
|
|
1007
844
|
return syntaxValidation;
|
|
1008
845
|
}
|
|
1009
|
-
|
|
1010
846
|
return validateReferences(contextWithDefaults, schema);
|
|
1011
847
|
}
|
|
1012
848
|
export function ensureValidLatestSchemaSyntax(obj) {
|
|
@@ -1015,26 +851,22 @@ export function ensureValidLatestSchemaSyntax(obj) {
|
|
|
1015
851
|
schema,
|
|
1016
852
|
errors
|
|
1017
853
|
} = validateSchemaSyntax(obj);
|
|
1018
|
-
|
|
1019
854
|
if (!valid && errors) {
|
|
1020
855
|
throw new Error(`Invalid Schema "${errors[0].path.join(',')}": "${errors[0].message}"`);
|
|
1021
856
|
}
|
|
1022
|
-
|
|
1023
857
|
if (isUndefined(schema)) {
|
|
1024
858
|
throw new Error(`Invalid schema: schema is undefined`);
|
|
1025
859
|
}
|
|
1026
|
-
|
|
1027
860
|
if (neq(CURRENT_SCHEMA_VERSION, coerce(schema.schemaVersion) ?? LEGACY_SCHEMA_VERSION)) {
|
|
1028
861
|
throw new Error(`Expected schemaVersion: "${CURRENT_SCHEMA_VERSION}", got "${schema.schemaVersion}"`);
|
|
1029
862
|
}
|
|
1030
|
-
|
|
1031
863
|
return schema;
|
|
1032
864
|
}
|
|
865
|
+
|
|
1033
866
|
/**
|
|
1034
867
|
* The roles import validator ensures required properties, and strips several
|
|
1035
868
|
* which might exist in an export but wouldn't apply to an import operation.
|
|
1036
869
|
*/
|
|
1037
|
-
|
|
1038
870
|
function createRoleInputValidator() {
|
|
1039
871
|
const validator = createAjv({
|
|
1040
872
|
useDefaults: true
|
|
@@ -1049,28 +881,24 @@ function createRoleInputValidator() {
|
|
|
1049
881
|
...RoleInput
|
|
1050
882
|
});
|
|
1051
883
|
}
|
|
884
|
+
|
|
1052
885
|
/**
|
|
1053
886
|
* Validates and returns a `RoleInput`, which is a subset of the `Role`
|
|
1054
887
|
* type's properties suitable for importing.
|
|
1055
888
|
*/
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
889
|
export function validateRoleInput(maybeRoleInput) {
|
|
1059
890
|
var _validate$errors;
|
|
1060
|
-
|
|
1061
891
|
const validate = createRoleInputValidator();
|
|
1062
|
-
|
|
1063
892
|
if (validate(maybeRoleInput)) {
|
|
1064
893
|
return maybeRoleInput;
|
|
1065
894
|
}
|
|
1066
|
-
|
|
1067
895
|
throw new SchemaValidationError('RoleInput was invalid', (_validate$errors = validate.errors) === null || _validate$errors === void 0 ? void 0 : _validate$errors.map(formatError));
|
|
1068
896
|
}
|
|
897
|
+
|
|
1069
898
|
/**
|
|
1070
899
|
* The roles import validator ensures required properties, and strips several
|
|
1071
900
|
* which might exist in an export but wouldn't apply to an import operation.
|
|
1072
901
|
*/
|
|
1073
|
-
|
|
1074
902
|
function createRoleImportValidator() {
|
|
1075
903
|
const validator = createAjv({
|
|
1076
904
|
useDefaults: true
|
|
@@ -1085,23 +913,18 @@ function createRoleImportValidator() {
|
|
|
1085
913
|
...RoleImport
|
|
1086
914
|
});
|
|
1087
915
|
}
|
|
916
|
+
|
|
1088
917
|
/**
|
|
1089
918
|
* Validates and returns a `RoleImport` array, which is a collection of `RoleInput`s.
|
|
1090
919
|
*/
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
920
|
export function ensureValidRoleImport(maybeRoles) {
|
|
1094
921
|
var _validate$errors2;
|
|
1095
|
-
|
|
1096
922
|
const validate = createRoleImportValidator();
|
|
1097
|
-
|
|
1098
923
|
if (validate(maybeRoles)) {
|
|
1099
924
|
return maybeRoles;
|
|
1100
925
|
}
|
|
1101
|
-
|
|
1102
926
|
throw new SchemaValidationError('Roles were invalid', (_validate$errors2 = validate.errors) === null || _validate$errors2 === void 0 ? void 0 : _validate$errors2.map(formatError));
|
|
1103
927
|
}
|
|
1104
|
-
|
|
1105
928
|
/**
|
|
1106
929
|
* Only use when validating an imported schema! ignore fields optional when importing
|
|
1107
930
|
*/
|
|
@@ -1110,19 +933,17 @@ export function validateProjectSchemaImport(maybeSchema) {
|
|
|
1110
933
|
suppressErrorPaths: [...projectSchemaImportOptionalProps, ...legacyProjectSchemaImportOptionalProps]
|
|
1111
934
|
});
|
|
1112
935
|
}
|
|
936
|
+
|
|
1113
937
|
/**
|
|
1114
938
|
* Only use when validating an imported schema!
|
|
1115
939
|
*
|
|
1116
940
|
* New style validation for parity with the `validateRoleImport` fn. Returns
|
|
1117
941
|
* a valid, clean `ImportProjectSchema` or throws a `SchemaValidationError`.
|
|
1118
942
|
*/
|
|
1119
|
-
|
|
1120
943
|
export function ensureValidProjectSchemaImport(maybeSchema) {
|
|
1121
944
|
const validateResult = validateProjectSchemaImport(maybeSchema);
|
|
1122
|
-
|
|
1123
945
|
if (validateResult.valid) {
|
|
1124
946
|
return validateResult.schema;
|
|
1125
947
|
}
|
|
1126
|
-
|
|
1127
948
|
throw new SchemaValidationError('ProjectSchema could not be validated', validateResult.errors);
|
|
1128
949
|
}
|