@takeshape/schema 8.145.1 → 8.150.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.
Files changed (125) hide show
  1. package/dist/builtin-schema.d.ts.map +1 -1
  2. package/dist/builtin-schema.js +17 -0
  3. package/dist/get-is-leaf.d.ts +1 -1
  4. package/dist/get-is-leaf.d.ts.map +1 -1
  5. package/dist/get-is-leaf.js +3 -1
  6. package/dist/migration/index.d.ts +1 -0
  7. package/dist/migration/index.d.ts.map +1 -1
  8. package/dist/migration/index.js +4 -1
  9. package/dist/migration/to/v3.0.0.d.ts.map +1 -1
  10. package/dist/migration/to/v3.18.0.d.ts +5 -0
  11. package/dist/migration/to/v3.18.0.d.ts.map +1 -0
  12. package/dist/migration/to/v3.18.0.js +85 -0
  13. package/dist/mocks.d.ts.map +1 -1
  14. package/dist/mocks.js +4 -2
  15. package/dist/project-schema/index.d.ts +4 -1
  16. package/dist/project-schema/index.d.ts.map +1 -1
  17. package/dist/project-schema/index.js +20 -3
  18. package/dist/project-schema/latest.d.ts +4 -139
  19. package/dist/project-schema/latest.d.ts.map +1 -1
  20. package/dist/project-schema/migrate.d.ts.map +1 -1
  21. package/dist/project-schema/migrate.js +4 -0
  22. package/dist/project-schema/v3.18.0.d.ts +1334 -0
  23. package/dist/project-schema/v3.18.0.d.ts.map +1 -0
  24. package/dist/project-schema/v3.18.0.js +5 -0
  25. package/dist/refs.d.ts +14 -2
  26. package/dist/refs.d.ts.map +1 -1
  27. package/dist/refs.js +26 -0
  28. package/dist/relationships.d.ts +28 -2
  29. package/dist/relationships.d.ts.map +1 -1
  30. package/dist/relationships.js +234 -19
  31. package/dist/rewrite.d.ts.map +1 -1
  32. package/dist/rewrite.js +10 -2
  33. package/dist/schema-util.d.ts +1 -18
  34. package/dist/schema-util.d.ts.map +1 -1
  35. package/dist/schema-util.js +36 -120
  36. package/dist/schemas/index.d.ts +2 -2
  37. package/dist/schemas/index.d.ts.map +1 -1
  38. package/dist/schemas/index.js +6 -4
  39. package/dist/schemas/index.ts +4 -2
  40. package/dist/schemas/project-schema/latest.json +2175 -2195
  41. package/dist/schemas/project-schema/v3.18.0.json +2350 -0
  42. package/dist/schemas/project-schema.json +3 -0
  43. package/dist/template-shapes/templates.d.ts +5 -0
  44. package/dist/template-shapes/templates.d.ts.map +1 -1
  45. package/dist/template-shapes/templates.js +59 -28
  46. package/dist/template-shapes/where.d.ts +3 -4
  47. package/dist/template-shapes/where.d.ts.map +1 -1
  48. package/dist/template-shapes/where.js +32 -26
  49. package/dist/types/types.d.ts +42 -2
  50. package/dist/types/types.d.ts.map +1 -1
  51. package/dist/types/utils.d.ts +2 -0
  52. package/dist/types/utils.d.ts.map +1 -1
  53. package/dist/types/utils.js +9 -1
  54. package/dist/unions.d.ts.map +1 -1
  55. package/dist/unions.js +3 -1
  56. package/dist/util/detect-cycles.d.ts +3 -1
  57. package/dist/util/detect-cycles.d.ts.map +1 -1
  58. package/dist/util/detect-cycles.js +37 -28
  59. package/dist/util/form-config.d.ts +9 -0
  60. package/dist/util/form-config.d.ts.map +1 -0
  61. package/dist/util/form-config.js +97 -0
  62. package/dist/util/index.d.ts +1 -0
  63. package/dist/util/index.d.ts.map +1 -1
  64. package/dist/util/index.js +13 -0
  65. package/dist/validate.d.ts.map +1 -1
  66. package/dist/validate.js +75 -45
  67. package/es/builtin-schema.js +17 -0
  68. package/es/get-is-leaf.js +2 -1
  69. package/es/migration/index.js +3 -1
  70. package/es/migration/to/v3.18.0.js +72 -0
  71. package/es/mocks.js +4 -2
  72. package/es/project-schema/index.js +3 -1
  73. package/es/project-schema/migrate.js +5 -1
  74. package/es/project-schema/v3.18.0.js +1 -0
  75. package/es/refs.js +22 -1
  76. package/es/relationships.js +215 -19
  77. package/es/rewrite.js +10 -2
  78. package/es/schema-util.js +38 -119
  79. package/es/schemas/index.js +4 -3
  80. package/es/schemas/index.ts +4 -2
  81. package/es/schemas/project-schema/latest.json +2175 -2195
  82. package/es/schemas/project-schema/v3.18.0.json +2350 -0
  83. package/es/schemas/project-schema.json +3 -0
  84. package/es/template-shapes/templates.js +55 -29
  85. package/es/template-shapes/where.js +29 -23
  86. package/es/types/utils.js +8 -2
  87. package/es/unions.js +2 -1
  88. package/es/util/detect-cycles.js +36 -28
  89. package/es/util/form-config.js +85 -0
  90. package/es/util/index.js +2 -1
  91. package/es/validate.js +74 -46
  92. package/examples/latest/betzino.json +12383 -6066
  93. package/examples/latest/blog-schema.json +46 -25
  94. package/examples/latest/brewery-schema.json +14 -9
  95. package/examples/latest/complex-project-schema.json +442 -244
  96. package/examples/latest/complex-schema.json +17205 -0
  97. package/examples/latest/fabric-ecommerce.json +2 -2
  98. package/examples/latest/frank-and-fred-schema.json +5141 -2391
  99. package/examples/latest/klirr-schema.json +35445 -0
  100. package/examples/latest/massive-schema.json +1205 -640
  101. package/examples/latest/mill-components-schema.json +241 -113
  102. package/examples/latest/one-earth.json +14429 -0
  103. package/examples/latest/pet-oneof-array.json +2 -2
  104. package/examples/latest/post-schema.json +18 -11
  105. package/examples/latest/pruned-shopify-product-schema.json +2 -2
  106. package/examples/latest/real-world-schema.json +81 -41
  107. package/examples/latest/recursive-repeater-schema.json +14 -9
  108. package/examples/latest/recursive-schema.json +14 -9
  109. package/examples/latest/rick-and-morty-ast.json +138 -80
  110. package/examples/latest/rick-and-morty-graphql.json +78 -45
  111. package/examples/latest/rick-and-morty-rest.json +2 -2
  112. package/examples/latest/schema-with-repeater-draftjs.json +38 -23
  113. package/examples/latest/shape-books-v3_2_0.json +138 -80
  114. package/examples/latest/shape-books.json +138 -80
  115. package/examples/latest/shopify-lookbook.json +30 -16
  116. package/examples/latest/shopify-namespace-schema.json +364 -0
  117. package/examples/latest/shopify-store-with-widget.json +2 -2
  118. package/examples/latest/stripe-starter-resolved.json +14 -8
  119. package/examples/latest/user-schema-no-required.json +2 -2
  120. package/examples/latest/user-schema-with-defaults.json +2 -2
  121. package/examples/source/complex-schema.json +12760 -0
  122. package/examples/source/klirr-schema.json +27716 -0
  123. package/examples/source/one-earth.json +11897 -0
  124. package/examples/source/post-schema.json +0 -1
  125. package/package.json +5 -4
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.findShapeFormConfig = findShapeFormConfig;
7
+ exports.normalizeForms = normalizeForms;
8
+
9
+ var _util = require("@takeshape/util");
10
+
11
+ var _refs = require("../refs");
12
+
13
+ var _schemaUtil = require("../schema-util");
14
+
15
+ function normalizeForms(projectSchema) {
16
+ const normalizedForms = {};
17
+ const {
18
+ forms = {}
19
+ } = projectSchema;
20
+
21
+ const storeSourceForm = (shapeName, formConfig, propName) => {
22
+ // Leave original forms intact for backwards compatibility
23
+ if (!forms[shapeName]) {
24
+ if (!normalizedForms[shapeName]) {
25
+ normalizedForms[shapeName] = {
26
+ default: (0, _util.deepClone)(formConfig)
27
+ };
28
+ } // Remove prop now that it has been normalized
29
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
30
+
31
+
32
+ delete normalizedForms[shapeName].default.properties[propName];
33
+ }
34
+ };
35
+
36
+ const normalizeNested = (shapeName, formConfig) => {
37
+ const shape = projectSchema.shapes[shapeName];
38
+
39
+ if (!shape || !formConfig.properties) {
40
+ return;
41
+ }
42
+
43
+ const propertyAccessor = (0, _schemaUtil.createSchemaPropertyAccessor)(projectSchema, shape);
44
+
45
+ for (const propName of Object.keys(formConfig.properties)) {
46
+ const propConfig = formConfig.properties[propName];
47
+ const propSchema = propertyAccessor.getValue(propName);
48
+
49
+ if (propSchema) {
50
+ const ref = (0, _refs.getRef)(projectSchema, propSchema);
51
+
52
+ if (ref && propConfig.properties) {
53
+ const nestedShapeName = (0, _refs.refItemToShapeName)(ref);
54
+ normalizedForms[nestedShapeName] = {
55
+ default: (0, _util.deepClone)(propConfig)
56
+ };
57
+ storeSourceForm(shapeName, formConfig, propName);
58
+ normalizeNested(nestedShapeName, propConfig);
59
+ }
60
+ }
61
+ }
62
+ };
63
+
64
+ if (forms) {
65
+ for (const shapeName of Object.keys(forms)) {
66
+ normalizeNested(shapeName, forms[shapeName].default); // copy forms with no changes
67
+
68
+ if (!normalizedForms[shapeName]) {
69
+ normalizedForms[shapeName] = forms[shapeName];
70
+ }
71
+ }
72
+ }
73
+
74
+ return normalizedForms;
75
+ }
76
+
77
+ const cache = new WeakMap();
78
+ /**
79
+ * Find the form config for a given shape name and the form key.
80
+ */
81
+
82
+ function findShapeFormConfig(projectSchema, shapeName, formName) {
83
+ var _normalizedForms$shap;
84
+
85
+ if (!projectSchema.forms) {
86
+ return;
87
+ }
88
+
89
+ let normalizedForms = cache.get(projectSchema);
90
+
91
+ if (!normalizedForms) {
92
+ normalizedForms = normalizeForms(projectSchema);
93
+ cache.set(projectSchema, normalizedForms);
94
+ }
95
+
96
+ return (_normalizedForms$shap = normalizedForms[shapeName]) === null || _normalizedForms$shap === void 0 ? void 0 : _normalizedForms$shap[formName];
97
+ }
@@ -1,4 +1,5 @@
1
1
  export * from './api-indexing';
