@jsii/kernel 1.61.0 → 1.62.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.
@@ -27,11 +27,14 @@
27
27
  * - /R(t) recurse with declared type t
28
28
  */
29
29
  Object.defineProperty(exports, "__esModule", { value: true });
30
- exports.serializationType = exports.SERIALIZERS = exports.SYMBOL_WIRE_TYPE = exports.EMPTY_OBJECT_FQN = void 0;
30
+ exports.SerializationError = exports.process = exports.serializationType = exports.SERIALIZERS = exports.SYMBOL_WIRE_TYPE = exports.EMPTY_OBJECT_FQN = void 0;
31
31
  const spec = require("@jsii/spec");
32
+ const assert = require("assert");
33
+ const util_1 = require("util");
32
34
  const api_1 = require("./api");
33
35
  const objects_1 = require("./objects");
34
36
  const _1 = require(".");
37
+ const VOID = 'void';
35
38
  /**
36
39
  * A special FQN that can be used to create empty javascript objects.
37
40
  */
@@ -59,11 +62,9 @@ exports.SERIALIZERS = {
59
62
  if (nullAndOk(value, optionalValue)) {
60
63
  return undefined;
61
64
  }
62
- if (optionalValue === 'void') {
63
- throw new Error('Encountered unexpected `void` type');
64
- }
65
+ assert(optionalValue !== VOID, 'Encountered unexpected void type!');
65
66
  if (!isDate(value)) {
66
- throw new Error(`Expected Date, got ${JSON.stringify(value)}`);
67
+ throw new SerializationError(`Value is not an instance of Date`, value);
67
68
  }
68
69
  return serializeDate(value);
69
70
  },
@@ -72,7 +73,7 @@ exports.SERIALIZERS = {
72
73
  return undefined;
73
74
  }
74
75
  if (!(0, api_1.isWireDate)(value)) {
75
- throw new Error(`Expected Date, got ${JSON.stringify(value)}`);
76
+ throw new SerializationError(`Value does not have the "${api_1.TOKEN_DATE}" key`, value);
76
77
  }
77
78
  return deserializeDate(value);
78
79
  },
@@ -83,15 +84,13 @@ exports.SERIALIZERS = {
83
84
  if (nullAndOk(value, optionalValue)) {
84
85
  return undefined;
85
86
  }
86
- if (optionalValue === 'void') {
87
- throw new Error('Encountered unexpected `void` type');
88
- }
87
+ assert(optionalValue !== VOID, 'Encountered unexpected void type!');
89
88
  const primitiveType = optionalValue.type;
90
89
  if (!isScalar(value)) {
91
- throw new Error(`Expected ${spec.describeTypeReference(optionalValue.type)}, got ${JSON.stringify(value)}`);
90
+ throw new SerializationError(`Value is not a ${spec.describeTypeReference(optionalValue.type)}`, value);
92
91
  }
93
92
  if (typeof value !== primitiveType.primitive) {
94
- throw new Error(`Expected a ${spec.describeTypeReference(optionalValue.type)}, got ${JSON.stringify(value)} (${typeof value})`);
93
+ throw new SerializationError(`Value is not a ${spec.describeTypeReference(optionalValue.type)}`, value);
95
94
  }
96
95
  return value;
97
96
  },
@@ -99,22 +98,24 @@ exports.SERIALIZERS = {
99
98
  if (nullAndOk(value, optionalValue)) {
100
99
  return undefined;
101
100
  }
102
- if (optionalValue === 'void') {
103
- throw new Error('Encountered unexpected `void` type');
104
- }
101
+ assert(optionalValue !== VOID, 'Encountered unexpected void type!');
105
102
  const primitiveType = optionalValue.type;
106
103
  if (!isScalar(value)) {
107
- throw new Error(`Expected a ${spec.describeTypeReference(optionalValue.type)}, got ${JSON.stringify(value)}`);
104
+ throw new SerializationError(`Value is not a ${spec.describeTypeReference(optionalValue.type)}`, value);
108
105
  }
109
106
  if (typeof value !== primitiveType.primitive) {
110
- throw new Error(`Expected a ${spec.describeTypeReference(optionalValue.type)}, got ${JSON.stringify(value)} (${typeof value})`);
107
+ throw new SerializationError(`Value is not a ${spec.describeTypeReference(optionalValue.type)}`, value);
111
108
  }
112
109
  return value;
113
110
  },
