@takeshape/schema 8.35.2 → 8.38.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/es/flatten-templates.js +26 -0
- package/es/index.js +2 -1
- package/es/layers/layers.js +1 -1
- package/es/layers/refs.js +1 -1
- package/es/refs.js +74 -2
- package/es/schema-util.js +28 -17
- package/es/template-shapes/index.js +35 -0
- package/es/template-shapes/templates.js +379 -0
- package/es/template-shapes/types.js +1 -0
- package/es/template-shapes/where.js +501 -0
- package/es/validate.js +2 -2
- package/examples/v4_0_0/rick-and-morty-notes/{character-notes.layer.json → layers/character-notes.json} +0 -0
- package/examples/v4_0_0/rick-and-morty-notes/{rick-and-morty.layer.json → layers/rick-and-morty.json} +0 -0
- package/examples/v4_0_0/rick-and-morty-notes/{takeshape-assets.layer.json → layers/takeshape-assets.json} +0 -0
- package/examples/v4_0_0/rick-and-morty-notes/{takeshape-builtins.layer.json → layers/takeshape-builtins.json} +0 -0
- package/examples/v4_0_0/rick-and-morty-notes/{takeshape-static-sites.layer.json → layers/takeshape-static-sites.json} +0 -0
- package/examples/v4_0_0/shopify-lookbook/{andrews-store.layer.json → layers/andrews-store.json} +0 -0
- package/examples/v4_0_0/shopify-lookbook/{lookbook.layer.json → layers/lookbook.json} +0 -0
- package/examples/v4_0_0/shopify-lookbook/{takeshape-assets.layer.json → layers/takeshape-assets.json} +0 -0
- package/examples/v4_0_0/shopify-lookbook/{takeshape-builtins.layer.json → layers/takeshape-builtins.json} +0 -0
- package/lib/flatten-templates.d.ts +3 -0
- package/lib/flatten-templates.d.ts.map +1 -0
- package/lib/flatten-templates.js +39 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +14 -0
- package/lib/layers/layers.js +3 -3
- package/lib/layers/refs.js +2 -2
- package/lib/refs.d.ts +26 -1
- package/lib/refs.d.ts.map +1 -1
- package/lib/refs.js +94 -11
- package/lib/schema-util.d.ts +7 -6
- package/lib/schema-util.d.ts.map +1 -1
- package/lib/schema-util.js +41 -29
- package/lib/template-shapes/index.d.ts +8 -0
- package/lib/template-shapes/index.d.ts.map +1 -0
- package/lib/template-shapes/index.js +46 -0
- package/lib/template-shapes/templates.d.ts +29 -0
- package/lib/template-shapes/templates.d.ts.map +1 -0
- package/lib/template-shapes/templates.js +427 -0
- package/lib/template-shapes/types.d.ts +10 -0
- package/lib/template-shapes/types.d.ts.map +1 -0
- package/lib/template-shapes/types.js +5 -0
- package/lib/template-shapes/where.d.ts +39 -0
- package/lib/template-shapes/where.d.ts.map +1 -0
- package/lib/template-shapes/where.js +534 -0
- package/lib/validate.js +1 -1
- package/package.json +4 -4
- package/es/template-shapes.js +0 -79
- package/lib/template-shapes.d.ts +0 -32
- package/lib/template-shapes.d.ts.map +0 -1
- package/lib/template-shapes.js +0 -101
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.fieldTypeComparison = exports.exceededRelationshipDepth = exports.comparatorDescriptions = exports.booleanOperators = exports.boolOpDescriptionMap = exports.MAX_RELATIONSHIP_DEPTH = void 0;
|
|
7
|
+
exports.getFieldTypeComparison = getFieldTypeComparison;
|
|
8
|
+
exports.getFields = getFields;
|
|
9
|
+
exports.getPropertyComparisonType = getPropertyComparisonType;
|
|
10
|
+
exports.getWhereSearchArg = getWhereSearchArg;
|
|
11
|
+
exports.getWhereShape = getWhereShape;
|
|
12
|
+
|
|
13
|
+
var _util = require("@takeshape/util");
|
|
14
|
+
|
|
15
|
+
var _isEqual = _interopRequireDefault(require("lodash/isEqual"));
|
|
16
|
+
|
|
17
|
+
var _get = _interopRequireDefault(require("lodash/get"));
|
|
18
|
+
|
|
19
|
+
var _unset = _interopRequireDefault(require("lodash/unset"));
|
|
20
|
+
|
|
21
|
+
var _isFunction = _interopRequireDefault(require("lodash/isFunction"));
|
|
22
|
+
|
|
23
|
+
var _schemaUtil = require("../schema-util");
|
|
24
|
+
|
|
25
|
+
var _apiVersion = require("../api-version");
|
|
26
|
+
|
|
27
|
+
var _refs = require("../refs");
|
|
28
|
+
|
|
29
|
+
var _unions = require("../unions");
|
|
30
|
+
|
|
31
|
+
var _types = require("../types");
|
|
32
|
+
|
|
33
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
34
|
+
|
|
35
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
36
|
+
|
|
37
|
+
const MAX_RELATIONSHIP_DEPTH = 1;
|
|
38
|
+
exports.MAX_RELATIONSHIP_DEPTH = MAX_RELATIONSHIP_DEPTH;
|
|
39
|
+
|
|
40
|
+
const exceededRelationshipDepth = (depth = 0) => depth >= MAX_RELATIONSHIP_DEPTH;
|
|
41
|
+
|
|
42
|
+
exports.exceededRelationshipDepth = exceededRelationshipDepth;
|
|
43
|
+
|
|
44
|
+
class ShapeCache {
|
|
45
|
+
constructor() {
|
|
46
|
+
_defineProperty(this, "thunks", new Map());
|
|
47
|
+
|
|
48
|
+
_defineProperty(this, "unresolved", new Set());
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
has(shapeName) {
|
|
52
|
+
return this.thunks.has(shapeName);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
set(shapeName, thunk) {
|
|
56
|
+
this.thunks.set(shapeName, thunk);
|
|
57
|
+
|
|
58
|
+
if ((0, _isFunction.default)(thunk)) {
|
|
59
|
+
this.unresolved.add(shapeName);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
resolveAll() {
|
|
64
|
+
while (this.unresolved.size) {
|
|
65
|
+
const shapeName = this.unresolved.values().next().value;
|
|
66
|
+
const thunk = this.thunks.get(shapeName);
|
|
67
|
+
|
|
68
|
+
if ((0, _isFunction.default)(thunk)) {
|
|
69
|
+
this.thunks.set(shapeName, thunk());
|
|
70
|
+
this.unresolved.delete(shapeName);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const result = {};
|
|
75
|
+
|
|
76
|
+
for (const [shapeName, shape] of this.thunks) {
|
|
77
|
+
result[shapeName] = shape;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const fieldTypeComparison = {
|
|
86
|
+
id: {
|
|
87
|
+
comparators: ['eq', 'in'],
|
|
88
|
+
type: 'string'
|
|
89
|
+
},
|
|
90
|
+
boolean: {
|
|
91
|
+
comparators: ['eq'],
|
|
92
|
+
type: 'boolean'
|
|
93
|
+
},
|
|
94
|
+
string: {
|
|
95
|
+
comparators: ['eq', 'in', 'match', 'regexp'],
|
|
96
|
+
type: 'string'
|
|
97
|
+
},
|
|
98
|
+
date: {
|
|
99
|
+
comparators: ['eq', 'lt', 'lte', 'gt', 'gte'],
|
|
100
|
+
type: 'string'
|
|
101
|
+
},
|
|
102
|
+
number: {
|
|
103
|
+
comparators: ['eq', 'lt', 'lte', 'gt', 'gte', 'in'],
|
|
104
|
+
type: 'number'
|
|
105
|
+
},
|
|
106
|
+
integer: {
|
|
107
|
+
comparators: ['eq', 'lt', 'lte', 'gt', 'gte', 'in'],
|
|
108
|
+
type: 'integer'
|
|
109
|
+
},
|
|
110
|
+
workflow: {
|
|
111
|
+
comparators: ['eq', 'lt', 'lte', 'gt', 'gte', 'in'],
|
|
112
|
+
type: 'string'
|
|
113
|
+
},
|
|
114
|
+
draftjs: {
|
|
115
|
+
comparators: ['match'],
|
|
116
|
+
type: 'string'
|
|
117
|
+
},
|
|
118
|
+
mdx: {
|
|
119
|
+
comparators: ['match'],
|
|
120
|
+
type: 'string'
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
exports.fieldTypeComparison = fieldTypeComparison;
|
|
124
|
+
const comparatorDescriptions = {
|
|
125
|
+
eq: 'Exact match',
|
|
126
|
+
gt: 'Greater than',
|
|
127
|
+
gte: 'Greater than or equal',
|
|
128
|
+
lt: 'Less than',
|
|
129
|
+
lte: 'Less than or equal',
|
|
130
|
+
in: 'Array of possible exact match values.',
|
|
131
|
+
match: 'Full text searching with fuzzy matching.',
|
|
132
|
+
regexp: 'Regular expression string matching. Use of * wildcards could degrade performance.'
|
|
133
|
+
};
|
|
134
|
+
exports.comparatorDescriptions = comparatorDescriptions;
|
|
135
|
+
const booleanOperators = ['AND', 'OR', 'NOT'];
|
|
136
|
+
exports.booleanOperators = booleanOperators;
|
|
137
|
+
const boolOpDescriptionMap = {
|
|
138
|
+
AND: 'AND takes an array of conditions that must appear in the matching results. Nested boolean operators can be used to create complex filters.',
|
|
139
|
+
OR: 'OR takes an array of conditions that should appear in the matching results. Nested boolean operators can be used to create complex filters.',
|
|
140
|
+
NOT: 'NOT takes a single condition that must not appear in the matching results.'
|
|
141
|
+
};
|
|
142
|
+
exports.boolOpDescriptionMap = boolOpDescriptionMap;
|
|
143
|
+
|
|
144
|
+
const getConflictingProperties = (projectSchema, shapes) => {
|
|
145
|
+
let conflicts = [];
|
|
146
|
+
const allProps = {};
|
|
147
|
+
|
|
148
|
+
for (const shape of Object.values(shapes)) {
|
|
149
|
+
const shapeConflicts = (0, _schemaUtil.createSchemaPropertyList)(projectSchema, shape.schema).filterBy(([name, prop]) => name in allProps && (allProps[name].type !== prop.type || !(0, _isEqual.default)((0, _get.default)(allProps, [name, '@relationship', 'shapeIds']), (0, _get.default)(prop, ['@relationship', 'shapeIds'])))).getNames();
|
|
150
|
+
conflicts = conflicts.concat(shapeConflicts);
|
|
151
|
+
|
|
152
|
+
if ((0, _types.isObjectSchema)(shape.schema)) {
|
|
153
|
+
Object.assign(allProps, shape.schema.properties);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return conflicts;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
function getFieldTypeComparison(fieldType) {
|
|
161
|
+
const comparison = fieldTypeComparison[fieldType];
|
|
162
|
+
|
|
163
|
+
if (!comparison) {
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const {
|
|
168
|
+
comparators,
|
|
169
|
+
type
|
|
170
|
+
} = comparison;
|
|
171
|
+
const result = {};
|
|
172
|
+
|
|
173
|
+
for (const op of comparators) {
|
|
174
|
+
const description = comparatorDescriptions[op];
|
|
175
|
+
result[op] = op === 'in' ? {
|
|
176
|
+
type: 'array',
|
|
177
|
+
items: {
|
|
178
|
+
type
|
|
179
|
+
},
|
|
180
|
+
description
|
|
181
|
+
} : {
|
|
182
|
+
description,
|
|
183
|
+
type
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return result;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function isId(name) {
|
|
191
|
+
return name === '_id' || name === '_contentTypeId' || name === '_shapeId';
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function isNonRelationshipRef(prop) {
|
|
195
|
+
return Boolean((0, _refs.hasRefProperty)(prop) && !prop['@relationship']);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function getPropType(projectSchema, name, prop) {
|
|
199
|
+
if (prop['@workflow']) {
|
|
200
|
+
return 'workflow';
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (prop['@tag'] === 'draftjs') {
|
|
204
|
+
return 'draftjs';
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (prop['@tag'] === 'mdx') {
|
|
208
|
+
return 'mdx';
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (prop.format === 'date-time') {
|
|
212
|
+
return 'date';
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (isId(name)) {
|
|
216
|
+
return 'id';
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (isNonRelationshipRef(prop)) {
|
|
220
|
+
const followed = (0, _refs.followRef)(projectSchema, prop);
|
|
221
|
+
|
|
222
|
+
if (followed.enum) {
|
|
223
|
+
return 'string';
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return 'object';
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return prop.type;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function getRelatedShapeNames(prop, projectSchema) {
|
|
233
|
+
var _prop$Relationship;
|
|
234
|
+
|
|
235
|
+
const names = (_prop$Relationship = prop['@relationship']) === null || _prop$Relationship === void 0 ? void 0 : _prop$Relationship.shapeIds.map(id => {
|
|
236
|
+
const shape = (0, _schemaUtil.getShapeById)(projectSchema, id);
|
|
237
|
+
return (0, _util.pascalCase)(shape ? shape.name : '');
|
|
238
|
+
}).sort().join('');
|
|
239
|
+
|
|
240
|
+
if (!names) {
|
|
241
|
+
throw new Error(`Relationship property ${prop.title} is missing related shapes`);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return names;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function joinShapeNames(shapes) {
|
|
248
|
+
return shapes.sort().join('');
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function getTypeName(name, prop, shapeName, context) {
|
|
252
|
+
const {
|
|
253
|
+
projectSchema,
|
|
254
|
+
relationshipDepth,
|
|
255
|
+
conflictingProperties
|
|
256
|
+
} = context;
|
|
257
|
+
let type = getPropType(projectSchema, name, prop);
|
|
258
|
+
|
|
259
|
+
if (isId(name)) {
|
|
260
|
+
return `TSWhereID`;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (prop['@relationship']) {
|
|
264
|
+
const shapeNames = getRelatedShapeNames(prop, projectSchema);
|
|
265
|
+
return `TSWhere${shapeNames}Relationship`;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if ((0, _unions.isUnionSchema)(prop)) {
|
|
269
|
+
if (prop.oneOf.length > 1) {
|
|
270
|
+
const shapeNames = joinShapeNames((0, _unions.enumerateOneOfKeys)(projectSchema, prop.oneOf).map(child => child.shapeName));
|
|
271
|
+
return `TSWhere${shapeNames}Union`;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
type = 'object';
|
|
275
|
+
prop = prop.oneOf[0];
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (type === 'object' || type === 'array') {
|
|
279
|
+
const prefix = `TS${relationshipDepth >= MAX_RELATIONSHIP_DEPTH ? 'Shallow' : ''}Where`;
|
|
280
|
+
const fieldName = `${conflictingProperties.includes(name) ? '_' : ''}${(0, _util.pascalCase)(name)}`;
|
|
281
|
+
const refItem = (0, _refs.getRefOrItemsRef)(projectSchema, prop);
|
|
282
|
+
const suffix = refItem ? (0, _refs.refItemToShapeName)(refItem) : `${shapeName}${fieldName}`;
|
|
283
|
+
return `${prefix}${suffix}`;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return `TSWhere${(0, _util.pascalCase)(type)}`;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function skipField(name, prop, projectSchema, exceededRelationshipDepth) {
|
|
290
|
+
return Boolean(prop['@user'] || prop['@sensitive'] || prop['@resolver'] || prop['@relationship'] && exceededRelationshipDepth || (name === '_enabled' || name === '_enabledAt') && (0, _apiVersion.workflowsEnabled)(projectSchema.apiVersion));
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function getFields(typeName, shapes, context) {
|
|
294
|
+
const {
|
|
295
|
+
shapeCache,
|
|
296
|
+
relationshipDepth,
|
|
297
|
+
booleanOperators,
|
|
298
|
+
projectSchema
|
|
299
|
+
} = context;
|
|
300
|
+
const result = {};
|
|
301
|
+
const tooDeep = exceededRelationshipDepth(relationshipDepth);
|
|
302
|
+
|
|
303
|
+
for (const shape of shapes) {
|
|
304
|
+
const nodes = (0, _schemaUtil.createSchemaPropertyList)(projectSchema, shape.schema).filterBy(([name, property]) => !skipField(name, property, projectSchema, tooDeep)).getNodes();
|
|
305
|
+
|
|
306
|
+
for (const [name, property] of nodes) {
|
|
307
|
+
Object.assign(result, getPropertyComparisonType(name, property, shape.name, context));
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return tooDeep || booleanOperators === false ? result : Object.assign(result, getBooleanOperatorTypes(result, typeName, shapeCache));
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function getBooleanOperatorTypes(fields, typeName, shapeCache) {
|
|
315
|
+
const result = {};
|
|
316
|
+
|
|
317
|
+
for (const op of booleanOperators) {
|
|
318
|
+
const name = `${typeName}${(0, _util.pascalCase)(op)}Operator`;
|
|
319
|
+
|
|
320
|
+
if (!shapeCache.has(name)) {
|
|
321
|
+
shapeCache.set(name, () => (0, _schemaUtil.createShape)(name, {
|
|
322
|
+
type: 'object',
|
|
323
|
+
properties: { ...fields,
|
|
324
|
+
...(op !== 'NOT' && getBooleanOperatorTypes(fields, typeName, shapeCache))
|
|
325
|
+
}
|
|
326
|
+
}, {
|
|
327
|
+
description: boolOpDescriptionMap[op]
|
|
328
|
+
}));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const refSchema = {
|
|
332
|
+
'@ref': `local:${name}`
|
|
333
|
+
};
|
|
334
|
+
result[op] = op === 'NOT' ? refSchema : {
|
|
335
|
+
type: 'array',
|
|
336
|
+
items: refSchema
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
return result;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function getPropertyComparisonType(name, prop, shapeName, context) {
|
|
344
|
+
const {
|
|
345
|
+
shapeCache,
|
|
346
|
+
projectSchema,
|
|
347
|
+
relationshipDepth,
|
|
348
|
+
conflictingProperties
|
|
349
|
+
} = context;
|
|
350
|
+
|
|
351
|
+
if (skipField(name, prop, projectSchema, exceededRelationshipDepth(relationshipDepth))) {
|
|
352
|
+
return undefined;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const fieldType = getPropType(projectSchema, name, prop) ?? 'string';
|
|
356
|
+
const typeName = getTypeName(name, prop, shapeName, context);
|
|
357
|
+
|
|
358
|
+
if ((0, _refs.hasRefProperty)(prop.items ?? prop)) {
|
|
359
|
+
if (!(0, _refs.hasResolvableRef)(projectSchema, prop.items ?? prop)) {
|
|
360
|
+
return undefined;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (prop.items) {
|
|
364
|
+
prop = { ...prop,
|
|
365
|
+
items: (0, _refs.followRef)(projectSchema, prop.items)
|
|
366
|
+
};
|
|
367
|
+
} else {
|
|
368
|
+
prop = (0, _refs.followRef)(projectSchema, prop);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (!shapeCache.has(typeName)) {
|
|
373
|
+
shapeCache.set(typeName, () => {
|
|
374
|
+
var _prop$items;
|
|
375
|
+
|
|
376
|
+
let props;
|
|
377
|
+
const propOrItems = prop.items ?? prop;
|
|
378
|
+
|
|
379
|
+
if (isId(name)) {
|
|
380
|
+
props = getFieldTypeComparison('id');
|
|
381
|
+
} else if (prop['@relationship']) {
|
|
382
|
+
const shapes = prop['@relationship'].shapeIds.map(id => (0, _schemaUtil.getShapeById)(projectSchema, id)).filter(_util.isDefined);
|
|
383
|
+
props = getFields(typeName, shapes, { ...context,
|
|
384
|
+
conflictingProperties: getConflictingProperties(context.projectSchema, shapes),
|
|
385
|
+
relationshipDepth: relationshipDepth + 1
|
|
386
|
+
});
|
|
387
|
+
} else if ((0, _unions.isUnionSchema)(propOrItems)) {
|
|
388
|
+
const shapes = (0, _unions.enumerateOneOfKeys)(projectSchema, propOrItems.oneOf).map(option => projectSchema.shapes[option.shapeName]);
|
|
389
|
+
props = getFields(typeName, shapes, { ...context,
|
|
390
|
+
conflictingProperties: getConflictingProperties(context.projectSchema, shapes),
|
|
391
|
+
relationshipDepth,
|
|
392
|
+
booleanOperators: false
|
|
393
|
+
});
|
|
394
|
+
} else if (fieldType === 'object' || fieldType === 'array' && ((_prop$items = prop.items) === null || _prop$items === void 0 ? void 0 : _prop$items.type) === 'object') {
|
|
395
|
+
var _prop$items2;
|
|
396
|
+
|
|
397
|
+
const properties = ((_prop$items2 = prop.items) === null || _prop$items2 === void 0 ? void 0 : _prop$items2.properties) ?? prop.properties;
|
|
398
|
+
|
|
399
|
+
if (properties) {
|
|
400
|
+
for (const propName of Object.keys(properties)) {
|
|
401
|
+
props = { ...props,
|
|
402
|
+
...getPropertyComparisonType(propName, properties[propName], shapeName, context)
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
} else {
|
|
407
|
+
var _prop$items3;
|
|
408
|
+
|
|
409
|
+
// Treat non-object arrays as their base type
|
|
410
|
+
let type;
|
|
411
|
+
|
|
412
|
+
if (typeof ((_prop$items3 = prop.items) === null || _prop$items3 === void 0 ? void 0 : _prop$items3.type) === 'string') {
|
|
413
|
+
type = prop.items.type;
|
|
414
|
+
} else {
|
|
415
|
+
type = fieldType;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
props = getFieldTypeComparison(type);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
return (0, _schemaUtil.createShape)(typeName, {
|
|
422
|
+
type: 'object',
|
|
423
|
+
properties: props ?? {}
|
|
424
|
+
});
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if (shapeCache.has(typeName)) {
|
|
429
|
+
const fieldName = `${conflictingProperties.includes(name) ? `${shapeName}_` : ''}${name}`;
|
|
430
|
+
return {
|
|
431
|
+
[fieldName]: {
|
|
432
|
+
'@ref': `local:${typeName}`
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
function findEmpty(shapes) {
|
|
439
|
+
const empty = new Set();
|
|
440
|
+
|
|
441
|
+
for (const [shapeName, shape] of Object.entries(shapes)) {
|
|
442
|
+
if ((0, _types.isObjectSchema)(shape.schema) && Object.keys(shape.schema.properties).length === 0) {
|
|
443
|
+
empty.add(shapeName);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
return empty;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function getRefSummary(shapes) {
|
|
451
|
+
const result = {};
|
|
452
|
+
|
|
453
|
+
for (const ref of (0, _schemaUtil.getAllRefsInShapes)({
|
|
454
|
+
shapes,
|
|
455
|
+
services: {}
|
|
456
|
+
})) {
|
|
457
|
+
const path = ref.path.slice(1, ref.path.length - 1);
|
|
458
|
+
|
|
459
|
+
if (result[ref.typeName]) {
|
|
460
|
+
result[ref.typeName].push(path);
|
|
461
|
+
} else {
|
|
462
|
+
result[ref.typeName] = [path];
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return result;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
function pruneEmpty(shapes) {
|
|
470
|
+
let toPrune = findEmpty(shapes);
|
|
471
|
+
|
|
472
|
+
if (toPrune.size) {
|
|
473
|
+
const refSummary = getRefSummary(shapes);
|
|
474
|
+
|
|
475
|
+
while (toPrune.size) {
|
|
476
|
+
for (const shapeName of toPrune) {
|
|
477
|
+
(0, _unset.default)(shapes, shapeName);
|
|
478
|
+
|
|
479
|
+
for (const path of refSummary[shapeName] ?? []) {
|
|
480
|
+
(0, _unset.default)(shapes, path);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
toPrune = findEmpty(shapes);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
return shapes;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function getWhereShape(projectSchema, shapes) {
|
|
492
|
+
const isManyContentTypes = shapes.length > 1;
|
|
493
|
+
const shapeName = isManyContentTypes ? 'TSWhereInput' : `TSWhere${(0, _util.pascalCase)(shapes[0].name)}Input`;
|
|
494
|
+
const shapeCache = new ShapeCache();
|
|
495
|
+
const conflictingProperties = getConflictingProperties(projectSchema, shapes);
|
|
496
|
+
const fields = getFields(shapeName, shapes, {
|
|
497
|
+
projectSchema,
|
|
498
|
+
shapeCache,
|
|
499
|
+
conflictingProperties,
|
|
500
|
+
relationshipDepth: 0
|
|
501
|
+
});
|
|
502
|
+
return {
|
|
503
|
+
shapeName,
|
|
504
|
+
dependencies: pruneEmpty({
|
|
505
|
+
[shapeName]: (0, _schemaUtil.createShape)(shapeName, {
|
|
506
|
+
type: 'object',
|
|
507
|
+
properties: { ...fields,
|
|
508
|
+
...(isManyContentTypes && getBooleanOperatorTypes(fields, shapeName, shapeCache))
|
|
509
|
+
}
|
|
510
|
+
}),
|
|
511
|
+
...shapeCache.resolveAll()
|
|
512
|
+
})
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
function getWhereSearchArg(projectSchema, shapes) {
|
|
517
|
+
const {
|
|
518
|
+
shapeName,
|
|
519
|
+
dependencies
|
|
520
|
+
} = getWhereShape(projectSchema, shapes.filter(s => s.model !== undefined || (0, _schemaUtil.isIndexedRemoteShape)(projectSchema, s)));
|
|
521
|
+
const schema = {
|
|
522
|
+
type: 'object',
|
|
523
|
+
properties: {
|
|
524
|
+
where: {
|
|
525
|
+
'@ref': `local:${shapeName}`,
|
|
526
|
+
description: 'The where clause uses the boolean AND, OR, and NOT parameters to construct complex filters based on the values of your fields. It applies an implicit AND to all the top-level keys. To avoid this, use a single OR or NOT key as the only top-level key.'
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
return {
|
|
531
|
+
schema,
|
|
532
|
+
dependencies
|
|
533
|
+
};
|
|
534
|
+
}
|
package/lib/validate.js
CHANGED
|
@@ -271,7 +271,7 @@ function validateQueryConfig(projectSchema, validReturnShapes, query, operation,
|
|
|
271
271
|
const {
|
|
272
272
|
template,
|
|
273
273
|
shapeName
|
|
274
|
-
} = (0,
|
|
274
|
+
} = (0, _refs.parseReturnShape)(projectSchema, query.shape);
|
|
275
275
|
|
|
276
276
|
if (template && !(0, _templateShapes.isValidTemplate)(template)) {
|
|
277
277
|
errors.push({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@takeshape/schema",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.38.0",
|
|
4
4
|
"description": "TakeShape Schema",
|
|
5
5
|
"homepage": "https://www.takeshape.io",
|
|
6
6
|
"repository": {
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
"examples"
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@takeshape/errors": "8.
|
|
25
|
-
"@takeshape/json-schema": "8.
|
|
26
|
-
"@takeshape/util": "8.
|
|
24
|
+
"@takeshape/errors": "8.38.0",
|
|
25
|
+
"@takeshape/json-schema": "8.38.0",
|
|
26
|
+
"@takeshape/util": "8.38.0",
|
|
27
27
|
"ajv": "^7.0.4",
|
|
28
28
|
"ajv-formats": "^1.5.1",
|
|
29
29
|
"lodash": "^4.17.20",
|
package/es/template-shapes.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { isRefSchema } from './types/utils';
|
|
2
|
-
import { getRef, refExpressionToRefItem, refItemToShapeName } from './refs';
|
|
3
|
-
export const knownTemplateShapes = new Set(['TSGetArgs', 'TSGetSingletonArgs', 'PaginatedList', 'TSListArgs', 'CreateArgs', 'UpdateArgs', 'DuplicateArgs', 'DeleteArgs', 'CreateResult', 'UpdateResult', 'DuplicateResult', 'DeleteResult']);
|
|
4
|
-
/**
|
|
5
|
-
* Check if a string is a known template such as `PaginatedList`
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export function isValidTemplate(template) {
|
|
9
|
-
return knownTemplateShapes.has(template);
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Parse a template like `PaginatedList<Post>` and return both the template and the shape name.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
export function parseTemplateShape(shape) {
|
|
16
|
-
const parts = shape.split('<');
|
|
17
|
-
|
|
18
|
-
if (parts.length > 1 && isValidTemplate(parts[0])) {
|
|
19
|
-
return {
|
|
20
|
-
shapeName: parts[1].replace(/(<|>)/, ''),
|
|
21
|
-
template: parts[0]
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return {
|
|
26
|
-
shapeName: parts[0],
|
|
27
|
-
template: undefined
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
export function parseReturnShape(projectSchema, shape) {
|
|
31
|
-
if (typeof shape === 'object') {
|
|
32
|
-
if (isRefSchema(shape.items)) {
|
|
33
|
-
const ref = getRef(projectSchema, shape.items);
|
|
34
|
-
|
|
35
|
-
if (!ref) {
|
|
36
|
-
throw new Error(`Could not parse ${JSON.stringify(shape.items)}: invalid ref`);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return {
|
|
40
|
-
isArray: true,
|
|
41
|
-
ref,
|
|
42
|
-
shapeName: refItemToShapeName(ref)
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (typeof shape.items.type !== 'string') {
|
|
47
|
-
throw new Error(`Could not parse ${JSON.stringify(shape.items)}: invalid type`);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return {
|
|
51
|
-
isArray: true,
|
|
52
|
-
shapeName: shape.items.type
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const ref = refExpressionToRefItem(projectSchema, shape);
|
|
57
|
-
const shapeName = refItemToShapeName(ref);
|
|
58
|
-
return {
|
|
59
|
-
isArray: false,
|
|
60
|
-
shapeName,
|
|
61
|
-
ref,
|
|
62
|
-
template: ref.template
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Create a template string like `PaginatedList<Post>` from a template and shape name.
|
|
67
|
-
*/
|
|
68
|
-
|
|
69
|
-
export function createTemplateShapeName(template, shapeName) {
|
|
70
|
-
return `${template}<${shapeName}>`;
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* If the string is a template like `PaginatedList<Post>`, return the shape name,
|
|
74
|
-
* in this case `Post`. Otherwise return the input.
|
|
75
|
-
*/
|
|
76
|
-
|
|
77
|
-
export const untemplate = input => {
|
|
78
|
-
return parseTemplateShape(input).shapeName;
|
|
79
|
-
};
|
package/lib/template-shapes.d.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type { ReturnShape } from './project-schema';
|
|
2
|
-
import type { ProjectSchemaV3X } from './types/types';
|
|
3
|
-
import { RefItem } from './refs';
|
|
4
|
-
export declare const knownTemplateShapes: Set<string>;
|
|
5
|
-
/**
|
|
6
|
-
* Check if a string is a known template such as `PaginatedList`
|
|
7
|
-
*/
|
|
8
|
-
export declare function isValidTemplate(template: string): boolean;
|
|
9
|
-
/**
|
|
10
|
-
* Parse a template like `PaginatedList<Post>` and return both the template and the shape name.
|
|
11
|
-
*/
|
|
12
|
-
export declare function parseTemplateShape(shape: string): {
|
|
13
|
-
template: string | undefined;
|
|
14
|
-
shapeName: string;
|
|
15
|
-
};
|
|
16
|
-
export interface ParsedReturnShape {
|
|
17
|
-
isArray: boolean;
|
|
18
|
-
template?: string;
|
|
19
|
-
shapeName: string;
|
|
20
|
-
ref?: RefItem;
|
|
21
|
-
}
|
|
22
|
-
export declare function parseReturnShape(projectSchema: ProjectSchemaV3X, shape: ReturnShape): ParsedReturnShape;
|
|
23
|
-
/**
|
|
24
|
-
* Create a template string like `PaginatedList<Post>` from a template and shape name.
|
|
25
|
-
*/
|
|
26
|
-
export declare function createTemplateShapeName(template: string, shapeName: string): string;
|
|
27
|
-
/**
|
|
28
|
-
* If the string is a template like `PaginatedList<Post>`, return the shape name,
|
|
29
|
-
* in this case `Post`. Otherwise return the input.
|
|
30
|
-
*/
|
|
31
|
-
export declare const untemplate: (input: string) => string;
|
|
32
|
-
//# sourceMappingURL=template-shapes.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"template-shapes.d.ts","sourceRoot":"","sources":["../../src/template-shapes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,eAAe,CAAC;AAEpD,OAAO,EAAiC,OAAO,EAAqB,MAAM,QAAQ,CAAC;AAEnF,eAAO,MAAM,mBAAmB,aAa9B,CAAC;AAEH;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG;IAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAC,CAOnG;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,gBAAgB,EAAE,KAAK,EAAE,WAAW,GAAG,iBAAiB,CAqBvG;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEnF;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,UAAW,MAAM,WAEvC,CAAC"}
|