gingersnap 0.23.11 → 0.23.13

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.
@@ -52,14 +52,9 @@ class Optional {
52
52
  * A Data de/serializer class that manages and validates data as JavaScript Objects
53
53
  */
54
54
  class Model {
55
- /**
56
- * Converts arraybuffer to a model
57
- * @param data arraybuffer
58
- * @param format data format
59
- * @param options configurations for deserializing the data
60
- * @returns new model or an array of models
61
- */
62
- static fromBuffer(data, format = DataFormat.JSON, options) {
55
+ static fromBuffer(data, options) {
56
+ var _a;
57
+ const format = (_a = options === null || options === void 0 ? void 0 : options.format) !== null && _a !== void 0 ? _a : DataFormat.JSON;
63
58
  switch (format) {
64
59
  case DataFormat.MESSAGE_PACK: {
65
60
  const decoder = decode;
@@ -68,27 +63,18 @@ class Model {
68
63
  throw new ParsingError([], "expected an array of models");
69
64
  if ((!(options === null || options === void 0 ? void 0 : options.array) && result instanceof Array) || Array.isArray(result))
70
65
  throw new ParsingError([], "expected only one model");
71
- if (result instanceof Array || Array.isArray(result))
72
- return result.map((v) => this.fromJSON(v));
73
- return this.fromJSON(result);
66
+ return this.fromJSON(result, { array: options === null || options === void 0 ? void 0 : options.array, maybeArray: options === null || options === void 0 ? void 0 : options.maybeArray });
74
67
  }
75
68
  case DataFormat.CSV: {
76
69
  const text = data instanceof Uint8Array ? new TextDecoder().decode(data.buffer) : data.toString();
77
- return this.fromString(text, format, options);
70
+ return this.fromString(text, options);
78
71
  }
79
72
  case DataFormat.XML:
80
73
  case DataFormat.JSON:
81
- return this.fromString(data instanceof Uint8Array ? new TextDecoder().decode(data) : data.toString(), format, options);
74
+ return this.fromString(data instanceof Uint8Array ? new TextDecoder().decode(data) : data.toString(), options);
82
75
  }
83
76
  }
84
- /**
85
- * Downloads data from the given source and deserializes the data to one or more models
86
- * @param source URL source to fetch the data
87
- * @param format data format
88
- * @param options configurations for deserializing and/or retrieving the data
89
- * @returns one or more models
90
- */
91
- static fromURL(source, format = DataFormat.JSON, options) {
77
+ static fromURL(source, options) {
92
78
  return __awaiter(this, void 0, void 0, function* () {
93
79
  const fetcher = fetch;
94
80
  const resp = yield fetcher(source, {
@@ -98,48 +84,37 @@ class Model {
98
84
  });
99
85
  if (!resp.ok)
100
86
  throw new NetworkError(resp.status);
101
- return yield this.fromBlob(yield resp.blob(), format, options);
87
+ return yield this.fromBlob(yield resp.blob(), options);
102
88
  });
103
89
  }
104
- /**
105
- * Deserializes one or more models from a Blob
106
- * @param data blob data
107
- * @param format data format
108
- * @param options configurations for deserializing the data
109
- * @returns one or more models
110
- */
111
- static fromBlob(data, format = DataFormat.JSON, options) {
90
+ static fromBlob(data, options) {
112
91
  return __awaiter(this, void 0, void 0, function* () {
113
- return this.fromBuffer(new Uint8Array(yield data.arrayBuffer()), format);
92
+ return this.fromBuffer(new Uint8Array(yield data.arrayBuffer()), options);
114
93
  });
115
94
  }
116
- /**
117
- * Deserializes one or more models from given string
118
- *
119
- * @remarks
120
- * If the data format is a binary one, the provided string should be a hexadecimal string.
121
- * @param data string data source
122
- * @param format data format
123
- * @param options
124
- */
125
- static fromString(data, format = DataFormat.JSON, options) {
126
- var _a, _b, _c, _d, _e, _f;
95
+ static fromString(data, options) {
96
+ var _a, _b, _c, _d, _e, _f, _g;
97
+ const format = (_a = options === null || options === void 0 ? void 0 : options.format) !== null && _a !== void 0 ? _a : DataFormat.JSON;
127
98
  switch (format) {
128
99
  case DataFormat.JSON:
129
100
  try {
130
101
  data = JSON.parse(data);
131
102
  }
132
103
  catch (e) {
133
- throw new ParsingError((_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : String(e));
104
+ throw new ParsingError((_b = e === null || e === void 0 ? void 0 : e.message) !== null && _b !== void 0 ? _b : String(e));
134
105
  }
135
- return this.fromJSON(data);
106
+ return this.fromJSON(data, { maybeArray: options === null || options === void 0 ? void 0 : options.maybeArray, array: options === null || options === void 0 ? void 0 : options.array });
136
107
  case DataFormat.XML:
137
- return this.fromObject(this.__xmlParser__.xml2js(data), format);
108
+ return this.fromObject(this.__xmlParser__.xml2js(data), {
109
+ format,
110
+ maybeArray: options === null || options === void 0 ? void 0 : options.maybeArray,
111
+ array: options === null || options === void 0 ? void 0 : options.array,
112
+ });
138
113
  case DataFormat.CSV: {
139
114
  let result;
140
115
  let text = data;
141
116
  if (options === null || options === void 0 ? void 0 : options.headers)
142
- text = options.headers.join((_b = options === null || options === void 0 ? void 0 : options.delimiter) !== null && _b !== void 0 ? _b : ",") + ((_c = options.newline) !== null && _c !== void 0 ? _c : "\n") + text;
117
+ text = options.headers.join((_c = options === null || options === void 0 ? void 0 : options.delimiter) !== null && _c !== void 0 ? _c : ",") + ((_d = options.newline) !== null && _d !== void 0 ? _d : "\n") + text;
143
118
  try {
144
119
  result = Papa.parse(text, {
145
120
  header: true,
@@ -147,36 +122,34 @@ class Model {
147
122
  });
148
123
  }
149
124
  catch (e) {
150
- throw new ParsingError([], (_d = e === null || e === void 0 ? void 0 : e.message) !== null && _d !== void 0 ? _d : String(e));
125
+ throw new ParsingError([], (_e = e === null || e === void 0 ? void 0 : e.message) !== null && _e !== void 0 ? _e : String(e));
151
126
  }
152
127
  if (!(options === null || options === void 0 ? void 0 : options.ignoreErrors) && result.errors.length > 0)
153
128
  throw new ParsingError(result.errors);
154
129
  if (!(options === null || options === void 0 ? void 0 : options.array) && result.data.length > 0)
155
130
  throw new ParsingError([], "Too many records found");
156
- if (options === null || options === void 0 ? void 0 : options.array)
157
- return result.data.map((v) => this.fromObject(v));
158
- return this.fromObject(result.data[0]);
131
+ if ((options === null || options === void 0 ? void 0 : options.array) || (options === null || options === void 0 ? void 0 : options.maybeArray))
132
+ return this.fromObject(result.data, { array: true });
133
+ if (!(options === null || options === void 0 ? void 0 : options.maybeArray) || (options.maybeArray && result.data.length === 1))
134
+ return this.fromObject(result.data[0]);
135
+ break;
159
136
  }
160
137
  default:
161
- return this.fromBuffer(new Uint8Array((_f = (_e = data.match(/../g)) === null || _e === void 0 ? void 0 : _e.map((h) => parseInt(h, 16))) !== null && _f !== void 0 ? _f : []), format, options);
138
+ return this.fromBuffer(new Uint8Array((_g = (_f = data.match(/../g)) === null || _f === void 0 ? void 0 : _f.map((h) => parseInt(h, 16))) !== null && _g !== void 0 ? _g : []), options);
162
139
  }
163
140
  }
164
- /**
165
- * Converts a JSON object to a model
166
- * @param data JSON Object
167
- * @returns new model
168
- */
169
- static fromJSON(data) {
170
- return this.fromObject(data, DataFormat.JSON);
141
+ static fromJSON(data, options) {
142
+ return this.fromObject(data, options);
171
143
  }
172
144
  /**
173
145
  * Converts the current model to a JSON object
174
146
  */
175
- object(removeMissingFields = false) {
147
+ object(options) {
176
148
  var _a, _b;
149
+ const { removeMissingFields = false, keepOptionals = true } = options || {};
177
150
  const serialize = (value) => {
178
151
  if (value instanceof Model) {
179
- return value.object(removeMissingFields);
152
+ return value.object({ removeMissingFields, keepOptionals });
180
153
  }
181
154
  else if (value instanceof Array || Array.isArray(value)) {
182
155
  return value.map((v) => serialize(v));
@@ -196,6 +169,13 @@ class Model {
196
169
  else if (value instanceof Function) {
197
170
  return null;
198
171
  }
172
+ else if (value instanceof Optional) {
173
+ if (keepOptionals)
174
+ return value;
175
+ if (value.isPresent())
176
+ return value.get();
177
+ return null;
178
+ }
199
179
  return value;
200
180
  };
201
181
  return R.reduce((acc, [key, fieldProps]) => {
@@ -213,42 +193,42 @@ class Model {
213
193
  /**
214
194
  * Converts the current model to a JSON string
215
195
  */
216
- json(removeMissingFields = false) {
217
- return JSON.stringify(this.object(removeMissingFields));
196
+ json(options) {
197
+ return JSON.stringify(this.object(options));
218
198
  }
219
199
  /**
220
200
  * Converts the current model to an arraybuffer
221
201
  */
222
- buffer(removeMissingFields = false) {
223
- return new TextEncoder().encode(this.json(removeMissingFields));
202
+ buffer(options) {
203
+ return new TextEncoder().encode(this.json(options));
224
204
  }
225
205
  /**
226
206
  * Converts the current model to a blob
227
207
  */
228
- blob(removeMissingFields = false) {
229
- return new Blob([this.buffer(removeMissingFields)]);
208
+ blob(options) {
209
+ return new Blob([this.buffer(options)]);
230
210
  }
231
211
  /**
232
212
  * Converts the current model to an XML string
233
213
  */
234
- xml(removeMissingFields = false) {
235
- return Model.__xmlParser__.js2xml(this.object(removeMissingFields));
214
+ xml(options) {
215
+ return Model.__xmlParser__.js2xml(this.object(options));
236
216
  }
237
217
  /**
238
218
  * Converts the current model to message pack binary format
239
219
  * @returns message pack binary
240
220
  */
241
- messagePack(removeMissingFields = false) {
242
- return encode(this.object(removeMissingFields)).buffer;
221
+ messagePack(options) {
222
+ return encode(this.object(options)).buffer;
243
223
  }
244
224
  /**
245
225
  * Converts the current model to csv format
246
- * @param removeMissingFields
226
+ * @param options
247
227
  * @param config CSV unparsing configuration
248
228
  * @returns csv string
249
229
  */
250
- csv(removeMissingFields = false, config) {
251
- return Papa.unparse([this.object(removeMissingFields)], config);
230
+ csv(options, config) {
231
+ return Papa.unparse([this.object(options)], config);
252
232
  }
253
233
  clone() {
254
234
  const newModel = new (Object.getPrototypeOf(this))();
@@ -259,10 +239,10 @@ class Model {
259
239
  }
260
240
  /**
261
241
  * Retrieves the schema of the current model based on the selected format
262
- * @param format data format
242
+ * @param includeTitleAndDraft boolean whether the title and JSON schema draft version should be referenced in the schema
263
243
  * @returns the schema for the current model
264
244
  */
265
- static schema(addTitleAndDraftRef = true) {
245
+ static schema(includeTitleAndDraft = true) {
266
246
  const model = new this();
267
247
  const props = this.buildPropTree(Object.getPrototypeOf(model));
268
248
  const handleArrays = (v, entry) => {
@@ -354,24 +334,38 @@ class Model {
354
334
  }
355
335
  return entry;
356
336
  }));
357
- if (addTitleAndDraftRef)
358
- return {
359
- $schema: "https://json-schema.org/draft/2020-12/schema",
360
- title: this.name,
337
+ const fieldEntries = Array.from(props.fields.entries());
338
+ const optionals = Object.getOwnPropertyNames(this.prototype)
339
+ .filter((key) => key !== "constructor")
340
+ .map((key) => [key, model[key]])
341
+ .map(([key, modelValue]) => ({
342
+ modelValue,
343
+ fieldProps: fieldEntries.find(([k, v]) => { var _a; return k === key || ((_a = v.aliases) === null || _a === void 0 ? void 0 : _a.includes(key)); }),
344
+ }))
345
+ .filter(({ modelValue, fieldProps }) => { var _a, _b, _c; return modelValue !== undefined || ((_b = (_a = fieldProps[1].schema) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b.optional) || ((_c = fieldProps[1].ignore) === null || _c === void 0 ? void 0 : _c.deserialize); })
346
+ .map(({ fieldProps }) => fieldProps[0]);
347
+ const required = fieldEntries.filter(([k]) => !optionals.includes(k)).map(([k]) => k);
348
+ const result = required.length
349
+ ? {
361
350
  type: "object",
362
351
  properties: generateProperties(),
363
352
  additionalProperties: false,
364
- };
365
- else {
366
- return {
353
+ required,
354
+ }
355
+ : {
367
356
  type: "object",
368
357
  properties: generateProperties(),
369
358
  additionalProperties: false,
370
359
  };
360
+ if (includeTitleAndDraft) {
361
+ return Object.assign(Object.assign({}, result), { $schema: "https://json-schema.org/draft/2020-12/schema", title: this.name });
362
+ }
363
+ else {
364
+ return result;
371
365
  }
372
366
  }
373
367
  toString() {
374
- return this.json(true);
368
+ return this.json({ removeMissingFields: true, keepOptionals: false });
375
369
  }
376
370
  /**
377
371
  * Constructs the model properties by traversing the inheritance tree of the current Model being instantiated
@@ -400,15 +394,17 @@ class Model {
400
394
  }
401
395
  return tree;
402
396
  }
403
- /**
404
- * Constructs a model from a JSON object
405
- * @param data JSON object
406
- * @param format
407
- * @private
408
- */
409
- static fromObject(data, format = DataFormat.JSON) {
410
- if (data instanceof Array || Array.isArray(data) || typeof data !== "object") {
411
- throw new ParsingError([], "Invalid data provided. Must be an object");
397
+ static fromObject(data, options) {
398
+ var _a;
399
+ const format = (_a = options === null || options === void 0 ? void 0 : options.format) !== null && _a !== void 0 ? _a : DataFormat.JSON;
400
+ if (Array.isArray(data)) {
401
+ if (!(options === null || options === void 0 ? void 0 : options.array) || !(options === null || options === void 0 ? void 0 : options.maybeArray))
402
+ throw new ParsingError([], "Invalid data provided. Must be an object");
403
+ else
404
+ return data.map((item) => this.fromObject(item, { format }));
405
+ }
406
+ else if (options === null || options === void 0 ? void 0 : options.array) {
407
+ throw new ParsingError([], "Invalid data provided. Must be an array of objects");
412
408
  }
413
409
  const processValue = (fieldProps, value) => {
414
410
  var _a, _b;
@@ -420,7 +416,7 @@ class Model {
420
416
  const model = new this();
421
417
  const props = this.buildPropTree(Object.getPrototypeOf(model));
422
418
  R.forEach(([key, fieldProps]) => {
423
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
419
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
424
420
  let value = data[key];
425
421
  if (value === undefined || value === null) {
426
422
  for (const alias of (_a = fieldProps.aliases) !== null && _a !== void 0 ? _a : []) {
@@ -441,12 +437,101 @@ class Model {
441
437
  else if ((value === undefined || value === null) && !(model[key] === undefined || model[key] === null)) {
442
438
  return;
443
439
  }
440
+ const checkOtherTypes = (value, Type, fallback) => {
441
+ var _a, _b;
442
+ if ((Type === null || Type === void 0 ? void 0 : Type.name) === "String") {
443
+ return processValue(fieldProps, String(value));
444
+ }
445
+ else if ((Type === null || Type === void 0 ? void 0 : Type.name) === "Boolean") {
446
+ return processValue(fieldProps, Boolean(value));
447
+ }
448
+ else if ((Type === null || Type === void 0 ? void 0 : Type.name) === "Number") {
449
+ const v = Number(value);
450
+ if (isNaN(v))
451
+ throw new ParsingError([], `value for ${key} is not a valid number`);
452
+ return processValue(fieldProps, v);
453
+ }
454
+ else if ((Type === null || Type === void 0 ? void 0 : Type.name) === "Map") {
455
+ const valueType = typeof value;
456
+ switch (valueType) {
457
+ case "object": {
458
+ try {
459
+ return processValue(fieldProps, value instanceof Array || Array.isArray(value) ? new Map(value) : new Map(Object.entries(value)));
460
+ }
461
+ catch (e) {
462
+ throw new ParsingError([], (_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : String(e));
463
+ }
464
+ }
465
+ case "string":
466
+ try {
467
+ value = JSON.parse(value);
468
+ return processValue(fieldProps, value instanceof Array || Array.isArray(value) ? new Map(value) : new Map(Object.entries(value)));
469
+ }
470
+ catch (e) {
471
+ throw new ParsingError([], (_b = e === null || e === void 0 ? void 0 : e.message) !== null && _b !== void 0 ? _b : String(e));
472
+ }
473
+ default:
474
+ throw new ParsingError([value], `value for ${key} cannot be converted to a Map`);
475
+ }
476
+ }
477
+ else if ((Type === null || Type === void 0 ? void 0 : Type.name) === "Set") {
478
+ if (value instanceof Array || Array.isArray(value)) {
479
+ return processValue(fieldProps, new Set(value));
480
+ }
481
+ else if (typeof value === "string") {
482
+ return processValue(fieldProps, new Set(JSON.parse(value)));
483
+ }
484
+ throw new ParsingError([value], `value for ${key} cannot be converted to a Set`);
485
+ }
486
+ else {
487
+ return fallback();
488
+ }
489
+ };
490
+ function processUnionField(value) {
491
+ let foundMatch = false;
492
+ let result;
493
+ for (const unionType of fieldProps.unionTypes) {
494
+ try {
495
+ result = checkOtherTypes(value, unionType, () => {
496
+ if (unionType.prototype instanceof Model) {
497
+ const parser = parse({
498
+ string: (v) => unionType.fromString(v, format),
499
+ object: (v) => unionType.fromObject(v, format),
500
+ default: () => {
501
+ throw new ParsingError([], `value for ${key} is expected to be an Array, instead received ${typeof value}`);
502
+ },
503
+ supportArray: true,
504
+ });
505
+ return processValue(fieldProps, parser(value));
506
+ }
507
+ throw new ParsingError([], `value for ${key} type is unsupported ${typeof value}`);
508
+ });
509
+ foundMatch = true;
510
+ break;
511
+ }
512
+ catch (e) { }
513
+ }
514
+ if (!foundMatch) {
515
+ throw new ParsingError([], `value for ${key} does not match any of the union types expected`);
516
+ }
517
+ return result;
518
+ }
444
519
  if ((_e = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(model), key)) === null || _e === void 0 ? void 0 : _e.set) {
445
520
  model[key] = processValue(fieldProps, value);
446
521
  }
447
522
  else if ((_f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(model), key)) === null || _f === void 0 ? void 0 : _f.get) {
448
523
  return;
449
524
  }
525
+ else if (fieldProps.isUnion) {
526
+ if (!fieldProps.isArray) {
527
+ model[key] = processUnionField(value);
528
+ }
529
+ else if (fieldProps.isArray && Array.isArray(value)) {
530
+ model[key] = value.map((item) => processUnionField(item));
531
+ }
532
+ else
533
+ throw new ParsingError([], `value for ${key} is expected to be an array`);
534
+ }
450
535
  else if (model[key] instanceof fieldProps.Type &&
451
536
  typeof model[key] === "function" &&
452
537
  fieldProps.Type instanceof Function) {
@@ -556,51 +641,8 @@ class Model {
556
641
  }
557
642
  }));
558
643
  }
559
- else if (((_k = fieldProps.Type) === null || _k === void 0 ? void 0 : _k.name) === "String") {
560
- model[key] = processValue(fieldProps, String(value));
561
- }
562
- else if (((_l = fieldProps.Type) === null || _l === void 0 ? void 0 : _l.name) === "Boolean") {
563
- model[key] = processValue(fieldProps, Boolean(value));
564
- }
565
- else if (((_m = fieldProps.Type) === null || _m === void 0 ? void 0 : _m.name) === "Number") {
566
- model[key] = processValue(fieldProps, Number(value));
567
- }
568
- else if (((_o = fieldProps.Type) === null || _o === void 0 ? void 0 : _o.name) === "Map") {
569
- const valueType = typeof value;
570
- switch (valueType) {
571
- case "object": {
572
- try {
573
- model[key] = processValue(fieldProps, value instanceof Array || Array.isArray(value) ? new Map(value) : new Map(Object.entries(value)));
574
- }
575
- catch (e) {
576
- throw new ParsingError([], (_p = e === null || e === void 0 ? void 0 : e.message) !== null && _p !== void 0 ? _p : String(e));
577
- }
578
- break;
579
- }
580
- case "string":
581
- try {
582
- value = JSON.parse(value);
583
- model[key] = processValue(fieldProps, value instanceof Array || Array.isArray(value) ? new Map(value) : new Map(Object.entries(value)));
584
- }
585
- catch (e) {
586
- throw new ParsingError([], (_q = e === null || e === void 0 ? void 0 : e.message) !== null && _q !== void 0 ? _q : String(e));
587
- }
588
- break;
589
- default:
590
- throw new ParsingError([value], `value for ${key} cannot be converted to a Map`);
591
- }
592
- }
593
- else if (((_r = fieldProps.Type) === null || _r === void 0 ? void 0 : _r.name) === "Set") {
594
- if (value instanceof Array || Array.isArray(value)) {
595
- model[key] = processValue(fieldProps, new Set(value));
596
- }
597
- else if (typeof value === "string") {
598
- model[key] = processValue(fieldProps, new Set(JSON.parse(value)));
599
- }
600
- throw new ParsingError([value], `value for ${key} cannot be converted to a Set`);
601
- }
602
644
  else {
603
- model[key] = processValue(fieldProps, new fieldProps.Type(value));
645
+ model[key] = checkOtherTypes(value, fieldProps.Type, () => processValue(fieldProps, new fieldProps.Type(value)));
604
646
  }
605
647
  if (fieldProps.readonly) {
606
648
  Object.defineProperty(model, key, {
@@ -612,7 +654,7 @@ class Model {
612
654
  R.forEach(([k, v]) => {
613
655
  if (v.__callback__)
614
656
  v.__callback__(k, v.properties, model, key);
615
- }, R.toPairs((_s = fieldProps.customTags) !== null && _s !== void 0 ? _s : {}));
657
+ }, R.toPairs((_k = fieldProps.customTags) !== null && _k !== void 0 ? _k : {}));
616
658
  }, Array.from(props.fields.entries()));
617
659
  return Object.seal(model);
618
660
  }
@@ -129,6 +129,31 @@ const Field = (name, type = undefined) => (target, key) => {
129
129
  props.parent = Object.getPrototypeOf(target).constructor.name;
130
130
  model.namespacedModelInternalProps.set(target.constructor.name, props);
131
131
  };
132
+ const UnionField = (types, name) => (target, key) => {
133
+ var _a, _b, _c;
134
+ const schema = {};
135
+ const props = (_a = model.namespacedModelInternalProps.get(target.constructor.name)) !== null && _a !== void 0 ? _a : {
136
+ fields: new Map(),
137
+ };
138
+ schema.description = (_b = name === null || name === void 0 ? void 0 : name.description) !== null && _b !== void 0 ? _b : "";
139
+ const fieldProp = (_c = props.fields.get(key)) !== null && _c !== void 0 ? _c : {};
140
+ fieldProp.name = typeof name === "string" ? name : typeof name === "object" ? name.name : key;
141
+ fieldProp.isUnion = true;
142
+ fieldProp.schema = schema;
143
+ fieldProp.unionTypes = types;
144
+ fieldProp.Type = {};
145
+ props.fields.set(key, fieldProp);
146
+ if (typeof name === "string" && name) {
147
+ if (fieldProp.aliases) {
148
+ fieldProp.aliases.push(name);
149
+ }
150
+ else {
151
+ fieldProp.aliases = [name];
152
+ }
153
+ }
154
+ props.parent = Object.getPrototypeOf(target).constructor.name;
155
+ model.namespacedModelInternalProps.set(target.constructor.name, props);
156
+ };
132
157
  /**
133
158
  * A property that exists on the incoming data, that contains an array of same data types
134
159
  * @param type Type of data in the array
@@ -144,8 +169,9 @@ const ArrayField = (type, name) => (target, key) => {
144
169
  const schema = { dataType: types.DataType.ARRAY };
145
170
  const dtype = Reflect.getMetadata("design:type", target, key);
146
171
  const optional = dtype === model.Optional;
172
+ const fieldProp = (_b = props.fields.get(key)) !== null && _b !== void 0 ? _b : {};
147
173
  schema.options = { useOptionalObj: optional, optional };
148
- schema.description = (_b = name === null || name === void 0 ? void 0 : name.description) !== null && _b !== void 0 ? _b : "";
174
+ schema.description = (_c = name === null || name === void 0 ? void 0 : name.description) !== null && _c !== void 0 ? _c : "";
149
175
  if (type instanceof Number) {
150
176
  schema.itemType = types.DataType.DOUBLE;
151
177
  }
@@ -158,7 +184,10 @@ const ArrayField = (type, name) => (target, key) => {
158
184
  else if (type instanceof model.Model) {
159
185
  schema.options.recordClass = type;
160
186
  }
161
- const fieldProp = (_c = props.fields.get(key)) !== null && _c !== void 0 ? _c : {};
187
+ else if (Array.isArray(type)) {
188
+ fieldProp.isUnion = true;
189
+ fieldProp.unionTypes = type;
190
+ }
162
191
  fieldProp.name = key;
163
192
  fieldProp.Type = type;
164
193
  fieldProp.isArray = true;
@@ -310,5 +339,6 @@ exports.RaiseError = RaiseError;
310
339
  exports.Range = Range;
311
340
  exports.Readonly = Readonly;
312
341
  exports.SchemaType = SchemaType;
342
+ exports.UnionField = UnionField;
313
343
  exports.UpperBound = UpperBound;
314
344
  exports.Validator = Validator;
@@ -11,6 +11,10 @@ export declare const Field: (name?: string | {
11
11
  name: string;
12
12
  description: string;
13
13
  }, type?: any) => (target: any, key: string) => void;
14
+ export declare const UnionField: (types: any[], name?: string | {
15
+ name: string;
16
+ description: string;
17
+ }) => (target: any, key: string) => void;
14
18
  /**
15
19
  * A property that exists on the incoming data, that contains an array of same data types
16
20
  * @param type Type of data in the array
@@ -18,7 +22,7 @@ export declare const Field: (name?: string | {
18
22
  * property name
19
23
  * @constructor
20
24
  */
21
- export declare const ArrayField: (type: any, name?: string | {
25
+ export declare const ArrayField: (type: any | any[], name?: string | {
22
26
  name: string;
23
27
  description: string;
24
28
  }) => (target: any, key: string) => void;
@@ -108,6 +108,31 @@ const Field = (name, type = undefined) => (target, key) => {
108
108
  props.parent = Object.getPrototypeOf(target).constructor.name;
109
109
  namespacedModelInternalProps.set(target.constructor.name, props);
110
110
  };
111
+ const UnionField = (types, name) => (target, key) => {
112
+ var _a, _b, _c;
113
+ const schema = {};
114
+ const props = (_a = namespacedModelInternalProps.get(target.constructor.name)) !== null && _a !== void 0 ? _a : {
115
+ fields: new Map(),
116
+ };
117
+ schema.description = (_b = name === null || name === void 0 ? void 0 : name.description) !== null && _b !== void 0 ? _b : "";
118
+ const fieldProp = (_c = props.fields.get(key)) !== null && _c !== void 0 ? _c : {};
119
+ fieldProp.name = typeof name === "string" ? name : typeof name === "object" ? name.name : key;
120
+ fieldProp.isUnion = true;
121
+ fieldProp.schema = schema;
122
+ fieldProp.unionTypes = types;
123
+ fieldProp.Type = {};
124
+ props.fields.set(key, fieldProp);
125
+ if (typeof name === "string" && name) {
126
+ if (fieldProp.aliases) {
127
+ fieldProp.aliases.push(name);
128
+ }
129
+ else {
130
+ fieldProp.aliases = [name];
131
+ }
132
+ }
133
+ props.parent = Object.getPrototypeOf(target).constructor.name;
134
+ namespacedModelInternalProps.set(target.constructor.name, props);
135
+ };
111
136
  /**
112
137
  * A property that exists on the incoming data, that contains an array of same data types
113
138
  * @param type Type of data in the array
@@ -123,8 +148,9 @@ const ArrayField = (type, name) => (target, key) => {
123
148
  const schema = { dataType: DataType.ARRAY };
124
149
  const dtype = Reflect.getMetadata("design:type", target, key);
125
150
  const optional = dtype === Optional;
151
+ const fieldProp = (_b = props.fields.get(key)) !== null && _b !== void 0 ? _b : {};
126
152
  schema.options = { useOptionalObj: optional, optional };
127
- schema.description = (_b = name === null || name === void 0 ? void 0 : name.description) !== null && _b !== void 0 ? _b : "";
153
+ schema.description = (_c = name === null || name === void 0 ? void 0 : name.description) !== null && _c !== void 0 ? _c : "";
128
154
  if (type instanceof Number) {
129
155
  schema.itemType = DataType.DOUBLE;
130
156
  }
@@ -137,7 +163,10 @@ const ArrayField = (type, name) => (target, key) => {
137
163
  else if (type instanceof Model) {
138
164
  schema.options.recordClass = type;
139
165
  }
140
- const fieldProp = (_c = props.fields.get(key)) !== null && _c !== void 0 ? _c : {};
166
+ else if (Array.isArray(type)) {
167
+ fieldProp.isUnion = true;
168
+ fieldProp.unionTypes = type;
169
+ }
141
170
  fieldProp.name = key;
142
171
  fieldProp.Type = type;
143
172
  fieldProp.isArray = true;
@@ -279,4 +308,4 @@ const UpperBound = (value, inclusive = false) => createValidator(inclusive ? (v)
279
308
  */
280
309
  const Range = (lower, upper, inclusive = false) => createValidator(inclusive ? (v) => lower <= v && v <= upper : (v) => lower <= v && v < upper, new InvalidValue(`value is not within the range of ${lower} <= v ` + (inclusive ? `<= ${upper}` : `< ${upper}`)));
281
310
 
282
- export { Alias, ArrayField, Field, Ignore, LowerBound, MapField, RaiseError, Range, Readonly, SchemaType, UpperBound, Validator };
311
+ export { Alias, ArrayField, Field, Ignore, LowerBound, MapField, RaiseError, Range, Readonly, SchemaType, UnionField, UpperBound, Validator };
package/data/model.cjs CHANGED
@@ -21,6 +21,7 @@ exports.RaiseError = property.RaiseError;
21
21
  exports.Range = property.Range;
22
22
  exports.Readonly = property.Readonly;
23
23
  exports.SchemaType = property.SchemaType;
24
+ exports.UnionField = property.UnionField;
24
25
  exports.UpperBound = property.UpperBound;
25
26
  exports.Validator = property.Validator;
26
27
  Object.defineProperty(exports, 'DataFormat', {
package/data/model.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  export { Model, Optional } from './model/model.mjs';
2
- export { Alias, ArrayField, Field, Ignore, LowerBound, MapField, RaiseError, Range, Readonly, SchemaType, UpperBound, Validator } from './model/property.mjs';
2
+ export { Alias, ArrayField, Field, Ignore, LowerBound, MapField, RaiseError, Range, Readonly, SchemaType, UnionField, UpperBound, Validator } from './model/property.mjs';
3
3
  export { DataFormat, DataType } from './model/types.mjs';
4
4
  export { APIKeyCredentials, BasicCredentials, BearerCredentials, Credentials } from './model/credentials.mjs';
5
5
  export { createModelClassAnnotationTag, createModelFieldAnnotationTag, getModelClassAnnotationTagProperties, getModelFieldAnnotationTagProperties } from './model/plugin.mjs';