114
111
  },
115
112
  // ----------------------------------------------------------------------
116
113
  ["Json" /* SerializationClass.Json */]: {
117
- serialize(value) {
114
+ serialize(value, optionalValue) {
115
+ // /!\ Top-level "null" will turn to undefined, but any null nested in the value is valid JSON, so it'll stay!
116
+ if (nullAndOk(value, optionalValue)) {
117
+ return undefined;
118
+ }
118
119
  // Just whatever. Dates will automatically serialize themselves to strings.
119
120
  return value;
120
121
  },
@@ -145,13 +146,13 @@ exports.SERIALIZERS = {
145
146
  return value.map(mapJsonValue);
146
147
  }
147
148
  return mapValues(value, mapJsonValue);
148
- function mapJsonValue(toMap) {
149
+ function mapJsonValue(toMap, key) {
149
150
  if (toMap == null) {
150
151
  return toMap;
151
152
  }
152
- return host.recurse(toMap, {
153
+ return process(host, 'deserialize', toMap, {
153
154
  type: { primitive: spec.PrimitiveType.Json },
154
- });
155
+ }, typeof key === 'string' ? `key ${(0, util_1.inspect)(key)}` : `index ${key}`);
155
156
  }
156
157
  },
157
158
  },
@@ -161,18 +162,16 @@ exports.SERIALIZERS = {
161
162
  if (nullAndOk(value, optionalValue)) {
162
163
  return undefined;
163
164
  }
164
- if (optionalValue === 'void') {
165
- throw new Error('Encountered unexpected `void` type');
166
- }
165
+ assert(optionalValue !== VOID, 'Encountered unexpected void type!');
167
166
  if (typeof value !== 'string' && typeof value !== 'number') {
168
- throw new Error(`Expected enum value, got ${JSON.stringify(value)}`);
167
+ throw new SerializationError(`Value is not a string or number`, value);
169
168
  }
170
169
  host.debug('Serializing enum');
171
170
  const enumType = optionalValue.type;
172
171
  const enumMap = host.findSymbol(enumType.fqn);
173
172
  const enumEntry = Object.entries(enumMap).find(([, v]) => v === value);
174
173
  if (!enumEntry) {
175
- throw new Error(`No entry in ${enumType.fqn} has value ${value}`);
174
+ throw new SerializationError(`Value is not present in enum ${spec.describeTypeReference(enumType)}`, value);
176
175
  }
177
176
  return { [api_1.TOKEN_ENUM]: `${enumType.fqn}/${enumEntry[0]}` };
178
177
  },
@@ -181,7 +180,7 @@ exports.SERIALIZERS = {
181
180
  return undefined;
182
181
  }
183
182
  if (!(0, api_1.isWireEnum)(value)) {
184
- throw new Error(`Expected enum value, got ${JSON.stringify(value)}`);
183
+ throw new SerializationError(`Value does not have the "${api_1.TOKEN_ENUM}" key`, value);
185
184
  }
186
185
  return deserializeEnum(value, host.findSymbol);
187
186
  },
@@ -192,27 +191,23 @@ exports.SERIALIZERS = {
192
191
  if (nullAndOk(value, optionalValue)) {
193
192
  return undefined;
194
193
  }
195
- if (optionalValue === 'void') {
196
- throw new Error('Encountered unexpected `void` type');
197
- }
194
+ assert(optionalValue !== VOID, 'Encountered unexpected void type!');
198
195
  if (!Array.isArray(value)) {
199
- throw new Error(`Expected array type, got ${JSON.stringify(value)}`);
196
+ throw new SerializationError(`Value is not an array`, value);
200
197
  }
201
198
  const arrayType = optionalValue.type;
202
- return value.map((x) => host.recurse(x, { type: arrayType.collection.elementtype }));
199
+ return value.map((x, idx) => process(host, 'serialize', x, { type: arrayType.collection.elementtype }, `index ${(0, util_1.inspect)(idx)}`));
203
200
  },