2
2
  export * from './detect-cycles';
3
3
  export * from './merge';
4
+ export * from './form-config';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/util/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/util/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC"}
@@ -41,4 +41,17 @@ Object.keys(_merge).forEach(function (key) {
41
41
  return _merge[key];
42
42
  }
43
43
  });
44
+ });
45
+
46
+ var _formConfig = require("./form-config");
47
+
48
+ Object.keys(_formConfig).forEach(function (key) {
49
+ if (key === "default" || key === "__esModule") return;
50
+ if (key in exports && exports[key] === _formConfig[key]) return;
51
+ Object.defineProperty(exports, key, {
52
+ enumerable: true,
53
+ get: function () {
54
+ return _formConfig[key];
55
+ }
56
+ });
44
57
  });
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/validate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,WAAW,EAAC,MAAM,KAAK,CAAC;AACvD,OAAO,KAAK,EAAC,UAAU,EAAE,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAC1D,OAAO,KAAK,EAAmB,mBAAmB,EAAC,MAAM,eAAe,CAAC;AACzE,OAAO,KAAK,EAEV,gBAAgB,EAChB,aAAa,EASb,iBAAiB,EAGlB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAwB,yBAAyB,EAAC,MAAM,mBAAmB,CAAC;AAwcnF,oBAAY,sBAAsB,GAC9B;IAAC,KAAK,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,SAAS,CAAA;CAAC,GAC1D;IAAC,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,yBAAyB,EAAE,CAAA;CAAC,CAAC;AAE3E,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,yBAAyB,CAuBzE;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,CAAC,aAAa,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAC/C,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,eAAe,KAAK,sBAAsB,CAAC;CAClF;AACD,MAAM,WAAW,eAAe;IAC9B,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;IACnC,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,iBAAiB,GAAG,SAAS,CAAC;CACnE;AAqKD;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,sBAAsB,CAqB9F;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,aAAa,CAgBnE;AAgBD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,cAAc,EAAE,OAAO,GAAG,SAAS,CAQpE;AAgBD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,OAAO,GAAG,UAAU,CAQlE;AAqBD;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,OAAO,GAAG,mBAAmB,CAarF"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/validate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,WAAW,EAAC,MAAM,KAAK,CAAC;AACvD,OAAO,KAAK,EAAC,UAAU,EAAE,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAC1D,OAAO,KAAK,EAAmB,mBAAmB,EAAC,MAAM,eAAe,CAAC;AACzE,OAAO,KAAK,EAEV,gBAAgB,EAChB,aAAa,EASb,iBAAiB,EAKlB,MAAM,kBAAkB,CAAC;AAI1B,OAAO,EAAwB,yBAAyB,EAAC,MAAM,mBAAmB,CAAC;AAoenF,oBAAY,sBAAsB,GAC9B;IAAC,KAAK,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,SAAS,CAAA;CAAC,GAC1D;IAAC,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,yBAAyB,EAAE,CAAA;CAAC,CAAC;AAE3E,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,yBAAyB,CAuBzE;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,CAAC,aAAa,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAC/C,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,eAAe,KAAK,sBAAsB,CAAC;CAClF;AACD,MAAM,WAAW,eAAe;IAC9B,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;IACnC,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,iBAAiB,GAAG,SAAS,CAAC;CACnE;AAqKD;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,sBAAsB,CAqB9F;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,aAAa,CAgBnE;AAgBD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,cAAc,EAAE,OAAO,GAAG,SAAS,CAQpE;AAgBD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,OAAO,GAAG,UAAU,CAQlE;AAqBD;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,OAAO,GAAG,mBAAmB,CAarF"}
package/dist/validate.js CHANGED
@@ -12,6 +12,8 @@ exports.validateSchema = validateSchema;
12
12
 
