@takeshape/schema 11.89.0 → 11.91.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/flatten-templates.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/interfaces.d.ts +4 -2
- package/dist/interfaces.js +6 -5
- package/dist/migration/to/v3.34.0.js +2 -7
- package/dist/models/runtime-schema.js +7 -7
- package/dist/models/shape.d.ts +1 -0
- package/dist/models/shape.js +5 -2
- package/dist/refs.d.ts +30 -51
- package/dist/refs.js +101 -137
- package/dist/relationships.d.ts +1 -1
- package/dist/relationships.js +22 -31
- package/dist/schema-util.d.ts +4 -16
- package/dist/schema-util.js +12 -45
- package/dist/service-dependencies.js +9 -9
- package/dist/template-shapes/templates.d.ts +10 -10
- package/dist/template-shapes/templates.js +6 -9
- package/dist/template-shapes/where.js +9 -11
- package/dist/types/types.d.ts +0 -14
- package/dist/types/types.js +0 -8
- package/dist/types/utils.d.ts +2 -8
- package/dist/types/utils.js +1 -14
- package/dist/unions.js +2 -2
- package/dist/util/expressions.d.ts +13 -2
- package/dist/util/expressions.js +32 -0
- package/dist/util/form-config.js +1 -1
- package/dist/util/get-conflicting-properties.js +2 -2
- package/dist/util/has-arg.js +2 -2
- package/dist/util/is-asset-property.d.ts +3 -0
- package/dist/util/is-asset-property.js +11 -0
- package/dist/util/merge.js +1 -1
- package/dist/validate/validate.js +24 -20
- package/package.json +6 -5
package/dist/refs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NotFoundError } from '@takeshape/errors';
|
|
2
|
-
import { isDefined, isIntegerLike, isRecord, visit } from '@takeshape/util';
|
|
2
|
+
import { deepCloneWith, isDefined, isIntegerLike, isIterableObject, isRecord, visit } from '@takeshape/util';
|
|
3
3
|
import compact from 'lodash/compact.js';
|
|
4
4
|
import assign from 'lodash/fp/assign.js';
|
|
5
5
|
import omit from 'lodash/fp/omit.js';
|
|
@@ -7,15 +7,10 @@ import get from 'lodash/get.js';
|
|
|
7
7
|
import isString from 'lodash/isString.js';
|
|
8
8
|
import { isScalar } from "./scalars.js";
|
|
9
9
|
import { getServiceNamespaces } from "./services/util.js";
|
|
10
|
-
import {
|
|
10
|
+
import { isAllOfSchema, isExtendsSchema, isObjectSchema, isOneOfSchema, isRefSchema, isRefSchemaLegacy } from "./types/index.js";
|
|
11
11
|
import { mergeDeepObjectSchemas, mergeObjectSchemas } from "./util/merge.js";
|
|
12
12
|
import { getShape } from "./util/shapes.js";
|
|
13
|
-
|
|
14
|
-
* Guard for RefItemWithPath. Tests for presence of all required props.
|
|
15
|
-
*/
|
|
16
|
-
export function isRefItemWithPath(ref) {
|
|
17
|
-
return Boolean(ref.typeName && ref.serviceKey && ref.path && isDefined(ref.isForeign));
|
|
18
|
-
}
|
|
13
|
+
export const LOCAL_LAYER_ID = 'local';
|
|
19
14
|
const templateShapeRegex = /^(\w+)<([\w:-]+)>$/;
|
|
20
15
|
/**
|
|
21
16
|
* Parse a template like `PaginatedList<Post>` and return both the template and the shape name.
|
|
@@ -27,17 +22,17 @@ export function parseTemplateShape(shapeExpression) {
|
|
|
27
22
|
}
|
|
28
23
|
return { shapeName: shapeExpression, template: undefined };
|
|
29
24
|
}
|
|
30
|
-
export function parseReturnShape(
|
|
25
|
+
export function parseReturnShape(context, shape) {
|
|
31
26
|
if (typeof shape === 'object') {
|
|
32
27
|
if (isRefSchema(shape.items)) {
|
|
33
|
-
const ref = getRef(
|
|
28
|
+
const ref = getRef(context, shape.items);
|
|
34
29
|
if (!ref) {
|
|
35
30
|
throw new Error(`Could not parse ${JSON.stringify(shape.items)}: invalid ref`);
|
|
36
31
|
}
|
|
37
32
|
return {
|
|
38
33
|
isArray: true,
|
|
39
34
|
ref,
|
|
40
|
-
shapeName: refItemToNamespacedShapeName(ref)
|
|
35
|
+
shapeName: refItemToNamespacedShapeName(context, ref)
|
|
41
36
|
};
|
|
42
37
|
}
|
|
43
38
|
if (typeof shape.items.type !== 'string') {
|
|
@@ -45,8 +40,8 @@ export function parseReturnShape(projectSchema, shape) {
|
|
|
45
40
|
}
|
|
46
41
|
return { isArray: true, shapeName: shape.items.type };
|
|
47
42
|
}
|
|
48
|
-
const ref =
|
|
49
|
-
const shapeName = refItemToNamespacedShapeName(ref);
|
|
43
|
+
const ref = parseRef(context, shape);
|
|
44
|
+
const shapeName = refItemToNamespacedShapeName(context, ref);
|
|
50
45
|
return { isArray: false, shapeName, ref, template: ref.template };
|
|
51
46
|
}
|
|
52
47
|
/**
|
|
@@ -58,7 +53,7 @@ export function returnShapeToSchema(projectSchema, returnShape) {
|
|
|
58
53
|
return { type: returnShape };
|
|
59
54
|
}
|
|
60
55
|
return {
|
|
61
|
-
'@ref':
|
|
56
|
+
'@ref': serializeRef(parseRef(projectSchema, returnShape))
|
|
62
57
|
};
|
|
63
58
|
}
|
|
64
59
|
return returnShape;
|
|
@@ -85,19 +80,12 @@ function $refToPath(ref) {
|
|
|
85
80
|
function $refToShapeName(ref) {
|
|
86
81
|
return $refToPath(ref)[1];
|
|
87
82
|
}
|
|
88
|
-
export function $refToAtRef($ref, service, namespace) {
|
|
89
|
-
const shapeName = $refToShapeName($ref);
|
|
90
|
-
if (service === 'local') {
|
|
91
|
-
return `local:${shapeName}`;
|
|
92
|
-
}
|
|
93
|
-
return `${service}:${namespace === undefined ? shapeName : shapeName.replace(`${namespace}_`, '')}`;
|
|
94
|
-
}
|
|
95
83
|
export function refSchemaToPath(context, refSchema) {
|
|
96
84
|
const refItem = getRef(context, refSchema);
|
|
97
85
|
if (refItem === undefined) {
|
|
98
86
|
throw new Error('Invalid ref in refSchemaToPath');
|
|
99
87
|
}
|
|
100
|
-
return refItemToShapePath(refItem);
|
|
88
|
+
return refItemToShapePath(context, refItem);
|
|
101
89
|
}
|
|
102
90
|
/**
|
|
103
91
|
* Safely turn a "template" shape reference (`@args`, `args`, `shape`) into a `RefItem`
|
|
@@ -107,18 +95,25 @@ export function refSchemaToPath(context, refSchema) {
|
|
|
107
95
|
* A ref expression might include "template" name and refer to a local or remote
|
|
108
96
|
* shape, `Foo` or `CreateArgs<Foo>` or `CreateArgs<remote:Foo>`.*
|
|
109
97
|
*/
|
|
110
|
-
export function
|
|
98
|
+
export function parseRef(context, refExpression) {
|
|
111
99
|
const { shapeName, template } = parseTemplateShape(refExpression);
|
|
112
100
|
if (shapeName.includes(':')) {
|
|
113
|
-
return
|
|
101
|
+
return refExpressionToRefItem(shapeName, template);
|
|
114
102
|
}
|
|
115
103
|
return shapeNameToRefItem(context, shapeName, template);
|
|
116
104
|
}
|
|
105
|
+
export function isRefEqual(context, a, b) {
|
|
106
|
+
const parsedA = typeof a === 'string' ? parseRef(context, a) : a;
|
|
107
|
+
const parsedB = typeof b === 'string' ? parseRef(context, b) : b;
|
|
108
|
+
return (parsedA.shapeName === parsedB.shapeName &&
|
|
109
|
+
parsedA.layerId === parsedB.layerId &&
|
|
110
|
+
parsedA.template === parsedB.template);
|
|
111
|
+
}
|
|
117
112
|
/**
|
|
118
113
|
* Converts a list of ref expressions into a list of ref items.
|
|
119
114
|
*/
|
|
120
115
|
export function refExpressionListToRefItemList(context, refExpressionList) {
|
|
121
|
-
return refExpressionList.map((ref) =>
|
|
116
|
+
return refExpressionList.map((ref) => parseRef(context, ref));
|
|
122
117
|
}
|
|
123
118
|
/**
|
|
124
119
|
* Sugar for converting a `refExpression` directly into a shape, without the
|
|
@@ -129,8 +124,8 @@ export function refExpressionListToRefItemList(context, refExpressionList) {
|
|
|
129
124
|
* A ref expression might include "template" name and refer to a local or remote
|
|
130
125
|
* shape, `Foo` or `CreateArgs<Foo>` or `CreateArgs<remote:Foo>`.
|
|
131
126
|
*/
|
|
132
|
-
export function
|
|
133
|
-
return refItemToShape(context,
|
|
127
|
+
export function getShapeByRef(context, refExpression) {
|
|
128
|
+
return refItemToShape(context, parseRef(context, refExpression));
|
|
134
129
|
}
|
|
135
130
|
/**
|
|
136
131
|
* Provided a service name and a referenced type. Supports 2 or 3 part
|
|
@@ -139,32 +134,30 @@ export function refExpressionToShape(context, refExpression) {
|
|
|
139
134
|
* @returns
|
|
140
135
|
* A 2 member array, where 0 is the service name, 1 is the referenced type.
|
|
141
136
|
*/
|
|
142
|
-
|
|
143
|
-
const index =
|
|
144
|
-
const serviceKey = index === -1 ?
|
|
145
|
-
const referencedType = index === -1 ?
|
|
137
|
+
function splitRefExpression(ref) {
|
|
138
|
+
const index = ref.lastIndexOf(':');
|
|
139
|
+
const serviceKey = index === -1 ? LOCAL_LAYER_ID : ref.substring(0, index);
|
|
140
|
+
const referencedType = index === -1 ? ref : ref.substring(index + 1);
|
|
146
141
|
return [serviceKey, referencedType];
|
|
147
142
|
}
|
|
148
|
-
function isValidServiceId(context, serviceId) {
|
|
149
|
-
return serviceId ===
|
|
143
|
+
export function isValidServiceId(context, serviceId) {
|
|
144
|
+
return serviceId === LOCAL_LAYER_ID || Boolean(context.services?.[serviceId]);
|
|
145
|
+
}
|
|
146
|
+
export function isValidRefItem(context) {
|
|
147
|
+
return (refItem) => {
|
|
148
|
+
return isValidServiceId(context, refItem.layerId);
|
|
149
|
+
};
|
|
150
150
|
}
|
|
151
151
|
/**
|
|
152
152
|
* Parses and returns a typeName, serviceKey, and potentially a namespace for
|
|
153
153
|
* the type.
|
|
154
154
|
*/
|
|
155
|
-
|
|
156
|
-
const [serviceKey, typeName] =
|
|
157
|
-
// It's possible the service doesn't have a namespace, or is local and has
|
|
158
|
-
// no service config.
|
|
159
|
-
const serviceConfig = context.services?.[serviceKey];
|
|
160
|
-
const serviceNamespace = serviceConfig?.namespace;
|
|
155
|
+
function refExpressionToRefItem(ref, template) {
|
|
156
|
+
const [serviceKey, typeName] = splitRefExpression(ref);
|
|
161
157
|
return {
|
|
162
|
-
typeName,
|
|
163
|
-
serviceKey,
|
|
164
|
-
|
|
165
|
-
template,
|
|
166
|
-
isForeign: Boolean(serviceConfig),
|
|
167
|
-
isValidService: isValidServiceId(context, serviceKey)
|
|
158
|
+
shapeName: typeName,
|
|
159
|
+
layerId: serviceKey,
|
|
160
|
+
template
|
|
168
161
|
};
|
|
169
162
|
}
|
|
170
163
|
export function refToRefItem(context, $ref, template) {
|
|
@@ -175,39 +168,33 @@ export function refToRefItem(context, $ref, template) {
|
|
|
175
168
|
*/
|
|
176
169
|
export function parseName(context, name) {
|
|
177
170
|
const shapeNameParts = name.split('_');
|
|
178
|
-
let
|
|
179
|
-
let namespace;
|
|
171
|
+
let layerId;
|
|
180
172
|
if (shapeNameParts.length > 1) {
|
|
181
173
|
const namespaces = getServiceNamespaces(context);
|
|
182
174
|
const maybeNamespace = shapeNameParts[0];
|
|
183
|
-
|
|
184
|
-
if (
|
|
175
|
+
layerId = namespaces.get(maybeNamespace);
|
|
176
|
+
if (layerId) {
|
|
185
177
|
name = shapeNameParts.slice(1).join('_');
|
|
186
|
-
namespace = maybeNamespace;
|
|
187
178
|
}
|
|
188
179
|
}
|
|
189
180
|
return {
|
|
190
181
|
name,
|
|
191
|
-
|
|
192
|
-
namespace
|
|
182
|
+
layerId: layerId ?? LOCAL_LAYER_ID
|
|
193
183
|
};
|
|
194
184
|
}
|
|
195
185
|
function shapeNameToRefItem(context, shapeName, template) {
|
|
196
186
|
const parsed = parseName(context, shapeName);
|
|
197
187
|
return {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
template,
|
|
202
|
-
isForeign: parsed.serviceId !== 'local',
|
|
203
|
-
isValidService: isValidServiceId(context, parsed.serviceId)
|
|
188
|
+
shapeName: parsed.name,
|
|
189
|
+
layerId: parsed.layerId,
|
|
190
|
+
template
|
|
204
191
|
};
|
|
205
192
|
}
|
|
206
193
|
export function shapeToRefItem(context, shape) {
|
|
207
194
|
return shapeNameToRefItem(context, shape.name);
|
|
208
195
|
}
|
|
209
196
|
export function shapeToRefString(context, shape) {
|
|
210
|
-
return
|
|
197
|
+
return serializeRef(shapeNameToRefItem(context, shape.name));
|
|
211
198
|
}
|
|
212
199
|
/**
|
|
213
200
|
* Given a property schema and project schema, finds a `@ref` or `$ref` and
|
|
@@ -217,21 +204,20 @@ export function getRef(context, refSchema) {
|
|
|
217
204
|
if (refSchema['@ref']) {
|
|
218
205
|
// @ref: my-service:ShapeName
|
|
219
206
|
const { shapeName, template } = parseTemplateShape(refSchema['@ref']);
|
|
220
|
-
return
|
|
207
|
+
return refExpressionToRefItem(shapeName, template);
|
|
221
208
|
}
|
|
222
209
|
if (refSchema.$ref) {
|
|
223
210
|
// $ref: #/shapes/[ShapeName OR Namespace_TypeName]/schema
|
|
224
211
|
return refToRefItem(context, refSchema.$ref);
|
|
225
212
|
}
|
|
226
213
|
}
|
|
227
|
-
export function getRefWithPath(context, refSchema, schemaPath = []
|
|
214
|
+
export function getRefWithPath(context, refSchema, schemaPath = []) {
|
|
228
215
|
const refItem = getRef(context, refSchema);
|
|
229
216
|
if (refItem) {
|
|
230
|
-
const refType =
|
|
217
|
+
const refType = refSchema['@ref'] ? '@ref' : '$ref';
|
|
231
218
|
return {
|
|
232
219
|
...refItem,
|
|
233
|
-
path: schemaPath.concat([refType])
|
|
234
|
-
isInterfaceRef
|
|
220
|
+
path: schemaPath.concat([refType])
|
|
235
221
|
};
|
|
236
222
|
}
|
|
237
223
|
}
|
|
@@ -272,28 +258,32 @@ export function getRefOrItemsRef(context, refSchema, schemaPath = []) {
|
|
|
272
258
|
/**
|
|
273
259
|
* Turns a `RefItem` into an `@ref`.
|
|
274
260
|
*/
|
|
275
|
-
export function
|
|
276
|
-
const shapeRef =
|
|
261
|
+
export function serializeRef(refItem) {
|
|
262
|
+
const shapeRef = formatShapeRef(refItem.layerId, refItem.shapeName);
|
|
277
263
|
return refItem.template ? createTemplateShapeName(refItem.template, shapeRef) : shapeRef;
|
|
278
264
|
}
|
|
279
265
|
/**
|
|
280
266
|
* Turns a `RefItem` into a standard shape name, namespacing if present.
|
|
281
267
|
*/
|
|
282
|
-
export function refItemToNamespacedShapeName(refItem) {
|
|
283
|
-
const {
|
|
284
|
-
|
|
268
|
+
export function refItemToNamespacedShapeName(context, refItem) {
|
|
269
|
+
const { shapeName, layerId } = refItem;
|
|
270
|
+
const namespace = getNamespace(context, layerId);
|
|
271
|
+
return namespace ? `${namespace}_${shapeName}` : shapeName;
|
|
272
|
+
}
|
|
273
|
+
export function refExpressionToNamespacedName(context, refExpression) {
|
|
274
|
+
return refItemToNamespacedShapeName(context, parseRef(context, refExpression));
|
|
285
275
|
}
|
|
286
276
|
/**
|
|
287
277
|
* Turns a `RefItem` into a path suitable for `lodash.get`.
|
|
288
278
|
*/
|
|
289
|
-
export function refItemToShapePath(refItem) {
|
|
290
|
-
return ['shapes', refItemToNamespacedShapeName(refItem)];
|
|
279
|
+
export function refItemToShapePath(context, refItem) {
|
|
280
|
+
return ['shapes', refItemToNamespacedShapeName(context, refItem)];
|
|
291
281
|
}
|
|
292
282
|
/**
|
|
293
283
|
* Get a Shape referenced by a `RefItem`.
|
|
294
284
|
*/
|
|
295
285
|
export function refItemToShape(context, refItem) {
|
|
296
|
-
const shapePath = refItemToShapePath(refItem);
|
|
286
|
+
const shapePath = refItemToShapePath(context, refItem);
|
|
297
287
|
return get(context, shapePath);
|
|
298
288
|
}
|
|
299
289
|
/**
|
|
@@ -306,7 +296,7 @@ export function refItemListToShapeList(context, refItems) {
|
|
|
306
296
|
* Get a shape referenced by a `RefItem`, also returning the path to the new shape.
|
|
307
297
|
*/
|
|
308
298
|
export function refItemToShapeWithPath(context, refItem) {
|
|
309
|
-
const shapePath = refItemToShapePath(refItem);
|
|
299
|
+
const shapePath = refItemToShapePath(context, refItem);
|
|
310
300
|
const shape = get(context, shapePath);
|
|
311
301
|
return shape ? { shape, path: shapePath } : undefined;
|
|
312
302
|
}
|
|
@@ -314,7 +304,7 @@ export function refItemToShapeWithPath(context, refItem) {
|
|
|
314
304
|
* Get a Shape schema referenced by a `RefItem`.
|
|
315
305
|
*/
|
|
316
306
|
export function refItemToShapeSchema(context, refItem) {
|
|
317
|
-
const shapePath = refItemToShapePath(refItem);
|
|
307
|
+
const shapePath = refItemToShapePath(context, refItem);
|
|
318
308
|
return get(context, [...shapePath, 'schema']);
|
|
319
309
|
}
|
|
320
310
|
/**
|
|
@@ -322,14 +312,14 @@ export function refItemToShapeSchema(context, refItem) {
|
|
|
322
312
|
*/
|
|
323
313
|
export function getRefShapeName(context, refSchema) {
|
|
324
314
|
const refItem = getRef(context, refSchema);
|
|
325
|
-
return refItem ? refItemToNamespacedShapeName(refItem) : undefined;
|
|
315
|
+
return refItem ? refItemToNamespacedShapeName(context, refItem) : undefined;
|
|
326
316
|
}
|
|
327
317
|
/**
|
|
328
318
|
* Sugar, for when you really just need a path...
|
|
329
319
|
*/
|
|
330
|
-
export function
|
|
320
|
+
export function refSchemaToShapeSchemaPath(context, refSchema) {
|
|
331
321
|
const refItem = getRef(context, refSchema);
|
|
332
|
-
return refItem ? [...refItemToShapePath(refItem), 'schema'] : undefined;
|
|
322
|
+
return refItem ? [...refItemToShapePath(context, refItem), 'schema'] : undefined;
|
|
333
323
|
}
|
|
334
324
|
/**
|
|
335
325
|
* Helper fn to omit `ref` props from the target schema, and then extend it with the source schema.
|
|
@@ -369,7 +359,8 @@ export function hasRef(schema) {
|
|
|
369
359
|
*/
|
|
370
360
|
export function hasResolvableRef(context, schema) {
|
|
371
361
|
if (isRefSchema(schema) || isRefSchemaLegacy(schema)) {
|
|
372
|
-
|
|
362
|
+
const ref = getRef(context, schema);
|
|
363
|
+
return Boolean(ref && refItemToShapeSchema(context, ref));
|
|
373
364
|
}
|
|
374
365
|
if (isAllOfSchema(schema)) {
|
|
375
366
|
return Boolean(schema.allOf.find((s) => hasResolvableRef(context, s)));
|
|
@@ -440,29 +431,28 @@ export function dereferenceObjectSchema(context, shapeOrFieldSchema, schemaPath
|
|
|
440
431
|
}
|
|
441
432
|
return schema;
|
|
442
433
|
}
|
|
443
|
-
function getNamespace(context,
|
|
444
|
-
return context.services?.[
|
|
434
|
+
function getNamespace(context, layerId) {
|
|
435
|
+
return context.services?.[layerId]?.namespace;
|
|
445
436
|
}
|
|
446
437
|
export function createGetNamespace(context) {
|
|
447
|
-
return (
|
|
438
|
+
return (layerId) => getNamespace(context, layerId);
|
|
448
439
|
}
|
|
449
440
|
export function parsePropertyRef(refStr) {
|
|
450
|
-
const [
|
|
441
|
+
const [layerId, coordinate] = splitRefExpression(refStr);
|
|
451
442
|
const coordinateParts = coordinate.split('.');
|
|
452
443
|
if (coordinateParts.length === 1) {
|
|
453
|
-
return {
|
|
444
|
+
return { layerId, shapeName: 'Query', propertyName: coordinateParts[0] };
|
|
454
445
|
}
|
|
455
446
|
if (coordinateParts.length === 2) {
|
|
456
447
|
return {
|
|
457
|
-
|
|
448
|
+
layerId,
|
|
458
449
|
shapeName: coordinateParts[0],
|
|
459
450
|
propertyName: coordinateParts[1]
|
|
460
451
|
};
|
|
461
452
|
}
|
|
462
453
|
}
|
|
463
|
-
export function serializePropertyRef({ shapeName, propertyName,
|
|
464
|
-
|
|
465
|
-
return serviceId === 'local' ? coordinate : `${serviceId}:${coordinate}`;
|
|
454
|
+
export function serializePropertyRef({ shapeName, propertyName, layerId }) {
|
|
455
|
+
return formatShapeRef(layerId, `${shapeName}.${propertyName}`);
|
|
466
456
|
}
|
|
467
457
|
export function normalizePropertyRef(refStr) {
|
|
468
458
|
const parsed = parsePropertyRef(refStr);
|
|
@@ -473,10 +463,10 @@ export function propertyRefToShapeRef(propertyRef) {
|
|
|
473
463
|
if (!parsed) {
|
|
474
464
|
throw new Error(`Invalid property ref "${propertyRef}`);
|
|
475
465
|
}
|
|
476
|
-
return formatShapeRef(parsed.
|
|
466
|
+
return formatShapeRef(parsed.layerId, parsed.shapeName);
|
|
477
467
|
}
|
|
478
|
-
export function formatShapeRef(
|
|
479
|
-
return `${
|
|
468
|
+
export function formatShapeRef(layerId, shapeName) {
|
|
469
|
+
return layerId === LOCAL_LAYER_ID ? shapeName : `${layerId}:${shapeName}`;
|
|
480
470
|
}
|
|
481
471
|
export function applyNamespace(namespace, name) {
|
|
482
472
|
return namespace ? `${namespace}_${name}` : name;
|
|
@@ -489,25 +479,9 @@ export function propertyRefItemToArgsPath(getNamespace, item) {
|
|
|
489
479
|
const path = propertyRefItemToPath(getNamespace, item);
|
|
490
480
|
return path.concat(path[0] === 'shapes' ? '@args' : 'args');
|
|
491
481
|
}
|
|
492
|
-
export function propertyRefItemToLocalName(getNamespace, item) {
|
|
493
|
-
const { shapeName, serviceId, propertyName } = item;
|
|
494
|
-
if (shapeName === 'Query' || shapeName === 'Mutation') {
|
|
495
|
-
const namespaced = applyNamespace(getNamespace(serviceId), propertyName);
|
|
496
|
-
return `${shapeName}.${namespaced}`;
|
|
497
|
-
}
|
|
498
|
-
return propertyName;
|
|
499
|
-
}
|
|
500
|
-
export function queryRefToLocalName(context, queryRef) {
|
|
501
|
-
const parsedQueryRef = parsePropertyRef(queryRef);
|
|
502
|
-
if (parsedQueryRef) {
|
|
503
|
-
return parsedQueryRef.serviceId === 'local'
|
|
504
|
-
? parsedQueryRef.propertyName
|
|
505
|
-
: propertyRefItemToLocalName(createGetNamespace(context), parsedQueryRef);
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
482
|
export function propertyRefItemToPath(getNamespace, item) {
|
|
509
|
-
const { shapeName,
|
|
510
|
-
const namespace = getNamespace(
|
|
483
|
+
const { shapeName, layerId, propertyName } = item;
|
|
484
|
+
const namespace = getNamespace(layerId);
|
|
511
485
|
if (shapeName === 'Query' || shapeName === 'Mutation') {
|
|
512
486
|
return [shapeName === 'Query' ? 'queries' : 'mutations', applyNamespace(namespace, propertyName)];
|
|
513
487
|
}
|
|
@@ -524,7 +498,7 @@ export function propertyRefToArgs(projectSchema, ref) {
|
|
|
524
498
|
* Get a ref to the given shape.
|
|
525
499
|
*/
|
|
526
500
|
export function normalizeRefExpression(context, refExpression) {
|
|
527
|
-
return
|
|
501
|
+
return serializeRef(parseRef(context, refExpression));
|
|
528
502
|
}
|
|
529
503
|
export function normalizeLocalRefString(ref) {
|
|
530
504
|
return ref.startsWith('local:') ? ref.substring(6) : ref;
|
|
@@ -588,38 +562,28 @@ export function ensureQuery(projectSchema, queryRef) {
|
|
|
588
562
|
return query;
|
|
589
563
|
}
|
|
590
564
|
export function normalizeRefs(projectSchema, property) {
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
}
|
|
608
|
-
// Convert $ref to @ref
|
|
609
|
-
const refItem = getRef(projectSchema, updatedProperty);
|
|
610
|
-
if (refItem && updatedProperty.$ref) {
|
|
611
|
-
updatedProperty = {
|
|
612
|
-
...omit(['$ref'], updatedProperty),
|
|
613
|
-
'@ref': refItemToAtRef(refItem)
|
|
614
|
-
};
|
|
615
|
-
}
|
|
616
|
-
return updatedProperty;
|
|
565
|
+
return deepCloneWith(property ?? projectSchema, (value, _key, _parent, clone) => {
|
|
566
|
+
if (isIterableObject(value)) {
|
|
567
|
+
const ref = getRef(projectSchema, value);
|
|
568
|
+
if (ref) {
|
|
569
|
+
const { $ref, '@output': output, '@input': input, ...newRefSchema } = value;
|
|
570
|
+
newRefSchema['@ref'] = serializeRef(ref);
|
|
571
|
+
if (output) {
|
|
572
|
+
newRefSchema['@output'] = clone(output, '@output', value);
|
|
573
|
+
}
|
|
574
|
+
if (input) {
|
|
575
|
+
newRefSchema['@input'] = clone(input, '@input', value);
|
|
576
|
+
}
|
|
577
|
+
return newRefSchema;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
});
|
|
617
581
|
}
|
|
618
582
|
/**
|
|
619
583
|
* Get a ShapeJSON from a RefItem, with the schema dereferenced.
|
|
620
584
|
*/
|
|
621
585
|
export function getReferencedShape(projectSchema, refItem, namespace) {
|
|
622
|
-
const shape = getShape(projectSchema, applyNamespace(namespace ?? getNamespace(projectSchema, refItem.
|
|
586
|
+
const shape = getShape(projectSchema, applyNamespace(namespace ?? getNamespace(projectSchema, refItem.layerId), refItem.shapeName));
|
|
623
587
|
if (shape) {
|
|
624
588
|
return {
|
|
625
589
|
...shape,
|
|
@@ -631,7 +595,7 @@ export function getReferencedShape(projectSchema, refItem, namespace) {
|
|
|
631
595
|
* Get a PropertySchema from a RefItem.
|
|
632
596
|
*/
|
|
633
597
|
export function getReferencedShapeProperty(projectSchema, refItem, namespace) {
|
|
634
|
-
const shape = getReferencedShape(projectSchema, refItem, namespace ?? getNamespace(projectSchema, refItem.
|
|
598
|
+
const shape = getReferencedShape(projectSchema, refItem, namespace ?? getNamespace(projectSchema, refItem.layerId));
|
|
635
599
|
if (shape && isObjectSchema(shape.schema)) {
|
|
636
600
|
return shape.schema.properties[refItem.propertyName];
|
|
637
601
|
}
|
package/dist/relationships.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export declare function getLegacyRelationship(projectSchema: ProjectSchemaJSON,
|
|
|
27
27
|
export declare function getRelationship(propertySchema: PropertySchema): Maybe<Relationship>;
|
|
28
28
|
export declare function findExistingRelationships(projectSchema: ProjectSchemaJSON, shapes: ShapeMap): Record<string, RelationshipEnv[]>;
|
|
29
29
|
/**
|
|
30
|
-
* Test whether two PropertySchemas have equal
|
|
30
|
+
* Test whether two PropertySchemas have equal relationships
|
|
31
31
|
*/
|
|
32
32
|
export declare function isEqualRelationship(a: PropertySchema, b: PropertySchema): boolean;
|
|
33
33
|
/**
|
package/dist/relationships.js
CHANGED
|
@@ -3,7 +3,7 @@ import camelCase from 'lodash/camelCase.js';
|
|
|
3
3
|
import find from 'lodash/find.js';
|
|
4
4
|
import uniq from 'lodash/uniq.js';
|
|
5
5
|
import { builtInShapes } from "./builtin-schema.js";
|
|
6
|
-
import { followRef, getRefShapeName } from "./refs.js";
|
|
6
|
+
import { followRef, getRefShapeName, getShapeByRef, shapeToRefString } from "./refs.js";
|
|
7
7
|
import { isModelShape, isObjectSchema, isPropertySchemaWithRelationship } from "./types/index.js";
|
|
8
8
|
import { isUnionSchema } from "./unions.js";
|
|
9
9
|
import { getShapeById } from "./util/shapes.js";
|
|
@@ -28,7 +28,7 @@ export function getRelationshipSchema(projectSchema, relationship) {
|
|
|
28
28
|
.map((shapeId) => {
|
|
29
29
|
const shape = getShapeById(projectSchema, shapeId) ?? find(builtInShapes, (shape) => shape.id === shapeId);
|
|
30
30
|
return (shape && {
|
|
31
|
-
'@ref':
|
|
31
|
+
'@ref': shapeToRefString(projectSchema, shape)
|
|
32
32
|
});
|
|
33
33
|
})
|
|
34
34
|
.filter(isDefined);
|
|
@@ -50,7 +50,7 @@ export function getRelationshipSchema(projectSchema, relationship) {
|
|
|
50
50
|
'@input': {
|
|
51
51
|
type: 'array',
|
|
52
52
|
items: {
|
|
53
|
-
'@ref': '
|
|
53
|
+
'@ref': 'TSRelationship'
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
};
|
|
@@ -59,7 +59,7 @@ export function getRelationshipSchema(projectSchema, relationship) {
|
|
|
59
59
|
...propertySchema,
|
|
60
60
|
...shapeRefsSchema,
|
|
61
61
|
'@input': {
|
|
62
|
-
'@ref': '
|
|
62
|
+
'@ref': 'TSRelationship'
|
|
63
63
|
}
|
|
64
64
|
};
|
|
65
65
|
}
|
|
@@ -81,25 +81,15 @@ export function getRelationshipShapeRefs(propertySchema) {
|
|
|
81
81
|
* Get a list of shapes given a property schema with a relationship resolver.
|
|
82
82
|
*/
|
|
83
83
|
export function getRelationshipShapes(shapes, refs) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const shapeName = ref.split(':')[1];
|
|
87
|
-
const shape = shapes[shapeName];
|
|
88
|
-
return shape ? shape : undefined;
|
|
89
|
-
})
|
|
90
|
-
.filter(isDefined);
|
|
84
|
+
const context = { shapes };
|
|
85
|
+
return refs.map((ref) => getShapeByRef(context, ref)).filter(isDefined);
|
|
91
86
|
}
|
|
92
87
|
/**
|
|
93
88
|
* Get a list of shape ids given a property schema with a relationship resolver.
|
|
94
89
|
*/
|
|
95
90
|
export function getRelationshipShapeIds(shapes, refs) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const shapeName = ref.split(':')[1];
|
|
99
|
-
const shape = shapes[shapeName];
|
|
100
|
-
return shape ? shape.id : undefined;
|
|
101
|
-
})
|
|
102
|
-
.filter(isDefined);
|
|
91
|
+
const context = { shapes };
|
|
92
|
+
return refs.map((ref) => getShapeByRef(context, ref)?.id).filter(isDefined);
|
|
103
93
|
}
|
|
104
94
|
/**
|
|
105
95
|
* Turn a Relationship into a LegacyRelationship object.
|
|
@@ -193,7 +183,7 @@ export function findExistingRelationships(projectSchema, shapes) {
|
|
|
193
183
|
return relationships;
|
|
194
184
|
}
|
|
195
185
|
/**
|
|
196
|
-
* Test whether two PropertySchemas have equal
|
|
186
|
+
* Test whether two PropertySchemas have equal relationships
|
|
197
187
|
*/
|
|
198
188
|
export function isEqualRelationship(a, b) {
|
|
199
189
|
const relationshipA = getRelationship(a);
|
|
@@ -236,23 +226,24 @@ export function addRelatedFields(projectSchema, allRelationships) {
|
|
|
236
226
|
const shape = getShapeById(projectSchema, shapeId);
|
|
237
227
|
if (shape && isObjectSchema(shape.schema)) {
|
|
238
228
|
const relatedShapeIds = getRelatedShapeIds(shapeRelationships);
|
|
239
|
-
const
|
|
240
|
-
if (
|
|
241
|
-
let
|
|
242
|
-
if (
|
|
229
|
+
const relatedShapeRefs = getShapes(projectSchema, relatedShapeIds).map((shape) => shapeToRefString(projectSchema, shape));
|
|
230
|
+
if (relatedShapeRefs.length) {
|
|
231
|
+
let shapeRef;
|
|
232
|
+
if (relatedShapeRefs.length === 1) {
|
|
243
233
|
// If only one back reference exists, _references is a regular shape
|
|
244
|
-
|
|
234
|
+
shapeRef = relatedShapeRefs[0];
|
|
245
235
|
}
|
|
246
236
|
else {
|
|
247
237
|
// If many back references exist, _references will be a union of referring shapes
|
|
248
|
-
shapeName = `${shape.name}Reference`;
|
|
238
|
+
const shapeName = `${shape.name}Reference`;
|
|
239
|
+
shapeRef = shapeName;
|
|
249
240
|
projectSchema.shapes[shapeName] = {
|
|
250
241
|
id: shapeName,
|
|
251
242
|
name: shapeName,
|
|
252
243
|
title: shapeName,
|
|
253
244
|
schema: {
|
|
254
|
-
oneOf:
|
|
255
|
-
'@ref':
|
|
245
|
+
oneOf: relatedShapeRefs.map((name) => ({
|
|
246
|
+
'@ref': name
|
|
256
247
|
}))
|
|
257
248
|
}
|
|
258
249
|
};
|
|
@@ -262,8 +253,8 @@ export function addRelatedFields(projectSchema, allRelationships) {
|
|
|
262
253
|
// It is for convenience.
|
|
263
254
|
if (shapeRelationships.some((rel) => rel.hasBackreference)) {
|
|
264
255
|
shape.schema.properties._references = {
|
|
265
|
-
'@args': `TSListArgs
|
|
266
|
-
'@ref': `PaginatedList
|
|
256
|
+
'@args': `TSListArgs<${shapeRef}>`,
|
|
257
|
+
'@ref': `PaginatedList<${shapeRef}>`,
|
|
267
258
|
'@resolver': {
|
|
268
259
|
name: 'shapedb:list',
|
|
269
260
|
service: 'shapedb',
|
|
@@ -286,8 +277,8 @@ export function addRelatedFields(projectSchema, allRelationships) {
|
|
|
286
277
|
const relatedFieldName = relatedName ? relatedName : `${camelCase(relatedShape.name)}Set`;
|
|
287
278
|
const filterField = relatedName ? relationship.path.concat('_id').join('.') : '_references';
|
|
288
279
|
shape.schema.properties[relatedFieldName] = {
|
|
289
|
-
'@args': `TSListArgs
|
|
290
|
-
'@ref': `PaginatedList
|
|
280
|
+
'@args': `TSListArgs<${relatedShape.name}>`,
|
|
281
|
+
'@ref': `PaginatedList<${relatedShape.name}>`,
|
|
291
282
|
'@resolver': {
|
|
292
283
|
name: 'shapedb:list',
|
|
293
284
|
service: 'shapedb',
|