204
201
  deserialize(value, optionalValue, host) {
205
202
  if (nullAndOk(value, optionalValue)) {
206
203
  return undefined;
207
204
  }
208
- if (optionalValue === 'void') {
209
- throw new Error('Encountered unexpected `void` type');
210
- }
205
+ assert(optionalValue !== VOID, 'Encountered unexpected void type!');
211
206
  if (!Array.isArray(value)) {
212
- throw new Error(`Expected array type, got ${JSON.stringify(value)}`);
207
+ throw new SerializationError(`Value is not an array`, value);
213
208
  }
214
209
  const arrayType = optionalValue.type;
215
- return value.map((x) => host.recurse(x, { type: arrayType.collection.elementtype }));
210
+ return value.map((x, idx) => process(host, 'deserialize', x, { type: arrayType.collection.elementtype }, `index ${(0, util_1.inspect)(idx)}`));
216
211
  },
217
212
  },
218
213
  // ----------------------------------------------------------------------
@@ -221,27 +216,23 @@ exports.SERIALIZERS = {
221
216
  if (nullAndOk(value, optionalValue)) {
222
217
  return undefined;
223
218
  }
224
- if (optionalValue === 'void') {
225
- throw new Error('Encountered unexpected `void` type');
226
- }
219
+ assert(optionalValue !== VOID, 'Encountered unexpected void type!');
227
220
  const mapType = optionalValue.type;
228
221
  return {
229
- [api_1.TOKEN_MAP]: mapValues(value, (v) => host.recurse(v, { type: mapType.collection.elementtype })),
222
+ [api_1.TOKEN_MAP]: mapValues(value, (v, key) => process(host, 'serialize', v, { type: mapType.collection.elementtype }, `key ${(0, util_1.inspect)(key)}`)),
230
223
  };
231
224
  },