13
13
  var _types = require("./types/types");
14
14
 
15
+ var _jsonpathPlus = require("jsonpath-plus");
16
+
15
17
  var _jsonSchema = require("@takeshape/json-schema");
16
18
 
17
19
  var _errors = require("@takeshape/errors");
@@ -58,6 +60,8 @@ var _util = require("@takeshape/util");
58
60
 
59
61
  var _forOwn = _interopRequireDefault(require("lodash/forOwn"));
60
62
 
63
+ var _relationships = require("./relationships");
64
+
61
65
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
62
66
 
63
67
  function findDuplicates(items) {
@@ -209,6 +213,15 @@ function validateResolver(projectSchema, basePath, resolver) {
209
213
  return [takeshapeResolver, utilResolver, graphqlResolver, restResolver, awsLambdaResolver].flatMap(resolver => resolver.properties.name.enum).includes(resolverName);
210
214
  };
211
215
 
216
+ const isValidShapeName = shapeName => {
217
+ var _indexedShapes;
218
+
219
+ const modelShape = shapeName ? projectSchema.shapes[shapeName] : undefined;
220
+ return Boolean((modelShape === null || modelShape === void 0 ? void 0 : modelShape.model) || shapeName && ((_indexedShapes = projectSchema.indexedShapes) === null || _indexedShapes === void 0 ? void 0 : _indexedShapes[shapeName]));
221
+ };
222
+
223
+ const isLessThanV3_9_0 = (0, _lt.default)((0, _coerce2.default)(projectSchema.schemaVersion) ?? _versions.LEGACY_SCHEMA_VERSION, '3.9.0');
224
+
212
225
  const validateBasicResolver = resolver => {
213
226
  if ((0, _utils.isBasicResolver)(resolver)) {
214
227
  var _projectSchema$servic;
@@ -221,35 +234,23 @@ function validateResolver(projectSchema, basePath, resolver) {
221
234
  });
222
235
  }
223
236
 
224
- if ((0, _lt.default)((0, _coerce2.default)(projectSchema.schemaVersion) ?? _versions.LEGACY_SCHEMA_VERSION, '3.9.0')) {
225
- if (!isValidResolverNameV3_9_0(resolver.name)) {
226
- errors.push({
227
- type: 'notFound',
228
- path: basePath.concat(['name']),
229
- message: `Invalid resolver name "${resolver.name}"`
230
- });
231
- }
237
+ if (isLessThanV3_9_0 && !isValidResolverNameV3_9_0(resolver.name)) {
238
+ errors.push({
239
+ type: 'notFound',
240
+ path: basePath.concat(['name']),
241
+ message: `Invalid resolver name "${resolver.name}"`
242
+ });
232
243
  }
233
244
 
234
- if (resolver.name.startsWith('takeshape')) {
245
+ if (isLessThanV3_9_0 && resolver.name.startsWith('takeshape')) {
235
246
  var _options;
236
247
 
237
- let shapeName;
238
-
239
248
  if ((_options = resolver.options) !== null && _options !== void 0 && _options.model) {
240
249
  var _options2;
241
250
 
242
- shapeName = (_options2 = resolver.options) === null || _options2 === void 0 ? void 0 : _options2.model;
243
- } else if (resolver.shapeName) {
244
- shapeName = resolver.shapeName;
245
- }
251
+ const shapeName = (_options2 = resolver.options) === null || _options2 === void 0 ? void 0 : _options2.model;
246
252
 
247
- if (shapeName) {
248
- var _indexedShapes;
249
-
250
- const modelShape = projectSchema.shapes[shapeName];
251
-
252
- if (!(modelShape !== null && modelShape !== void 0 && modelShape.model) && !(shapeName && (_indexedShapes = projectSchema.indexedShapes) !== null && _indexedShapes !== void 0 && _indexedShapes[shapeName])) {
253
+ if (!isValidShapeName(shapeName)) {
253
254
  errors.push({
254
255
  type: 'notFound',
255
256
  path: basePath.concat(['options', 'model']),
@@ -258,6 +259,20 @@ function validateResolver(projectSchema, basePath, resolver) {
258
259
  }
259
260
  }
260
261
  }
262
+
263
+ if (resolver.shapeName) {
264
+ const {
265
+ shapeName
266
+ } = resolver;
267
+
268
+ if (!isValidShapeName(shapeName)) {
269
+ errors.push({
270
+ type: 'notFound',
271
+ path: basePath.concat(['shapeName']),
272
+ message: `Invalid Model Shape "${shapeName ?? ''}"`
273
+ });
274
+ }
275
+ }
261
276
  } else {
262
277
  errors.push({
263
278
  type: 'notFound',
@@ -403,29 +418,43 @@ function validateRefs(projectSchema, additionalShapeNames = builtInShapeNames) {
403
418
  return errors;
404
419
  }
405
420
 
421
+ function visitShapePropertiesJson(projectSchema, callback) {
422
+ (0, _jsonpathPlus.JSONPath)('shapes.*.schema.properties.*', projectSchema, (property, _type, {
423
+ path: propertyPath
424
+ }) => {
425
+ callback(property, propertyPath.slice(3, -2).split(`']['`));
426
+ }, undefined);
427
+ }
428
+
406
429
  function validateDirectives(projectSchema, additionalShapeIds = builtInModelShapeIds) {
407
430
  const errors = [];
408
431
  const projectShapeIds = new Set([...getModelShapeIds(projectSchema.shapes), ...additionalShapeIds]);
409
- (0, _schemaUtil.visitShapeProperties)(projectSchema.shapes, (schema, path) => {
410
- if (schema['@relationship']) {
411
- var _schema$Relationship;
412
-
413
- const shapeIds = (_schema$Relationship = schema['@relationship']) === null || _schema$Relationship === void 0 ? void 0 : _schema$Relationship.shapeIds;
414
- shapeIds.forEach(shapeId => {
415
- if (!projectShapeIds.has(shapeId)) {
416
- const propPath = path.concat('@relationship');
417
- errors.push({
418
- type: 'notFound',
419
- path: propPath,
420
- message: `Invalid shapeId relationship "${shapeId}" for property "${propPath[4]}" in shape "${propPath[1]}"`
421
- });
422
- }
423
- });
432
+ const isLessThanV3_18_0 = (0, _lt.default)((0, _coerce2.default)(projectSchema.schemaVersion) ?? _versions.LEGACY_SCHEMA_VERSION, '3.18.0');
433
+ visitShapePropertiesJson(projectSchema, (property, propertyPath) => {
434
+ if (isLessThanV3_18_0) {
435
+ const propSchema = property;
436
+
437
+ if (propSchema['@relationship']) {
438
+ var _propSchema$Relation;
439
+
440
+ const shapeIds = (_propSchema$Relation = propSchema['@relationship']) === null || _propSchema$Relation === void 0 ? void 0 : _propSchema$Relation.shapeIds;
441
+ shapeIds.forEach(shapeId => {
442
+ if (!projectShapeIds.has(shapeId)) {
443
+ const propPath = propertyPath.concat('@relationship');
444
+ errors.push({
445
+ type: 'notFound',
446
+ path: propPath,
447
+ message: `Invalid shapeId relationship "${shapeId}" for property "${propPath[4]}" in shape "${propPath[1]}"`
448
+ });
449
+ }
450
+ });
451
+ }
424
452
  }
425
453
 
426
- if (schema['@resolver']) {
427
- const resolver = schema['@resolver'];
428
- const propPath = path.concat('@resolver');
454
+ const resolver = property['@resolver'];
455
+
456
+ if (resolver) {
457
+ const propPath = propertyPath.concat('@resolver');
429
458
  const resolverErrors = validateResolver(projectSchema, propPath, resolver);
430
459
 
431
460
  if (resolverErrors) {
@@ -438,11 +467,12 @@ function validateDirectives(projectSchema, additionalShapeIds = builtInModelShap
438
467
 
439
468
  function validateOneOfs(projectSchema) {
440
469
  const errors = [];
441
- (0, _schemaUtil.visitShapeProperties)(projectSchema.shapes, (schema, path) => {
442
- const oneOfPath = schema.items ? ['items', 'oneOf'] : ['oneOf'];
443
- schema = schema.items ? schema.items : schema;
470
+ visitShapePropertiesJson(projectSchema, (property, propertyPath) => {
471
+ const oneOfPath = property.items ? ['items', 'oneOf'] : ['oneOf'];
472
+ const relationship = (0, _relationships.getRelationship)(property);
473
+ const schema = property.items ? property.items : property;
444
474
 
445
- if (schema.oneOf) {
475
+ if (schema.oneOf && !relationship) {
446
476
  if ((0, _unions.isUnionSchema)(schema)) {
447
477
  const modelsReferenced = (0, _unions.enumerateOneOfKeys)(projectSchema, schema.oneOf).map(child => child.shapeName).filter(shapeName => projectSchema.shapes[shapeName].model);
448
478
 
@@ -450,14 +480,14 @@ function validateOneOfs(projectSchema) {
450
480
  const shapeNames = modelsReferenced.join(', ');
451
481
  errors.push({
452
482
  type: 'json',
453
- path: path.concat(oneOfPath),
483
+ path: propertyPath.concat(oneOfPath),
454
484
  message: `Invalid refs to ${shapeNames}. oneOf unions cannot reference model shapes. Use @relationship instead`
455
485
  });
456
486
  }
457
487
  } else if (!(0, _enum.isEnumLikeSchema)(schema)) {
458
488
  errors.push({
459
489
  type: 'json',
460
- path: path.concat(oneOfPath),
490
+ path: propertyPath.concat(oneOfPath),
461
491
  message: `Invalid oneOf must contain only @ref or title + enum/const schemas`
462
492
  });
463
493
  }
@@ -33,6 +33,23 @@ export const builtInShapes = {
33
33
  required: ['id']
34
34
  }
35
35
  },
36
+ TSRelationshipArgs: {
37
+ id: 'TSRelationshipArgs',
38
+ name: 'TSRelationshipArgs',
39
+ title: 'TSRelationshipArgs',
40
+ schema: {
41
+ type: 'object',
42
+ properties: {
43
+ enableLocaleFallback: {
44
+ type: 'boolean',
45
+ default: true
46
+ },
47
+ locale: {
48
+ type: 'string'
49
+ }
50
+ }
51
+ }
52
+ },
36
53
  TSColorHsl: {
37
54
  id: 'TSColorHsl',
38
55
  name: 'TSColorHsl',
package/es/get-is-leaf.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { getType } from './content-schema-transform';
2
2
  import { getKey, isBuiltinType } from './schema-util';
3
3
  import { followRef, getRefShapeName } from './refs';
4
+ import { isPropertySchemaWithRelationship } from './types';
4
5
  const scalarTags = new Set(['draftjs']);
5
6
 
6
7
  function isLeafTypeV3(projectSchema, propertySchema) {
@@ -8,7 +9,7 @@ function isLeafTypeV3(projectSchema, propertySchema) {
8
9
  return Boolean( // Must have key
9
10
  getKey(propertySchema) && ( // If is not a structure, then is a leaf
10
11
  !['object', 'array'].includes(type) || // If is relationship, then is a leaf
11
- propertySchema['@relationship'] || propertySchema['@tag'] && scalarTags.has(propertySchema['@tag']) || // If is array, then should not be a synchronized structure
12
+ isPropertySchemaWithRelationship(propertySchema) || propertySchema['@tag'] && scalarTags.has(propertySchema['@tag']) || // If is array, then should not be a synchronized structure
12
13
  type === 'array' && !propertySchema['@syncLocaleStructure'] || isBuiltinType(projectSchema, propertySchema)));
13
14
  }
14
15
 
@@ -21,6 +21,7 @@ import migrateToV3_15_0 from './to/v3.15.0';
21
21
  import migrateToV3_16_0 from './to/v3.16.0';
22
22
  import migrateToV3_17_0 from './to/v3.17.0';
23
23
  import migrateToV3_17_1 from './to/v3.17.1';
24
+ import migrateToV3_18_0 from './to/v3.18.0';
24
25
  export const migrateTo = {
25
26
  'v3.0.0': migrateToV3_0_0,
26
27
  'v3.1.0': migrateToV3_1_0,
@@ -44,7 +45,8 @@ export const migrateTo = {
44
45
  'v3.15.0': migrateToV3_15_0,
45
46
  'v3.16.0': migrateToV3_16_0,
46
47
  'v3.17.0': migrateToV3_17_0,
47
- 'v3.17.1': migrateToV3_17_1
48
+ 'v3.17.1': migrateToV3_17_1,
49
+ 'v3.18.0': migrateToV3_18_0
48
50
  };
49
51
  export * from './utils';
50
52
  export const listTypePrefix = 'PaginatedList';
@@ -0,0 +1,72 @@
1
+ import { isDefined, visit } from '@takeshape/util';
2
+ import get from 'lodash/get';
3
+ import set from 'lodash/set';
4
+ import omit from 'lodash/omit';
5
+
6
+ const migrate = async (_, projectSchema) => {
7
+ visit(projectSchema, ['@relationship'], (relationship, path) => {
8
+ const propertyPath = path.slice(0, -1);
9
+ const originalPropertySchema = get(projectSchema, propertyPath);
10
+ const propertySchema = omit(originalPropertySchema, ['@relationship', 'type', '$ref']);
11
+ const shapeIdMap = new Map(Object.values(projectSchema.shapes).map(shape => [shape.id, shape]));
12
+
13
+ const shapeIdsToShapeRefs = shapeIds => {
14
+ return shapeIds.map(shapeId => {
15
+ let shape;
16
+
17
+ if (shapeId === 'ASSET') {
18
+ shape = {
19
+ name: 'Asset'
20
+ };
21
+ } else {
22
+ shape = shapeIdMap.get(shapeId);
23
+ }
24
+
25
+ if (!shape) {
26
+ return;
27
+ }
28
+
29
+ return {
30
+ '@ref': `local:${shape.name}`
31
+ };
32
+ }).filter(isDefined);
33
+ };
34
+
35
+ const shapeRefs = shapeIdsToShapeRefs(relationship.shapeIds);
36
+ const shapeRefsSchema = shapeRefs.length === 1 ? shapeRefs[0] : {
37
+ oneOf: shapeRefs
38
+ };
39
+
40
+ if (relationship.type === 'multiple') {
41
+ propertySchema.type = 'array';
42
+ propertySchema.items = shapeRefsSchema;
43
+ propertySchema['@input'] = {
44
+ type: 'array',
45
+ items: {
46
+ '@ref': 'local:TSRelationship'
47
+ }
48
+ };
49
+ } else {
50
+ delete propertySchema.type;
51
+ Object.assign(propertySchema, shapeRefsSchema);
52
+ propertySchema['@input'] = {
53
+ '@ref': 'local:TSRelationship'
54
+ };
55
+ }
56
+
57
+ propertySchema['@args'] = 'TSRelationshipArgs';
58
+ propertySchema['@resolver'] = {
59
+ name: 'takeshape:getRelated',
60
+ service: 'takeshape:local',
61
+ options: {
62
+ nullable: true
63
+ }
64
+ };
65
+ set(projectSchema, propertyPath, propertySchema);
66
+ });
67
+ return { ...projectSchema,
68
+ schemaVersion: '3.18.0'
69
+ };
70
+ };
71
+
72
+ export default migrate;
package/es/mocks.js CHANGED
@@ -6,7 +6,8 @@ import { pascalCase } from '@takeshape/util';
6
6
 
7
7
  export function createMockSchema(projectId, schema = {}) {
8
8
  return { ...emptySchema(projectId, schema.dataKey ?? 'supersecret'),
9
- ...schema
9
+ ...schema,
10
+ projectId
10
11
  };
11
12
  }
12
13
  /**
@@ -15,7 +16,8 @@ export function createMockSchema(projectId, schema = {}) {
15
16
 
16
17
  export function createMockSchemaWithDefaults(projectId, schema = {}) {
17
18
  return applyDefaultsToSchema({ ...emptySchema(projectId, schema.dataKey ?? 'supersecret'),
18
- ...schema
19
+ ...schema,
20
+ projectId
19
21
  });
20
22
  }
21
23
  export function createMockServiceConfig(serviceKey, serviceConfig) {
@@ -24,6 +24,7 @@ export * from './v3.15.0';
24
24
  export * from './v3.16.0';
25
25
  export * from './v3.17.0';
26
26
  export * from './v3.17.1';
27
+ export * from './v3.18.0';
27
28
  export * from './v4.0.0';
28
29
 
29
30
  // Schema type utilities
@@ -69,5 +70,6 @@ export const isProjectSchemaV3_15_0 = createVersionPredicate('3.15.0');
69
70
  export const isProjectSchemaV3_16_0 = createVersionPredicate('3.16.0');
70
71
  export const isProjectSchemaV3_17_0 = createVersionPredicate('3.17.0');
71
72
  export const isProjectSchemaV3_17_1 = createVersionPredicate('3.17.1');
72
- export const isLatestProjectSchema = createVersionPredicate('3.17.1');
73
+ export const isProjectSchemaV3_18_0 = createVersionPredicate('3.18.0');
74
+ export const isLatestProjectSchema = createVersionPredicate('3.18.0');
73
75
  export const isProjectSchemaV4_0_0 = createVersionPredicate('4.0.0');
@@ -1,6 +1,6 @@
1
1
  // This file is generated by "pnpm json2ts"
2
2
  import { migrateTo } from '../migration';
3
- import { isProjectSchemaV1_0_0, isProjectSchemaV3_0_0, isProjectSchemaV3_1_0, isProjectSchemaV3_2_0, isProjectSchemaV3_3_0, isProjectSchemaV3_4_0, isProjectSchemaV3_5_0, isProjectSchemaV3_5_1, isProjectSchemaV3_6_0, isProjectSchemaV3_7_0, isProjectSchemaV3_8_0, isProjectSchemaV3_9_0, isProjectSchemaV3_10_0, isProjectSchemaV3_11_0, isProjectSchemaV3_12_0, isProjectSchemaV3_12_1, isProjectSchemaV3_12_2, isProjectSchemaV3_12_3, isProjectSchemaV3_13_0, isProjectSchemaV3_14_0, isProjectSchemaV3_15_0, isProjectSchemaV3_16_0, isProjectSchemaV3_17_0, isProjectSchemaV4_0_0, isLatestProjectSchema } from './index'; // eslint-disable-next-line complexity
3
+ import { isProjectSchemaV1_0_0, isProjectSchemaV3_0_0, isProjectSchemaV3_1_0, isProjectSchemaV3_2_0, isProjectSchemaV3_3_0, isProjectSchemaV3_4_0, isProjectSchemaV3_5_0, isProjectSchemaV3_5_1, isProjectSchemaV3_6_0, isProjectSchemaV3_7_0, isProjectSchemaV3_8_0, isProjectSchemaV3_9_0, isProjectSchemaV3_10_0, isProjectSchemaV3_11_0, isProjectSchemaV3_12_0, isProjectSchemaV3_12_1, isProjectSchemaV3_12_2, isProjectSchemaV3_12_3, isProjectSchemaV3_13_0, isProjectSchemaV3_14_0, isProjectSchemaV3_15_0, isProjectSchemaV3_16_0, isProjectSchemaV3_17_0, isProjectSchemaV3_17_1, isProjectSchemaV4_0_0, isLatestProjectSchema } from './index'; // eslint-disable-next-line complexity
4
4
 
5
5
  export async function migrateToLatestProjectSchema(context, projectSchema) {
6
6
  if (isLatestProjectSchema(projectSchema)) {
@@ -99,6 +99,10 @@ export async function migrateToLatestProjectSchema(context, projectSchema) {
99
99
  projectSchema = await migrateTo['v3.17.1'](context, projectSchema);
100
100
  }
101
101
 
102
+ if (isProjectSchemaV3_17_1(projectSchema)) {
103
+ projectSchema = await migrateTo['v3.18.0'](context, projectSchema);
104
+ }
105
+
102
106
  if (isProjectSchemaV4_0_0(projectSchema)) {
103
107
  throw new Error('You are using an unreleased schema version. Migration is not possible');
104
108
  }
@@ -0,0 +1 @@
1
+ export {};
package/es/refs.js CHANGED
@@ -5,7 +5,14 @@ import omit from 'lodash/fp/omit';
5
5
  import { getServiceNamespace, getServiceNamespaces } from './services';
6
6
  import { mergeObjectSchemas } from './util/merge';
7
7
  import { resolveSchema } from 'ajv/dist/compile';
8
- import { isIntegerLike } from '@takeshape/util';
8
+ import { isIntegerLike, isDefined } from '@takeshape/util';
9
+
10
+ /**
11
+ * Guard for RefItemWithPath. Tests for presence of all required props.
12
+ */
13
+ export function isRefItemWithPath(ref) {
14
+ return Boolean(ref.typeName && ref.serviceKey && ref.path && isDefined(ref.isForeign));
15
+ }
9
16
  const templateShapeRegex = /^(\w+)<([\w:-]+)>$/;
10
17
  /**
11
18
  * Parse a template like `PaginatedList<Post>` and return both the template and the shape name.
@@ -127,6 +134,13 @@ export function refExpressionToRefItem(context, refExpression) {
127
134
 
128
135
  return refToRefItem(context, `#/shapes/${shapeName}/schema`, template);
129
136
  }
137
+ /**
138
+ * Converts a list of ref expressions into a list of ref items.
139
+ */
140
+
141
+ export function refExpressionListToRefItemList(context, refExpressionList) {
142
+ return refExpressionList.map(ref => refExpressionToRefItem(context, ref));
143
+ }
130
144
  /**
131
145
  * Sugar for converting a `refExpression` directly into a shape, without the
132
146
  * intermediate `refItem`.
@@ -289,6 +303,13 @@ export function refItemToShape(context, refItem) {
289
303
  const shapePath = refItemToShapePath(refItem);
290
304
  return get(context, shapePath);
291
305
  }
306
+ /**
307
+ * Get all shapes referenced by a RefItem array.
308
+ */
309
+
310
+ export function refItemListToShapeList(context, refItems) {
311
+ return refItems.map(ref => refItemToShape(context, ref)).filter(isDefined);
312
+ }
292
313
  /**
293
314
  * Get a shape referenced by a `RefItem`, also returning the path to the new shape.
294
315
  */