@api-client/core 0.6.14 → 0.6.15

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 (147) hide show
  1. package/build/browser.d.ts +9 -2
  2. package/build/browser.js +12 -2
  3. package/build/browser.js.map +1 -1
  4. package/build/index.d.ts +9 -2
  5. package/build/index.js +12 -2
  6. package/build/index.js.map +1 -1
  7. package/build/src/amf/AmfMixin.d.ts +395 -0
  8. package/build/src/amf/AmfMixin.js +1146 -0
  9. package/build/src/amf/AmfMixin.js.map +1 -0
  10. package/build/src/amf/AmfSerializer.d.ts +136 -0
  11. package/build/src/amf/AmfSerializer.js +1913 -0
  12. package/build/src/amf/AmfSerializer.js.map +1 -0
  13. package/build/src/amf/AmfShapeGenerator.d.ts +85 -0
  14. package/build/src/amf/AmfShapeGenerator.js +385 -0
  15. package/build/src/amf/AmfShapeGenerator.js.map +1 -0
  16. package/build/src/amf/AmfTypes.d.ts +24 -0
  17. package/build/src/amf/AmfTypes.js +122 -0
  18. package/build/src/amf/AmfTypes.js.map +1 -0
  19. package/build/src/amf/ApiExampleGenerator.d.ts +36 -0
  20. package/build/src/amf/ApiExampleGenerator.js +109 -0
  21. package/build/src/amf/ApiExampleGenerator.js.map +1 -0
  22. package/build/src/amf/ApiMonacoSchemaGenerator.d.ts +67 -0
  23. package/build/src/amf/ApiMonacoSchemaGenerator.js +243 -0
  24. package/build/src/amf/ApiMonacoSchemaGenerator.js.map +1 -0
  25. package/build/src/amf/ApiSchemaGenerator.d.ts +55 -0
  26. package/build/src/amf/ApiSchemaGenerator.js +94 -0
  27. package/build/src/amf/ApiSchemaGenerator.js.map +1 -0
  28. package/build/src/amf/ApiSchemaValues.d.ts +98 -0
  29. package/build/src/amf/ApiSchemaValues.js +382 -0
  30. package/build/src/amf/ApiSchemaValues.js.map +1 -0
  31. package/build/src/amf/Utils.d.ts +41 -0
  32. package/build/src/amf/Utils.js +176 -0
  33. package/build/src/amf/Utils.js.map +1 -0
  34. package/build/src/amf/data-node/DataNodeBase.d.ts +31 -0
  35. package/build/src/amf/data-node/DataNodeBase.js +77 -0
  36. package/build/src/amf/data-node/DataNodeBase.js.map +1 -0
  37. package/build/src/amf/data-node/JsonDataNodeGenerator.d.ts +15 -0
  38. package/build/src/amf/data-node/JsonDataNodeGenerator.js +24 -0
  39. package/build/src/amf/data-node/JsonDataNodeGenerator.js.map +1 -0
  40. package/build/src/amf/data-node/UrlEncodedDataNodeGenerator.d.ts +13 -0
  41. package/build/src/amf/data-node/UrlEncodedDataNodeGenerator.js +42 -0
  42. package/build/src/amf/data-node/UrlEncodedDataNodeGenerator.js.map +1 -0
  43. package/build/src/amf/data-node/XmlDataNodeGenerator.d.ts +21 -0
  44. package/build/src/amf/data-node/XmlDataNodeGenerator.js +30 -0
  45. package/build/src/amf/data-node/XmlDataNodeGenerator.js.map +1 -0
  46. package/build/src/amf/definitions/Amf.d.ts +362 -0
  47. package/build/src/amf/definitions/Amf.js +2 -0
  48. package/build/src/amf/definitions/Amf.js.map +1 -0
  49. package/build/src/amf/definitions/Api.d.ts +381 -0
  50. package/build/src/amf/definitions/Api.js +2 -0
  51. package/build/src/amf/definitions/Api.js.map +1 -0
  52. package/build/src/amf/definitions/Base.d.ts +11 -0
  53. package/build/src/amf/definitions/Base.js +2 -0
  54. package/build/src/amf/definitions/Base.js.map +1 -0
  55. package/build/src/amf/definitions/Namespace.d.ts +311 -0
  56. package/build/src/amf/definitions/Namespace.js +330 -0
  57. package/build/src/amf/definitions/Namespace.js.map +1 -0
  58. package/build/src/amf/definitions/Shapes.d.ts +309 -0
  59. package/build/src/amf/definitions/Shapes.js +87 -0
  60. package/build/src/amf/definitions/Shapes.js.map +1 -0
  61. package/build/src/amf/models/AmfDataNode.d.ts +68 -0
  62. package/build/src/amf/models/AmfDataNode.js +188 -0
  63. package/build/src/amf/models/AmfDataNode.js.map +1 -0
  64. package/build/src/amf/shape/ShapeBase.d.ts +75 -0
  65. package/build/src/amf/shape/ShapeBase.js +90 -0
  66. package/build/src/amf/shape/ShapeBase.js.map +1 -0
  67. package/build/src/amf/shape/ShapeJsonSchemaGenerator.d.ts +46 -0
  68. package/build/src/amf/shape/ShapeJsonSchemaGenerator.js +406 -0
  69. package/build/src/amf/shape/ShapeJsonSchemaGenerator.js.map +1 -0
  70. package/build/src/amf/shape/ShapeXmlSchemaGenerator.d.ts +84 -0
  71. package/build/src/amf/shape/ShapeXmlSchemaGenerator.js +820 -0
  72. package/build/src/amf/shape/ShapeXmlSchemaGenerator.js.map +1 -0
  73. package/build/src/models/data/Bindings.d.ts +161 -0
  74. package/build/src/models/data/Bindings.js +2 -0
  75. package/build/src/models/data/Bindings.js.map +1 -0
  76. package/build/src/models/data/DataAssociation.d.ts +135 -14
  77. package/build/src/models/data/DataAssociation.js +154 -21
  78. package/build/src/models/data/DataAssociation.js.map +1 -1
  79. package/build/src/models/data/DataAssociationSchema.d.ts +36 -0
  80. package/build/src/models/data/DataEntity.d.ts +54 -4
  81. package/build/src/models/data/DataEntity.js +85 -9
  82. package/build/src/models/data/DataEntity.js.map +1 -1
  83. package/build/src/models/data/DataFile.d.ts +3 -0
  84. package/build/src/models/data/DataFile.js +3 -0
  85. package/build/src/models/data/DataFile.js.map +1 -1
  86. package/build/src/models/data/DataModel.d.ts +1 -1
  87. package/build/src/models/data/DataModel.js.map +1 -1
  88. package/build/src/models/data/DataProperty.d.ts +107 -36
  89. package/build/src/models/data/DataProperty.js +147 -17
  90. package/build/src/models/data/DataProperty.js.map +1 -1
  91. package/data/apis/oas-date/oas-date.yaml +28 -0
  92. package/data/apis/oas-types/oas-types.yaml +159 -0
  93. package/data/apis/oas-unions/oas-unions.yaml +75 -0
  94. package/data/apis/raml-date/raml-date.raml +28 -0
  95. package/data/apis/recursive/recursive.raml +14 -0
  96. package/data/apis/schema-api/examples/person.json +14 -0
  97. package/data/apis/schema-api/examples/person.raml +14 -0
  98. package/data/apis/schema-api/examples/person.url.encoded +1 -0
  99. package/data/apis/schema-api/examples/person.xml +14 -0
  100. package/data/apis/schema-api/library/demo-types.raml +43 -0
  101. package/data/apis/schema-api/schema-api.raml +644 -0
  102. package/data/apis/schema-api/schemas/person.json +104 -0
  103. package/data/apis/schema-api/schemas/person.xsd +26 -0
  104. package/data/apis/schema-api/types/DemoPerson.raml +67 -0
  105. package/data/model.js +106 -0
  106. package/data/models/oas-date.json +637 -0
  107. package/data/models/oas-types.json +5352 -0
  108. package/data/models/oas-unions.json +1881 -0
  109. package/data/models/raml-date.json +1096 -0
  110. package/data/models/recursive.json +610 -0
  111. package/data/models/schema-api.json +37319 -0
  112. package/package.json +9 -6
  113. package/src/amf/AmfMixin.ts +1623 -0
  114. package/src/amf/AmfSerializer.ts +2028 -0
  115. package/src/amf/AmfShapeGenerator.ts +400 -0
  116. package/src/amf/AmfTypes.ts +126 -0
  117. package/src/amf/ApiExampleGenerator.ts +112 -0
  118. package/src/amf/ApiMonacoSchemaGenerator.ts +296 -0
  119. package/src/amf/ApiSchemaGenerator.ts +108 -0
  120. package/src/amf/ApiSchemaValues.ts +411 -0
  121. package/src/amf/Utils.ts +182 -0
  122. package/src/amf/data-node/DataNodeBase.ts +81 -0
  123. package/src/amf/data-node/JsonDataNodeGenerator.ts +26 -0
  124. package/src/amf/data-node/README.md +3 -0
  125. package/src/amf/data-node/UrlEncodedDataNodeGenerator.ts +43 -0
  126. package/src/amf/data-node/XmlDataNodeGenerator.ts +38 -0
  127. package/src/amf/definitions/Amf.ts +443 -0
  128. package/src/amf/definitions/Api.ts +427 -0
  129. package/src/amf/definitions/Base.ts +13 -0
  130. package/src/amf/definitions/Namespace.ts +341 -0
  131. package/src/amf/definitions/Shapes.ts +414 -0
  132. package/src/amf/models/AmfDataNode.ts +200 -0
  133. package/src/amf/shape/README.md +4 -0
  134. package/src/amf/shape/ShapeBase.ts +160 -0
  135. package/src/amf/shape/ShapeJsonSchemaGenerator.ts +422 -0
  136. package/src/amf/shape/ShapeXmlSchemaGenerator.ts +876 -0
  137. package/src/models/data/Bindings.ts +186 -0
  138. package/src/models/data/DataAssociation.ts +226 -29
  139. package/src/models/data/DataAssociationSchema.ts +38 -0
  140. package/src/models/data/DataEntity.ts +112 -14
  141. package/src/models/data/DataFile.ts +3 -0
  142. package/src/models/data/DataModel.ts +1 -1
  143. package/src/models/data/DataProperty.ts +191 -47
  144. package/build/src/models/data/DataPropertySchema.d.ts +0 -125
  145. package/build/src/models/data/DataPropertySchema.js +0 -33
  146. package/build/src/models/data/DataPropertySchema.js.map +0 -1
  147. package/src/models/data/DataPropertySchema.ts +0 -156