232
225
  deserialize(value, optionalValue, host) {
233
226
  if (nullAndOk(value, optionalValue)) {
234
227
  return undefined;
235
228
  }
236
- if (optionalValue === 'void') {
237
- throw new Error('Encountered unexpected `void` type');
238
- }
229
+ assert(optionalValue !== VOID, 'Encountered unexpected void type!');
239
230
  const mapType = optionalValue.type;
240
231
  if (!(0, api_1.isWireMap)(value)) {
241
232
  // Compatibility mode with older versions that didn't wrap in [TOKEN_MAP]
242
- return mapValues(value, (v) => host.recurse(v, { type: mapType.collection.elementtype }));
233
+ return mapValues(value, (v, key) => process(host, 'deserialize', v, { type: mapType.collection.elementtype }, `key ${(0, util_1.inspect)(key)}`));
243
234
  }
244
- const result = mapValues(value[api_1.TOKEN_MAP], (v) => host.recurse(v, { type: mapType.collection.elementtype }));
235
+ const result = mapValues(value[api_1.TOKEN_MAP], (v, key) => process(host, 'deserialize', v, { type: mapType.collection.elementtype }, `key ${(0, util_1.inspect)(key)}`));
245
236
  Object.defineProperty(result, exports.SYMBOL_WIRE_TYPE, {
246
237
  configurable: false,
247
238
  enumerable: false,
@@ -257,11 +248,12 @@ exports.SERIALIZERS = {
257
248
  if (nullAndOk(value, optionalValue)) {
258
249
  return undefined;
259
250
  }
260
- if (optionalValue === 'void') {
261
- throw new Error('Encountered unexpected `void` type');
251
+ assert(optionalValue !== VOID, 'Encountered unexpected void type!');
252
+ if (typeof value !== 'object' || value == null || value instanceof Date) {
253
+ throw new SerializationError(`Value is not an object`, value);
262
254
  }
263
- if (typeof value !== 'object' || value == null) {
264
- throw new Error(`Expected object, got ${JSON.stringify(value)}`);
255
+ if (Array.isArray(value)) {
256
+ throw new SerializationError(`Value is an array`, value);
265
257
  }
266
258
  /*
267
259
  This is what we'd like to do, but we can't because at least the Java client
@@ -283,23 +275,21 @@ exports.SERIALIZERS = {
283
275
  ]);
284
276
  },
285
277
  deserialize(value, optionalValue, host) {
286
- if (typeof value === 'object' && Object.keys(value ?? {}).length === 0) {
278
+ if (typeof value === 'object' && Object.keys(value !== null && value !== void 0 ? value : {}).length === 0) {
287
279
  // Treat empty structs as `undefined` (see https://github.com/aws/jsii/issues/411)
288
280
  value = undefined;
289
281
  }
290
282
  if (nullAndOk(value, optionalValue)) {
291
283
  return undefined;
292
284
  }
293
- if (optionalValue === 'void') {
294
- throw new Error('Encountered unexpected `void` type');
295
- }
285
+ assert(optionalValue !== VOID, 'Encountered unexpected void type!');
296
286
  if (typeof value !== 'object' || value == null) {
297
- throw new Error(`Expected object reference, got ${JSON.stringify(value)}`);
287
+ throw new SerializationError(`Value is not an object`, value);
298
288
  }
299
289
  const namedType = host.lookupType(optionalValue.type.fqn);
300
290
  const props = propertiesOf(namedType, host.lookupType);
301
291
  if (Array.isArray(value)) {
302
- throw new Error(`Got an array where a ${namedType.fqn} was expected. Did you mean to pass a variable number of arguments?`);
292
+ throw new SerializationError('Value is an array (varargs may have been incorrectly supplied)', value);
303
293
  }
304
294
  // Similarly to serialization, we might be getting a reference type where we're
305
295
  // expecting a value type. Accept this for now (but also validate that object
@@ -312,7 +302,7 @@ exports.SERIALIZERS = {
312
302
  if (_1.api.isWireStruct(value)) {
313
303
  const { fqn, data } = value[_1.api.TOKEN_STRUCT];
314
304
  if (!isAssignable(fqn, namedType, host.lookupType)) {
315
- throw new Error(`Wire struct type '${fqn}' does not match expected '${namedType.fqn}'`);
305
+ throw new SerializationError(`Wired struct has type '${fqn}', which does not match expected type`, value);
316
306
  }
317
307
  value = data;
318
308
  }
@@ -326,41 +316,40 @@ exports.SERIALIZERS = {
326
316
  if (!props[key]) {
327
317
  return undefined;
328
318
  } // Don't map if unknown property
329
- return host.recurse(v, props[key]);
319
+ return process(host, 'deserialize', v, props[key], `key ${(0, util_1.inspect)(key)}`);
330
320
  });
331
321
  },
332
322
  },
333
323
  // ----------------------------------------------------------------------
334
324
  ["RefType" /* SerializationClass.ReferenceType */]: {
335
325
  serialize(value, optionalValue, host) {
326
+ var _a;
336
327
  if (nullAndOk(value, optionalValue)) {
337
328
  return undefined;
338
329
  }
339
- if (optionalValue === 'void') {
340
- throw new Error('Encountered unexpected `void` type');
330
+ assert(optionalValue !== VOID, 'Encountered unexpected void type!');
331
+ if (typeof value !== 'object' || value == null || Array.isArray(value)) {
332
+ throw new SerializationError(`Value is not an object`, value);
341
333
  }
342
- if (typeof value !== 'object' || value == null) {
343
- throw new Error(`Expected object reference, got ${JSON.stringify(value)}`);
334
+ if (value instanceof Date) {
335
+ throw new SerializationError(`Value is a Date`, value);
344
336
  }
345
337
  const expectedType = host.lookupType(optionalValue.type.fqn);
346
338
  const interfaces = spec.isInterfaceType(expectedType)
347
339
  ? [expectedType.fqn]
348
340
  : undefined;
349
- const jsiiType = (0, objects_1.jsiiTypeFqn)(value) ??
350
- (spec.isClassType(expectedType) ? expectedType.fqn : exports.EMPTY_OBJECT_FQN);
341
+ const jsiiType = (_a = (0, objects_1.jsiiTypeFqn)(value)) !== null && _a !== void 0 ? _a : (spec.isClassType(expectedType) ? expectedType.fqn : exports.EMPTY_OBJECT_FQN);
351
342
  return host.objects.registerObject(value, jsiiType, interfaces);
352
343
  },
353
344
  deserialize(value, optionalValue, host) {
354
345
  if (nullAndOk(value, optionalValue)) {
355
346
  return undefined;
356
347
  }
357
- if (optionalValue === 'void') {
358
- throw new Error('Encountered unexpected `void` type');
359
- }
348
+ assert(optionalValue !== VOID, 'Encountered unexpected void type!');
360
349
  // The only way to pass a by-ref object is to have created it
361
350
  // previously inside JSII kernel, so it must have an objref already.
362
351
  if (!(0, api_1.isObjRef)(value)) {
363
- throw new Error(`Expected object reference, got ${JSON.stringify(value)}`);
352
+ throw new SerializationError(`Value does not have the "${api_1.TOKEN_REF}" key`, value);
364
353
  }
365
354
  const { instance, fqn } = host.objects.findObject(value);
366
355
  const namedTypeRef = optionalValue.type;
@@ -373,7 +362,7 @@ exports.SERIALIZERS = {
373
362
  const declaredType = optionalValue.type;
374
363
  if (spec.isClassType(namedType) &&
375
364
  !isAssignable(fqn, declaredType, host.lookupType)) {
376
- throw new Error(`Object of type ${fqn} is not convertible to ${declaredType.fqn}`);
365
+ throw new SerializationError(`Object of type '${fqn}' is not convertible to ${spec.describeTypeReference(declaredType)}`, value);
377
366
  }
378
367
  }
379
368
  return instance;
@@ -382,6 +371,7 @@ exports.SERIALIZERS = {
382
371
  // ----------------------------------------------------------------------
383
372
  ["Any" /* SerializationClass.Any */]: {
384
373
  serialize(value, _type, host) {
374
+ var _a;
385
375
  if (value == null) {
386
376
  return undefined;
387
377
  }
@@ -392,15 +382,15 @@ exports.SERIALIZERS = {
392
382
  return value;
393
383
  }
394
384
  if (Array.isArray(value)) {
395
- return value.map((e) => host.recurse(e, { type: spec.CANONICAL_ANY }));
385
+ return value.map((e, idx) => process(host, 'serialize', e, { type: spec.CANONICAL_ANY }, `index ${(0, util_1.inspect)(idx)}`));
396
386
  }
397
387
  // Note: no case for "ENUM" here, without type declaration we can't tell the difference
398
388
  // between an enum member and a scalar.
399
389
  if (typeof value === 'function') {
400
- throw new Error('JSII Kernel is unable to serialize `function`. An instance with methods might have been returned by an `any` method?');
390
+ throw new SerializationError('Functions cannot be passed across language boundaries', value);
401
391
  }
402
392
  if (typeof value !== 'object' || value == null) {
403
- throw new Error(`JSII kernel assumption violated, ${JSON.stringify(value)} is not an object`);
393
+ throw new SerializationError(`A jsii kernel assumption was violated: value is not an object`, value);
404
394
  }
405
395
  if (exports.SYMBOL_WIRE_TYPE in value &&
406
396
  value[exports.SYMBOL_WIRE_TYPE] === api_1.TOKEN_MAP) {
@@ -417,7 +407,7 @@ exports.SERIALIZERS = {
417
407
  // those and throw a descriptive error message. We can't detect these cases any other
418
408
  // way, and the by-value serialized object will be quite useless.
419
409
  if (value instanceof Set || value instanceof Map) {
420
- throw new Error("Can't return objects of type Set or Map");
410
+ throw new SerializationError('Set and Map instances cannot be sent across the language boundary', value);
421
411
  }
422
412
  // Use a previous reference to maintain object identity. NOTE: this may cause us to return
423
413
  // a different type than requested! This is just how it is right now.
@@ -428,8 +418,7 @@ exports.SERIALIZERS = {
428
418
  }
429
419
  // If this is or should be a reference type, pass or make the reference
430
420
  // (Like regular reftype serialization, but without the type derivation to an interface)
431
- const jsiiType = (0, objects_1.jsiiTypeFqn)(value) ??
432
- (isByReferenceOnly(value) ? exports.EMPTY_OBJECT_FQN : undefined);
421
+ const jsiiType = (_a = (0, objects_1.jsiiTypeFqn)(value)) !== null && _a !== void 0 ? _a : (isByReferenceOnly(value) ? exports.EMPTY_OBJECT_FQN : undefined);
433
422
  if (jsiiType) {
434
423
  return host.objects.registerObject(value, jsiiType);
435
424
  }
@@ -438,7 +427,7 @@ exports.SERIALIZERS = {
438
427
  // We will serialize by-value, but recurse for serialization so that if
439
428
  // the object contains reference objects, they will be serialized appropriately.
440
429
  // (Basically, serialize anything else as a map of 'any').
441
- return mapValues(value, (v) => host.recurse(v, { type: spec.CANONICAL_ANY }));
430
+ return mapValues(value, (v, key) => process(host, 'serialize', v, { type: spec.CANONICAL_ANY }, `key ${(0, util_1.inspect)(key)}`));
442
431
  },
443
432
  deserialize(value, _type, host) {
444
433
  if (value == null) {
@@ -454,7 +443,7 @@ exports.SERIALIZERS = {
454
443
  }
455
444
  if (Array.isArray(value)) {
456
445
  host.debug('ANY is an Array');
457
- return value.map((e) => host.recurse(e, { type: spec.CANONICAL_ANY }));
446
+ return value.map((e, idx) => process(host, 'deserialize', e, { type: spec.CANONICAL_ANY }, `index ${(0, util_1.inspect)(idx)}`));
458
447
  }
459
448
  if ((0, api_1.isWireEnum)(value)) {
460
449
  host.debug('ANY is an Enum');
@@ -484,7 +473,7 @@ exports.SERIALIZERS = {
484
473
  }
485
474
  // At this point again, deserialize by-value.
486
475
  host.debug('ANY is a Map');
487
- return mapValues(value, (v) => host.recurse(v, { type: spec.CANONICAL_ANY }));
476
+ return mapValues(value, (v, key) => process(host, 'deserialize', v, { type: spec.CANONICAL_ANY }, `key ${(0, util_1.inspect)(key)}`));
488
477
  },
489
478
  },
490
479
  };
@@ -498,13 +487,13 @@ function deserializeEnum(value, lookup) {
498
487
  const enumLocator = value[api_1.TOKEN_ENUM];
499
488
  const sep = enumLocator.lastIndexOf('/');
500
489
  if (sep === -1) {
501
- throw new Error(`Malformed enum value: ${JSON.stringify(value)}`);
490
+ throw new SerializationError(`Invalid enum token value ${(0, util_1.inspect)(enumLocator)}`, value);
502
491
  }
503
492
  const typeName = enumLocator.slice(0, sep);
504
493
  const valueName = enumLocator.slice(sep + 1);
505
494
  const enumValue = lookup(typeName)[valueName];
506
495
  if (enumValue === undefined) {
507
- throw new Error(`No enum member named ${valueName} in ${typeName}`);
496
+ throw new SerializationError(`No such enum member: ${(0, util_1.inspect)(valueName)}`, value);
508
497
  }
509
498
  return enumValue;
510
499
  }
@@ -514,9 +503,7 @@ function deserializeEnum(value, lookup) {
514
503
  * There can be multiple, because the type can be a type union.
515
504
  */
516
505
  function serializationType(typeRef, lookup) {
517
- if (typeRef == null) {
518
- throw new Error("Kernel error: expected type information, got 'undefined'");
519
- }
506
+ assert(typeRef != null, `Kernel error: expected type information, got ${(0, util_1.inspect)(typeRef)}`);
520
507
  if (typeRef === 'void') {
521
508
  return [{ serializationClass: "Void" /* SerializationClass.Void */, typeRef }];
522
509
  }
@@ -533,7 +520,7 @@ function serializationType(typeRef, lookup) {
533
520
  case spec.PrimitiveType.String:
534
521
  return [{ serializationClass: "Scalar" /* SerializationClass.Scalar */, typeRef }];
535
522
  }
536
- throw new Error('Unknown primitive type');
523
+ assert(false, `Unknown primitive type: ${(0, util_1.inspect)(typeRef.type)}`);
537
524
  }
538
525
  if (spec.isCollectionTypeReference(typeRef.type)) {
539
526
  return [
@@ -571,7 +558,7 @@ function nullAndOk(x, type) {
571
558
  return false;
572
559
  }
573
560
  if (type !== 'void' && !type.optional) {
574
- throw new Error(`Got 'undefined' for non-optional instance of ${JSON.stringify(type)}`);
561
+ throw new SerializationError(`A value is required (type is non-optional)`, x);
575
562
  }
576
563
  return true;
577
564
  }
@@ -594,7 +581,10 @@ function flatMap(xs, fn) {
594
581
  */
595
582
  function mapValues(value, fn) {
596
583
  if (typeof value !== 'object' || value == null) {
597
- throw new Error(`Expected object type, got ${JSON.stringify(value)}`);
584
+ throw new SerializationError(`Value is not an object`, value);
585
+ }
586
+ if (Array.isArray(value)) {
587
+ throw new SerializationError(`Value is an array`, value);
598
588
  }
599
589
  const out = {};
600
590
  for (const [k, v] of Object.entries(value)) {
@@ -607,6 +597,7 @@ function mapValues(value, fn) {
607
597
  return out;
608
598
  }
609
599
  function propertiesOf(t, lookup) {
600
+ var _a;
610
601
  if (!spec.isClassOrInterfaceType(t)) {
611
602
  return {};
612
603
  }
@@ -619,7 +610,7 @@ function propertiesOf(t, lookup) {
619
610
  if (spec.isClassType(t) && t.base) {
620
611
  ret = { ...ret, ...propertiesOf(lookup(t.base), lookup) };
621
612
  }
622
- for (const prop of t.properties ?? []) {
613
+ for (const prop of (_a = t.properties) !== null && _a !== void 0 ? _a : []) {
623
614
  ret[prop.name] = prop;
624
615
  }
625
616
  return ret;
@@ -659,7 +650,9 @@ function validateRequiredProps(actualProps, typeName, specProps) {
659
650
  .filter((name) => !specProps[name].optional)
660
651
  .filter((name) => !(name in actualProps));
661
652
  if (missingRequiredProps.length > 0) {
662
- throw new Error(`Missing required properties for ${typeName}: ${missingRequiredProps.join(', ')}`);
653
+ throw new SerializationError(`Missing required properties for ${typeName}: ${missingRequiredProps
654
+ .map((p) => (0, util_1.inspect)(p))
655
+ .join(', ')}`, actualProps);
663
656
  }
664
657
  return actualProps;
665
658
  }
@@ -697,9 +690,9 @@ function isByReferenceOnly(obj) {
697
690
  do {
698
691
  for (const prop of Object.getOwnPropertyNames(curr)) {
699
692
  const descr = Object.getOwnPropertyDescriptor(curr, prop);
700
- if (descr?.get != null ||
701
- descr?.set != null ||
702
- typeof descr?.value === 'function') {
693
+ if ((descr === null || descr === void 0 ? void 0 : descr.get) != null ||
694
+ (descr === null || descr === void 0 ? void 0 : descr.set) != null ||
695
+ typeof (descr === null || descr === void 0 ? void 0 : descr.value) === 'function') {
703
696
  // Property has a dynamic getter, setter or is a constructor/method, so by-ref required!
704
697
  return true;
705
698
  }
@@ -708,4 +701,91 @@ function isByReferenceOnly(obj) {
708
701
  } while (Object.getPrototypeOf((curr = Object.getPrototypeOf(curr))) != null);
709
702
  return false;
710
703
  }
704
+ function process(host, serde, value, type, context) {
705
+ const wireTypes = serializationType(type, host.lookupType);
706
+ host.debug(serde, value, wireTypes);
707
+ const errors = new Array();
708
+ for (const { serializationClass, typeRef } of wireTypes) {
709
+ try {
710
+ return exports.SERIALIZERS[serializationClass][serde](value, typeRef, host);
711
+ }
712
+ catch (error) {
713
+ error.context = `as ${typeRef === VOID ? VOID : spec.describeTypeReference(typeRef.type)}`;
714
+ errors.push(error);
715
+ }
716
+ }
717
+ const typeDescr = type === VOID ? type : spec.describeTypeReference(type.type);
718
+ const optionalTypeDescr = type !== VOID && type.optional ? `${typeDescr} | undefined` : typeDescr;
719
+ throw new SerializationError(`${titleize(context)}: Unable to ${serde} value as ${optionalTypeDescr}`, value, errors, { renderValue: true });
720
+ function titleize(text) {
721
+ text = text.trim();
722
+ if (text === '') {
723
+ return text;
724
+ }
725
+ const [first, ...rest] = text;
726
+ return [first.toUpperCase(), ...rest].join('');
727
+ }
728
+ }
729
+ exports.process = process;
730
+ class SerializationError extends Error {
731
+ constructor(message, value, causes = [], { renderValue = false } = {}) {
732
+ super([
733
+ message,
734
+ ...(renderValue
735
+ ? [
736
+ `${causes.length > 0 ? '\u{251C}' : '\u{2570}'}\u{2500}\u{2500} \u{1F6D1} Failing value is ${describeTypeOf(value)}`,
737
+ ...(value == null
738
+ ? []
739
+ : (0, util_1.inspect)(value, false, 0)
740
+ .split('\n')
741
+ .map((l) => `${causes.length > 0 ? '\u{2502}' : ' '} ${l}`)),
742
+ ]
743
+ : []),
744
+ ...(causes.length > 0
745
+ ? [
746
+ '\u{2570}\u{2500}\u{2500} \u{1F50D} Failure reason(s):',
747
+ ...causes.map((cause, idx) => {
748
+ var _a;
749
+ return ` ${idx < causes.length - 1 ? '\u{251C}' : '\u{2570}'}\u{2500}${causes.length > 1
750
+ ? ` [${(_a = cause.context) !== null && _a !== void 0 ? _a : (0, util_1.inspect)(idx)}]`
751
+ : ''} ${cause.message.split('\n').join('\n ')}`;
752
+ }),
753
+ ]
754
+ : []),
755
+ ].join('\n'));
756
+ this.value = value;
757
+ this.causes = causes;
758
+ this.name = '@jsii/kernel.SerializationError';
759
+ }
760
+ }
761
+ exports.SerializationError = SerializationError;
762
+ function describeTypeOf(value) {
763
+ const type = typeof value;
764
+ switch (type) {
765
+ case 'object':
766
+ if (value == null) {
767
+ return JSON.stringify(value);
768
+ }
769
+ if (Array.isArray(value)) {
770
+ return 'an array';
771
+ }
772
+ const fqn = (0, objects_1.jsiiTypeFqn)(value);
773
+ if (fqn != null && fqn !== exports.EMPTY_OBJECT_FQN) {
774
+ return `an instance of ${fqn}`;
775
+ }
776
+ const ctorName = value.constructor.name;
777
+ if (ctorName != null && ctorName !== Object.name) {
778
+ return `an instance of ${ctorName}`;
779
+ }
780
+ return `an object`;
781
+ case 'undefined':
782
+ return type;
783
+ case 'boolean':
784
+ case 'function':
785
+ case 'number':
786
+ case 'string':
787
+ default:
788
+ return `a ${type}`;
789
+ }
790
+ }
711
791
  //# sourceMappingURL=serialization.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsii/kernel",
3
- "version": "1.61.0",
3
+ "version": "1.62.0",
4
4
  "description": "kernel for jsii execution environment",
5
5
  "license": "Apache-2.0",
6
6
  "author": {
@@ -31,17 +31,17 @@
31
31
  "package": "package-js"
32
32
  },
33
33
  "dependencies": {
34
- "@jsii/spec": "^1.61.0",
34
+ "@jsii/spec": "^1.62.0",
35
35
  "fs-extra": "^10.1.0",
36
36
  "tar": "^6.1.11"
37
37
  },
38
38
  "devDependencies": {
39
- "@scope/jsii-calc-base": "^1.61.0",
40
- "@scope/jsii-calc-lib": "^1.61.0",
39
+ "@scope/jsii-calc-base": "^1.62.0",
40
+ "@scope/jsii-calc-lib": "^1.62.0",
41
41
  "@types/fs-extra": "^9.0.13",
42
42
  "@types/tar": "^6.1.1",
43
43
  "jest-expect-message": "^1.0.2",
44
- "jsii-build-tools": "^1.61.0",
44
+ "jsii-build-tools": "^1.62.0",
45
45
  "jsii-calc": "^3.20.120"
46
46
  }
47
47
  }