@@ -5,6 +5,9 @@ import { DataProperty, DataPropertyType } from "./DataProperty.js";
5
5
  import { DataAssociation } from "./DataAssociation.js";
6
6
  import { IBreadcrumb } from "../store/Breadcrumb.js";
7
7
  import { DataModel } from "./DataModel.js";
8
+ import { INodeShape, IShapeUnion } from "../../amf/definitions/Shapes.js";
9
+ import { AmfShapeGenerator } from "../../amf/AmfShapeGenerator.js";
10
+ import { ApiSchemaGenerator } from "../../amf/ApiSchemaGenerator.js";
8
11
 
9
12
  export const Kind = 'Core#DataEntity';
10
13
 
@@ -60,6 +63,24 @@ export interface IDataEntity {
60
63
  * Whether this entity is deprecated.
61
64
  */
62
65
  deprecated?: boolean;
66
+
67
+ /**
68
+ * The schema allowing to translate the model into a specific format (like JSON, RAML, XML, etc.)
69
+ *
70
+ * Schema limitations:
71
+ *
72
+ * - can only occur on an adapted property. Has no effect on the "main" property.
73
+ */
74
+ schema?: INodeShape;
75
+
76
+ /**
77
+ * The key of the entity that is adapted by this entity.
78
+ * Adapted entities can manipulate the shape of the schema for the entity.
79
+ *
80
+ * Each value defined on the adapted entity changes the original value defined on
81
+ * the entity.
82
+ */
83
+ adapts?: string;
63
84
  }
64
85
 
65
86
  /**
@@ -114,6 +135,15 @@ export class DataEntity {
114
135
  */
115
136
  deprecated?: boolean;
116
137
 
138
+ /**
139
+ * The key of the entity that is adapted by this entity.
140
+ * Adapted entities can manipulate the shape of the schema for the entity.
141
+ *
142
+ * Each value defined on the adapted entity changes the original value defined on
143
+ * the entity.
144
+ */
145
+ adapts?: string;
146
+
117
147
  static fromName(root: DataNamespace, name: string): DataEntity {
118
148
  const entity = new DataEntity(root);
119
149
  entity.info = Thing.fromName(name);
@@ -123,7 +153,7 @@ export class DataEntity {
123
153
  /**
124
154
  * @param input The data entity definition to restore.
125
155
  */
126
- constructor(protected root: DataNamespace, input?: string | IDataEntity) {
156
+ constructor(public root: DataNamespace, input?: string | IDataEntity) {
127
157
  let init: IDataEntity;
128
158
  if (typeof input === 'string') {
129
159
  init = JSON.parse(input);
@@ -143,7 +173,10 @@ export class DataEntity {
143
173
  if (!DataEntity.isDataEntity(init)) {
144
174
  throw new Error(`Not a data entity.`);
145
175
  }
146
- const { info, key = v4(), kind = Kind, tags, taxonomy, parents, properties, associations, deprecated } = init;
176
+ const {
177
+ info, key = v4(), kind = Kind, tags, taxonomy, parents, properties, associations,
178
+ deprecated, adapts,
179
+ } = init;
147
180
  this.kind = kind;
148
181
  this.key = key;
149
182
  if (info) {
@@ -151,7 +184,6 @@ export class DataEntity {
151
184
  } else {
152
185
  this.info = Thing.fromName('');
153
186
  }
154
-
155
187
  if (Array.isArray(tags)) {
156
188
  this.tags = [...tags];
157
189
  } else {
@@ -167,7 +199,6 @@ export class DataEntity {
167
199
  } else {
168
200
  this.parents = [];
169
201
  }
170
-
171
202
  this.properties = [];
172
203
  if (Array.isArray(properties)) {
173
204
  properties.forEach(key => {
@@ -177,7 +208,6 @@ export class DataEntity {
177
208
  }
178
209
  });
179
210
  }
180
-
181
211
  this.associations = [];
182
212
  if (Array.isArray(associations)) {
183
213
  associations.forEach(key => {
@@ -187,12 +217,16 @@ export class DataEntity {
187
217
  }
188
218
  });
189
219
  }
190
-
191
220
  if (typeof deprecated === 'boolean') {
192
221
  this.deprecated = deprecated;
193
222
  } else {
194
223
  this.deprecated = undefined;
195
224
  }
225
+ if (typeof adapts === 'string') {
226
+ this.adapts = adapts;
227
+ } else {
228
+ this.adapts = undefined;
229
+ }
196
230
  }
197
231
 
198
232
  static isDataEntity(input: unknown): boolean {
@@ -227,6 +261,9 @@ export class DataEntity {
227
261
  if (typeof this.deprecated === 'boolean') {
228
262
  result.deprecated = this.deprecated;
229
263
  }
264
+ if (this.adapts) {
265
+ result.adapts = this.adapts;
266
+ }
230
267
  return result;
231
268
  }
232
269
 
@@ -243,8 +280,11 @@ export class DataEntity {
243
280
  * @param type The type of the property
244
281
  * @returns The created property
245
282
  */
246
- addTypedProperty(type: DataPropertyType): DataProperty {
283
+ addTypedProperty(type: DataPropertyType, name?: string): DataProperty {
247
284
  const property = DataProperty.fromType(this.root, type);
285
+ if (name) {
286
+ property.info.name = name;
287
+ }
248
288
  this.root.definitions.properties.push(property);
249
289
  this.properties.push(property);
250
290
  return property;
@@ -295,8 +335,11 @@ export class DataEntity {
295
335
  * @param target The target entity key of the association
296
336
  * @returns The created association
297
337
  */
298
- addTargetAssociation(target: string): DataAssociation {
338
+ addTargetAssociation(target: string, name?: string): DataAssociation {
299
339
  const result = DataAssociation.fromTarget(this.root, target);
340
+ if (name) {
341
+ result.info.name = name;
342
+ }
300
343
  this.root.definitions.associations.push(result);
301
344
  this.associations.push(result);
302
345
  return result;
@@ -321,15 +364,18 @@ export class DataEntity {
321
364
  /**
322
365
  * Reads the list of parents for the entity, inside the root namespace. The computed list contains the list of all
323
366
  * parents in the inheritance chain in no particular order.
367
+ * @param recursive Whether to include parent parents as well.
324
368
  */
325
- getComputedParents(): DataEntity[] {
369
+ getComputedParents(recursive?: boolean): DataEntity[] {
326
370
  const { entities } = this.root.definitions;
327
371
  let result: DataEntity[] = [];
328
372
  this.parents.forEach((key) => {
329
373
  const parent = entities.find(i => i.key === key);
330
374
  if (parent) {
331
375
  result.push(parent);
332
- result = result.concat(parent.getComputedParents());
376
+ if (recursive) {
377
+ result = result.concat(parent.getComputedParents());
378
+ }
333
379
  }
334
380
  });
335
381
  return result;
@@ -352,10 +398,10 @@ export class DataEntity {
352
398
  const { entities } = root.definitions;
353
399
  const result: DataEntity[] = [];
354
400
  associations.forEach((assoc) => {
355
- if (!assoc.target) {
401
+ if (!assoc.targets.length) {
356
402
  return;
357
403
  }
358
- const entity = entities.find(i => i.key === assoc.target);
404
+ const entity = entities.find(i => assoc.targets.includes(i.key));
359
405
  if (entity) {
360
406
  result.push(entity);
361
407
  }
@@ -463,7 +509,7 @@ export class DataEntity {
463
509
  const graph: Record<string, string[]> = {};
464
510
  const { associations, entities } = this.root.definitions;
465
511
  for (const assoc of associations) {
466
- if (!assoc.target) {
512
+ if (!assoc.targets.length) {
467
513
  continue;
468
514
  }
469
515
  const srcEntity = entities.find(i => i.associations.some(a => a === assoc));
@@ -473,7 +519,7 @@ export class DataEntity {
473
519
  if (!graph[srcEntity.key]) {
474
520
  graph[srcEntity.key] = [];
475
521
  }
476
- graph[srcEntity.key].push(assoc.target);
522
+ graph[srcEntity.key].splice(0, 0, ...assoc.targets);
477
523
  }
478
524
  return graph;
479
525
  }
@@ -552,4 +598,56 @@ export class DataEntity {
552
598
  tags.splice(index, 1);
553
599
  }
554
600
  }
601
+
602
+ /**
603
+ * Creates a Shape of AMF.
604
+ * The property itself is auto-generated. If the `schema` is defined then it is used
605
+ * as the `range` of the property. Otherwise basic shape is generated for the range.
606
+ *
607
+ * This is a preferred way of reading the AMF shape as this synchronizes changed
608
+ * data properties with the shape definition.
609
+ *
610
+ * @returns AMF property shape definition.
611
+ */
612
+ toApiShape(): IShapeUnion {
613
+ const serializer = new AmfShapeGenerator();
614
+ return serializer.entity(this);
615
+ }
616
+
617
+ /**
618
+ * Reads the schema of the Entity and generates an example for it.
619
+ */
620
+ toExample(mime: string): string | number | boolean | null | undefined {
621
+ const shape = this.toApiShape();
622
+ const generator = new ApiSchemaGenerator(mime, {
623
+ renderExamples: true,
624
+ renderMocked: true,
625
+ renderOptional: true,
626
+ });
627
+ return generator.generate(shape);
628
+ }
629
+
630
+ /**
631
+ * @returns The adapted entity, if any
632
+ */
633
+ readAdapted(): DataEntity | undefined {
634
+ const { adapts } = this;
635
+ if (!adapts) {
636
+ return undefined;
637
+ }
638
+ return this.root.definitions.entities.find(i => i.key === adapts);
639
+ }
640
+
641
+ /**
642
+ * Creates new adapted entity and associates it with this entity.
643
+ * @returns The instance of the created entity.
644
+ */
645
+ createAdapted(): DataEntity {
646
+ const entity = new DataEntity(this.root);
647
+ // disallow defaults as this would influence the schema generation
648
+ entity.info.name = undefined;
649
+ this.root.definitions.entities.push(entity);
650
+ this.adapts = entity.key;
651
+ return entity;
652
+ }
555
653
  }
@@ -9,6 +9,9 @@ export interface IDataFile extends IFile {
9
9
  kind: typeof Kind;
10
10
  }
11
11
 
12
+ /**
13
+ * Used by the store. A file definition for the DataNamespace
14
+ */
12
15
  export class DataFile extends File {
13
16
  kind = Kind;
14
17
 
@@ -59,7 +59,7 @@ export class DataModel {
59
59
  * @param root the root namespace.
60
60
  * @param input The data model definition to restore.
61
61
  */
62
- constructor(protected root: DataNamespace, input?: string | IDataModel) {
62
+ constructor(public root: DataNamespace, input?: string | IDataModel) {
63
63
  let init: IDataModel;
64
64
  if (typeof input === 'string') {
65
65
  init = JSON.parse(input);
@@ -1,51 +1,44 @@
1
+ import { Core as JsonCore } from '@api-client/json';
1
2
  import { IThing, Thing } from "../Thing.js";
2
3
  import v4 from '../../lib/uuid.js';
3
4
  import { DataNamespace } from "./DataNamespace.js";
4
- import { IDataPropertySchema } from "./DataPropertySchema.js";
5
+ import { IPropertyShape } from "../../amf/definitions/Shapes.js";
6
+ import { AmfShapeGenerator } from '../../amf/AmfShapeGenerator.js';
7
+ import { IPropertyBindings, IPropertySchema } from './Bindings.js';
5
8
 
6
- export type DataPropertyType = 'string' | 'number' | 'nil' | 'boolean' | 'date' | 'datetime' |
7
- 'time' | 'bytes' | 'any' | 'file';
9
+ export type DataPropertyType = 'string' | 'number' | 'integer' | 'nil' | 'boolean' | 'date' | 'datetime' | 'time' | 'any' | 'binary';
8
10
  export const DataPropertyTypes: DataPropertyType[] = [
9
- 'string', 'number', 'nil', 'boolean', 'date', 'datetime', 'time', 'bytes', 'any', 'file'
11
+ 'string', 'number', 'integer', 'nil', 'boolean', 'date', 'datetime', 'time' , 'any', 'binary'
10
12
  ];
11
13
 
12
14
  export enum DataPropertyList {
13
15
  string = 'string',
14
16
  number = 'number',
17
+ integer = 'integer', // RAML, OAS and JSON schema define numbers and integers separately
15
18
  nil = 'nil',
16
19
  boolean = 'boolean',
17
20
  date = 'date',
18
21
  datetime = 'datetime',
19
22
  time = 'time',
20
- bytes = 'bytes',
21
23
  any = 'any',
22
- file = 'file',
24
+ file = 'binary',
23
25
  }
24
26
 
25
- export const Kind = 'Core#DataProperty';
26
-
27
- export interface IPropertySchema<T> {
27
+ export type DateFormat = 'rfc3339' | 'rfc2616';
28
+ export const DateFormats: DateFormat[] = ['rfc3339', 'rfc2616'];
29
+ export enum DateFormatList {
28
30
  /**
29
- * Whether it is a general schema for the property.
30
- * All other schemas inherit from this one. This allows creating global schema description
31
- * like examples, default values, minimum value, etc and then use it as a base to generate specific formats.
32
- *
33
- * A property may not have a global schema.
31
+ * The "date-time" notation of RFC3339
34
32
  */
35
- global?: boolean;
33
+ rfc3339 = 'rfc3339',
36
34
  /**
37
- * The mime type this schema describes.
38
- * For JSON it is `application/json`, for XML it is `application/xml` (or `text/xml`) adn so on.
39
- *
40
- * Note, when this value is missing then it is assumed that the schema is `global`.
35
+ * The format defined in RFC2616.
41
36
  */
42
- format?: string;
43
- /**
44
- * The schema definition.
45
- */
46
- value: IDataPropertySchema<T>;
37
+ rfc2616 = 'rfc2616',
47
38
  }
48
39
 
40
+ export const Kind = 'Core#DataProperty';
41
+
49
42
  export interface IDataProperty {
50
43
  kind: typeof Kind;
51
44
  /**
@@ -72,6 +65,21 @@ export interface IDataProperty {
72
65
  * Whether this property describes an indexed property of the entity.
73
66
  */
74
67
  index?: boolean;
68
+ /**
69
+ * Whether the property is read only in the schema.
70
+ */
71
+ readOnly?: boolean;
72
+ /**
73
+ * Whether the property is write only in the schema.
74
+ */
75
+ writeOnly?: boolean;
76
+ /**
77
+ * Whether the attribute is hidden in the schema (not a part of it).
78
+ *
79
+ * The hidden attribute should only appear in the adapted attribute.
80
+ * Has no effect when added to the "main" attribute.
81
+ */
82
+ hidden?: boolean;
75
83
  /**
76
84
  * Whether this property is deprecated.
77
85
  */
@@ -94,16 +102,30 @@ export interface IDataProperty {
94
102
  * a derivative entity for specific schema to describe specific schema case.
95
103
  */
96
104
  type: DataPropertyType;
97
-
98
105
  /**
99
- * While the `DataProperty` describes the general shape of the data and can be used to
100
- * model the structure of the data in the system, a schema describes hwo the data
101
- * should be serialized into a specific format. This allows adding example values,
102
- * default values, specifying data format, etc. The assumption here is
103
- * that with enough specifics provided by the user (a domain specialist)
104
- * we can automatically generate a schema for the given format.
106
+ * The general schema definition of this property.
107
+ * This is propagated to all bindings (when they support these properties).
108
+ *
109
+ * Note, schema can only occur on an adapted property. Has no effect on the "main"
110
+ * property.
111
+ */
112
+ schema?: IPropertySchema;
113
+ /**
114
+ * The list of bindings for this property.
115
+ *
116
+ * A binding defines a translation from a data model to a specific format.
117
+ * For example allows to define properties required to generate AMF shape and therefore RAML/OAS shapes for web APIs
118
+ * or a protocol buffer schema.
119
+ */
120
+ bindings?: IPropertyBindings[];
121
+ /**
122
+ * The key of the property that is adapted by this property.
123
+ * Adapted properties can manipulate the shape of the schema for the property.
124
+ *
125
+ * Each value defined on the adapted property changes the original value defined on
126
+ * the property.
105
127
  */
106
- schemas?: IPropertySchema<unknown>[];
128
+ adapts?: string;
107
129
  }
108
130
 
109
131
  export class DataProperty {
@@ -136,6 +158,23 @@ export class DataProperty {
136
158
  */
137
159
  index?: boolean;
138
160
 
161
+ /**
162
+ * Whether the property is read only in the schema.
163
+ */
164
+ readOnly?: boolean;
165
+
166
+ /**
167
+ * Whether the property is write only in the schema.
168
+ */
169
+ writeOnly?: boolean;
170
+
171
+ /**
172
+ * Whether the attribute is hidden in the schema (not a part of it).
173
+ * The hidden attribute should only appear in the adapted attribute.
174
+ * Has no effect when added to the "main" attribute.
175
+ */
176
+ hidden?: boolean;
177
+
139
178
  /**
140
179
  * Whether this property is deprecated.
141
180
  */
@@ -165,14 +204,30 @@ export class DataProperty {
165
204
  type: DataPropertyType = 'string';
166
205
 
167
206
  /**
168
- * While the `DataProperty` describes the general shape of the data and can be used to
169
- * model the structure of the data in the system, a schema describes hwo the data
170
- * should be serialized into a specific format. This allows adding example values,
171
- * default values, specifying data format, etc. The assumption here is
172
- * that with enough specifics provided by the user (a domain specialist)
173
- * we can automatically generate a schema for the given format.
207
+ * The general schema definition of this property.
208
+ * This is propagated to all bindings (when they support these properties).
209
+ *
210
+ * Note, schema can only occur on an adapted property. Has no effect on the "main"
211
+ * property.
212
+ */
213
+ schema?: IPropertySchema;
214
+ /**
215
+ * The list of bindings for this property.
216
+ *
217
+ * A binding defines a translation from a data model to a specific format.
218
+ * For example allows to define properties required to generate AMF shape and therefore RAML/OAS shapes for web APIs
219
+ * or a protocol buffer schema.
220
+ */
221
+ bindings: IPropertyBindings[] = [];
222
+
223
+ /**
224
+ * The key of the property that is adapted by this property.
225
+ * Adapted properties can manipulate the shape of the schema for the property.
226
+ *
227
+ * Each value defined on the adapted property changes the original value defined on
228
+ * the property.
174
229
  */
175
- schemas: IPropertySchema<unknown>[] = [];
230
+ adapts?: string;
176
231
 
177
232
  static get supportedTypes(): DataPropertyType[] {
178
233
  return [...DataPropertyTypes];
@@ -193,7 +248,7 @@ export class DataProperty {
193
248
  /**
194
249
  * @param input The data property definition to restore.
195
250
  */
196
- constructor(protected root: DataNamespace, input?: string | IDataProperty) {
251
+ constructor(public root: DataNamespace, input?: string | IDataProperty) {
197
252
  let init: IDataProperty;
198
253
  if (typeof input === 'string') {
199
254
  init = JSON.parse(input);
@@ -214,7 +269,11 @@ export class DataProperty {
214
269
  if (!DataProperty.isDataProperty(init)) {
215
270
  throw new Error(`Not a data property.`);
216
271
  }
217
- const { info, key = v4(), kind = Kind, multiple, required, type = DataPropertyList.string, index, primary, tags, taxonomy, schemas, deprecated } = init;
272
+ const {
273
+ info, key = v4(), kind = Kind, multiple, required, type = DataPropertyList.string,
274
+ index, primary, readOnly, writeOnly, adapts, hidden, tags, taxonomy, deprecated,
275
+ schema, bindings,
276
+ } = init;
218
277
  this.kind = kind;
219
278
  this.key = key;
220
279
  this.type = type;
@@ -248,6 +307,26 @@ export class DataProperty {
248
307
  } else {
249
308
  this.primary = undefined;
250
309
  }
310
+ if (typeof readOnly === 'boolean') {
311
+ this.readOnly = readOnly;
312
+ } else {
313
+ this.readOnly = undefined;
314
+ }
315
+ if (typeof writeOnly === 'boolean') {
316
+ this.writeOnly = writeOnly;
317
+ } else {
318
+ this.writeOnly = undefined;
319
+ }
320
+ if (typeof hidden === 'boolean') {
321
+ this.hidden = hidden;
322
+ } else {
323
+ this.hidden = undefined;
324
+ }
325
+ if (typeof adapts === 'string') {
326
+ this.adapts = adapts;
327
+ } else {
328
+ this.adapts = undefined;
329
+ }
251
330
  if (Array.isArray(tags)) {
252
331
  this.tags = [...tags];
253
332
  } else {
@@ -258,10 +337,15 @@ export class DataProperty {
258
337
  } else {
259
338
  this.taxonomy = [];
260
339
  }
261
- if (Array.isArray(schemas)) {
262
- this.schemas = schemas.map(i => ({ ...i }));
340
+ if (schema) {
341
+ this.schema = JsonCore.clone(schema);
342
+ } else {
343
+ this.schema = undefined;
344
+ }
345
+ if (Array.isArray(bindings)) {
346
+ this.bindings = bindings.map(i => JsonCore.clone(i));
263
347
  } else {
264
- this.schemas = [];
348
+ this.bindings = [];
265
349
  }
266
350
  }
267
351
 
@@ -295,14 +379,29 @@ export class DataProperty {
295
379
  if (typeof this.required === 'boolean') {
296
380
  result.required = this.required;
297
381
  }
382
+ if (typeof this.readOnly === 'boolean') {
383
+ result.readOnly = this.readOnly;
384
+ }
385
+ if (typeof this.writeOnly === 'boolean') {
386
+ result.writeOnly = this.writeOnly;
387
+ }
388
+ if (typeof this.hidden === 'boolean') {
389
+ result.hidden = this.hidden;
390
+ }
391
+ if (this.adapts) {
392
+ result.adapts = this.adapts;
393
+ }
298
394
  if (Array.isArray(this.tags) && this.tags.length) {
299
395
  result.tags = [...this.tags];
300
396
  }
301
397
  if (Array.isArray(this.taxonomy) && this.taxonomy.length) {
302
398
  result.taxonomy = [...this.taxonomy];
303
399
  }
304
- if (Array.isArray(this.schemas) && this.schemas.length) {
305
- result.schemas = this.schemas.map(i => ({ ...i }));
400
+ if (this.schema) {
401
+ result.schema = JsonCore.clone(this.schema);
402
+ }
403
+ if (Array.isArray(this.bindings) && this.bindings.length) {
404
+ result.taxonomy = this.taxonomy.map(i => JsonCore.clone(i));
306
405
  }
307
406
  return result;
308
407
  }
@@ -311,7 +410,7 @@ export class DataProperty {
311
410
  * Removes self from the parent entity and the namespace definition.
312
411
  */
313
412
  remove(): void {
314
- const { root } = this;
413
+ const { root, adapts } = this;
315
414
  const entity = root.definitions.entities.find(i => i.properties.some(j => j === this));
316
415
  if (entity) {
317
416
  const assocIndex = entity.properties.findIndex(i => i === this);
@@ -321,6 +420,12 @@ export class DataProperty {
321
420
  if (defIndex >= 0) {
322
421
  this.root.definitions.properties.splice(defIndex, 1);
323
422
  }
423
+ if (adapts) {
424
+ const adaptsIndex = this.root.definitions.properties.findIndex(i => i.key === adapts);
425
+ if (adaptsIndex >= 0) {
426
+ this.root.definitions.properties.splice(adaptsIndex, 1);
427
+ }
428
+ }
324
429
  }
325
430
 
326
431
  /**
@@ -362,4 +467,43 @@ export class DataProperty {
362
467
  tags.splice(index, 1);
363
468
  }
364
469
  }
470
+
471
+ /**
472
+ * Creates a Property Shape of AMF.
473
+ * The property itself is auto-generated. If the `schema` is defined then it is used
474
+ * as the `range` of the property. Otherwise basic shape is generated for the range.
475
+ *
476
+ * This is a preferred way of reading the AMF shape as this synchronizes changed
477
+ * data properties with the shape definition.
478
+ *
479
+ * @returns AMF property shape definition.
480
+ */
481
+ toApiShape(): IPropertyShape {
482
+ const serializer = new AmfShapeGenerator();
483
+ return serializer.property(this);
484
+ }
485
+
486
+ /**
487
+ * @returns The adapted property, if any
488
+ */
489
+ readAdapted(): DataProperty | undefined {
490
+ const { adapts } = this;
491
+ if (!adapts) {
492
+ return undefined;
493
+ }
494
+ return this.root.definitions.properties.find(i => i.key === adapts);
495
+ }
496
+
497
+ /**
498
+ * Creates new adapted property and associates it with this property.
499
+ * @returns The instance of the created property.
500
+ */
501
+ createAdapted(): DataProperty {
502
+ const property = new DataProperty(this.root);
503
+ // disallow defaults as this would influence the schema generation
504
+ property.info.name = undefined;
505
+ this.root.definitions.properties.push(property);
506
+ this.adapts = property.key;
507
+ return property;
508
+ }
365
509
  }