@promptbook/editable 0.112.0-73 → 0.112.0-79

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 (74) hide show
  1. package/README.md +9 -9
  2. package/esm/index.es.js +310 -204
  3. package/esm/index.es.js.map +1 -1
  4. package/esm/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
  5. package/esm/src/avatars/visuals/octopus3d2AvatarVisual.d.ts +7 -0
  6. package/esm/src/avatars/visuals/octopus3dAvatarVisualShared.d.ts +37 -0
  7. package/esm/src/book-components/Chat/save/_common/chatExportRendering.d.ts +47 -0
  8. package/esm/src/book-components/Chat/save/html/htmlSaveFormatDefinition.d.ts +12 -0
  9. package/esm/src/book-components/Chat/save/index.d.ts +2 -2
  10. package/esm/src/book-components/Chat/save/markdown/mdSaveFormatDefinition.d.ts +5 -3
  11. package/esm/src/book-components/Chat/save/pdf/buildChatPdf.d.ts +3 -3
  12. package/esm/src/book-components/Chat/save/pdf/pdfSaveFormatDefinition.d.ts +1 -1
  13. package/esm/src/cli/cli-commands/agent/agentProjectPaths.d.ts +8 -8
  14. package/esm/src/cli/cli-commands/agent/initializeAgentRunnerCommand.d.ts +1 -1
  15. package/esm/src/cli/cli-commands/agents-server/buildAgentsServer.d.ts +56 -0
  16. package/esm/src/cli/cli-commands/agents-server/buildAgentsServer.test.d.ts +1 -0
  17. package/esm/src/cli/cli-commands/agents-server/ensureAgentsServerEnvFile.d.ts +7 -0
  18. package/esm/src/cli/cli-commands/agents-server/ensureAgentsServerGitignoreFile.d.ts +7 -0
  19. package/esm/src/cli/cli-commands/agents-server/init.d.ts +9 -0
  20. package/esm/src/cli/cli-commands/agents-server/init.test.d.ts +1 -0
  21. package/esm/src/cli/cli-commands/agents-server/initializeAgentsServerProjectConfiguration.d.ts +17 -0
  22. package/esm/src/cli/cli-commands/agents-server/printAgentsServerInitializationSummary.d.ts +7 -0
  23. package/esm/src/cli/cli-commands/agents-server/run.d.ts +14 -0
  24. package/esm/src/cli/cli-commands/agents-server/run.test.d.ts +1 -0
  25. package/esm/src/cli/cli-commands/agents-server/startAgentsServer.d.ts +23 -0
  26. package/esm/src/cli/cli-commands/agents-server.d.ts +8 -0
  27. package/esm/src/cli/cli-commands/common/projectInitialization.d.ts +65 -0
  28. package/esm/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +44 -0
  29. package/esm/src/cli/common/$deprecateCliCommand.d.ts +8 -0
  30. package/esm/src/cli/common/$deprecateCliCommand.test.d.ts +1 -0
  31. package/esm/src/utils/color/Color.d.ts +4 -44
  32. package/esm/src/utils/color/ColorValue.d.ts +55 -0
  33. package/esm/src/utils/color/isHexColorString.d.ts +10 -0
  34. package/esm/src/utils/color/parseColorString.d.ts +11 -0
  35. package/esm/src/version.d.ts +1 -1
  36. package/package.json +2 -2
  37. package/umd/index.umd.js +310 -204
  38. package/umd/index.umd.js.map +1 -1
  39. package/umd/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
  40. package/umd/src/avatars/visuals/octopus3d2AvatarVisual.d.ts +7 -0
  41. package/umd/src/avatars/visuals/octopus3dAvatarVisualShared.d.ts +37 -0
  42. package/umd/src/book-components/Chat/save/_common/chatExportRendering.d.ts +47 -0
  43. package/umd/src/book-components/Chat/save/html/htmlSaveFormatDefinition.d.ts +12 -0
  44. package/umd/src/book-components/Chat/save/index.d.ts +2 -2
  45. package/umd/src/book-components/Chat/save/markdown/mdSaveFormatDefinition.d.ts +5 -3
  46. package/umd/src/book-components/Chat/save/pdf/buildChatPdf.d.ts +3 -3
  47. package/umd/src/book-components/Chat/save/pdf/pdfSaveFormatDefinition.d.ts +1 -1
  48. package/umd/src/cli/cli-commands/agent/agentProjectPaths.d.ts +8 -8
  49. package/umd/src/cli/cli-commands/agent/initializeAgentRunnerCommand.d.ts +1 -1
  50. package/umd/src/cli/cli-commands/agents-server/buildAgentsServer.d.ts +56 -0
  51. package/umd/src/cli/cli-commands/agents-server/buildAgentsServer.test.d.ts +1 -0
  52. package/umd/src/cli/cli-commands/agents-server/ensureAgentsServerEnvFile.d.ts +7 -0
  53. package/umd/src/cli/cli-commands/agents-server/ensureAgentsServerGitignoreFile.d.ts +7 -0
  54. package/umd/src/cli/cli-commands/agents-server/init.d.ts +9 -0
  55. package/umd/src/cli/cli-commands/agents-server/init.test.d.ts +1 -0
  56. package/umd/src/cli/cli-commands/agents-server/initializeAgentsServerProjectConfiguration.d.ts +17 -0
  57. package/umd/src/cli/cli-commands/agents-server/printAgentsServerInitializationSummary.d.ts +7 -0
  58. package/umd/src/cli/cli-commands/agents-server/run.d.ts +14 -0
  59. package/umd/src/cli/cli-commands/agents-server/run.test.d.ts +1 -0
  60. package/umd/src/cli/cli-commands/agents-server/startAgentsServer.d.ts +23 -0
  61. package/umd/src/cli/cli-commands/agents-server.d.ts +8 -0
  62. package/umd/src/cli/cli-commands/common/projectInitialization.d.ts +65 -0
  63. package/umd/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +44 -0
  64. package/umd/src/cli/common/$deprecateCliCommand.d.ts +8 -0
  65. package/umd/src/cli/common/$deprecateCliCommand.test.d.ts +1 -0
  66. package/umd/src/utils/color/Color.d.ts +4 -44
  67. package/umd/src/utils/color/ColorValue.d.ts +55 -0
  68. package/umd/src/utils/color/isHexColorString.d.ts +10 -0
  69. package/umd/src/utils/color/parseColorString.d.ts +11 -0
  70. package/umd/src/version.d.ts +1 -1
  71. package/esm/src/cli/cli-commands/coder/appendBlock.d.ts +0 -6
  72. package/esm/src/cli/cli-commands/coder/readTextFileIfExists.d.ts +0 -6
  73. package/umd/src/cli/cli-commands/coder/appendBlock.d.ts +0 -6
  74. package/umd/src/cli/cli-commands/coder/readTextFileIfExists.d.ts +0 -6
package/umd/index.umd.js CHANGED
@@ -22,7 +22,7 @@
22
22
  * @generated
23
23
  * @see https://github.com/webgptorg/promptbook
24
24
  */
25
- const PROMPTBOOK_ENGINE_VERSION = '0.112.0-73';
25
+ const PROMPTBOOK_ENGINE_VERSION = '0.112.0-79';
26
26
  /**
27
27
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
28
28
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -272,6 +272,111 @@
272
272
  }
273
273
  }
274
274
 
275
+ /**
276
+ * Shared immutable channel storage and serialization helpers for `Color`.
277
+ *
278
+ * @private base class of Color
279
+ */
280
+ class ColorValue {
281
+ constructor(red, green, blue, alpha = 255) {
282
+ this.red = red;
283
+ this.green = green;
284
+ this.blue = blue;
285
+ this.alpha = alpha;
286
+ checkChannelValue('Red', red);
287
+ checkChannelValue('Green', green);
288
+ checkChannelValue('Blue', blue);
289
+ checkChannelValue('Alpha', alpha);
290
+ }
291
+ /**
292
+ * Shortcut for `red` property
293
+ * Number from 0 to 255
294
+ * @alias red
295
+ */
296
+ get r() {
297
+ return this.red;
298
+ }
299
+ /**
300
+ * Shortcut for `green` property
301
+ * Number from 0 to 255
302
+ * @alias green
303
+ */
304
+ get g() {
305
+ return this.green;
306
+ }
307
+ /**
308
+ * Shortcut for `blue` property
309
+ * Number from 0 to 255
310
+ * @alias blue
311
+ */
312
+ get b() {
313
+ return this.blue;
314
+ }
315
+ /**
316
+ * Shortcut for `alpha` property
317
+ * Number from 0 (transparent) to 255 (opaque)
318
+ * @alias alpha
319
+ */
320
+ get a() {
321
+ return this.alpha;
322
+ }
323
+ /**
324
+ * Shortcut for `alpha` property
325
+ * Number from 0 (transparent) to 255 (opaque)
326
+ * @alias alpha
327
+ */
328
+ get opacity() {
329
+ return this.alpha;
330
+ }
331
+ /**
332
+ * Shortcut for 1-`alpha` property
333
+ */
334
+ get transparency() {
335
+ return 255 - this.alpha;
336
+ }
337
+ clone() {
338
+ return take(this.createColor(this.red, this.green, this.blue, this.alpha));
339
+ }
340
+ toString() {
341
+ return this.toHex();
342
+ }
343
+ toHex() {
344
+ if (this.alpha === 255) {
345
+ return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
346
+ .toString(16)
347
+ .padStart(2, '0')}`;
348
+ }
349
+ else {
350
+ return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
351
+ .toString(16)
352
+ .padStart(2, '0')}${this.alpha.toString(16).padStart(2, '0')}`;
353
+ }
354
+ }
355
+ toRgb() {
356
+ if (this.alpha === 255) {
357
+ return `rgb(${this.red}, ${this.green}, ${this.blue})`;
358
+ }
359
+ else {
360
+ return `rgba(${this.red}, ${this.green}, ${this.blue}, ${Math.round((this.alpha / 255) * 100)}%)`;
361
+ }
362
+ }
363
+ toHsl() {
364
+ throw new Error(`Getting HSL is not implemented`);
365
+ }
366
+ }
367
+
368
+ /**
369
+ * Checks if the given value is a valid hex color string
370
+ *
371
+ * @param value - value to check
372
+ * @returns true if the value is a valid hex color string (e.g., `#009edd`, `#fff`, etc.)
373
+ *
374
+ * @private function of Color
375
+ */
376
+ function isHexColorString(value) {
377
+ return (typeof value === 'string' && /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(value));
378
+ }
379
+
275
380
  /**
276
381
  * Constant for short hex lengths.
277
382
  */
@@ -483,16 +588,53 @@
483
588
 
484
589
  /**
485
590
  * Pattern matching hsl regex.
591
+ *
592
+ * @private function of Color
486
593
  */
487
594
  const HSL_REGEX_PATTERN = /^hsl\(\s*([0-9.]+)\s*,\s*([0-9.]+)%\s*,\s*([0-9.]+)%\s*\)$/;
488
595
  /**
489
596
  * Pattern matching RGB regex.
597
+ *
598
+ * @private function of Color
490
599
  */
491
600
  const RGB_REGEX_PATTERN = /^rgb\(\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*\)$/;
492
601
  /**
493
602
  * Pattern matching rgba regex.
603
+ *
604
+ * @private function of Color
494
605
  */
495
606
  const RGBA_REGEX_PATTERN = /^rgba\(\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*\)$/;
607
+ /**
608
+ * Parses a supported color string into RGBA channels.
609
+ *
610
+ * @param color as a string for example `#009edd`, `rgb(0,158,221)`, `rgb(0%,62%,86.7%)`, `hsl(197.1,100%,43.3%)`, `red`, `darkgrey`,...
611
+ * @returns RGBA channel values.
612
+ *
613
+ * @private function of Color
614
+ */
615
+ function parseColorString(color) {
616
+ const trimmed = color.trim();
617
+ const cssColor = CSS_COLORS[trimmed];
618
+ if (cssColor) {
619
+ return parseColorString(cssColor);
620
+ }
621
+ else if (isHexColorString(trimmed)) {
622
+ return parseHexColor(trimmed);
623
+ }
624
+ if (HSL_REGEX_PATTERN.test(trimmed)) {
625
+ return parseHslColor(trimmed);
626
+ }
627
+ else if (RGB_REGEX_PATTERN.test(trimmed)) {
628
+ return parseRgbColor(trimmed);
629
+ }
630
+ else if (RGBA_REGEX_PATTERN.test(trimmed)) {
631
+ return parseRgbaColor(trimmed);
632
+ }
633
+ else {
634
+ throw new Error(`Can not create a new Color instance from string "${trimmed}".`);
635
+ }
636
+ }
637
+
496
638
  /**
497
639
  * Color object represents an RGB color with alpha channel
498
640
  *
@@ -500,7 +642,7 @@
500
642
  *
501
643
  * @public exported from `@promptbook/color`
502
644
  */
503
- class Color {
645
+ class Color extends ColorValue {
504
646
  /**
505
647
  * Creates a new Color instance from miscellaneous formats
506
648
  * - It can receive Color instance and just return the same instance
@@ -573,25 +715,7 @@
573
715
  * @returns Color object
574
716
  */
575
717
  static fromString(color) {
576
- const trimmed = color.trim();
577
- if (CSS_COLORS[trimmed]) {
578
- return Color.fromString(CSS_COLORS[trimmed]);
579
- }
580
- else if (Color.isHexColorString(trimmed)) {
581
- return Color.fromHex(trimmed);
582
- }
583
- if (HSL_REGEX_PATTERN.test(trimmed)) {
584
- return Color.fromHsl(trimmed);
585
- }
586
- else if (RGB_REGEX_PATTERN.test(trimmed)) {
587
- return Color.fromRgbString(trimmed);
588
- }
589
- else if (RGBA_REGEX_PATTERN.test(trimmed)) {
590
- return Color.fromRgbaString(trimmed);
591
- }
592
- else {
593
- throw new Error(`Can not create a new Color instance from string "${trimmed}".`);
594
- }
718
+ return Color.fromColorChannels(parseColorString(color));
595
719
  }
596
720
  /**
597
721
  * Gets common color
@@ -621,8 +745,7 @@
621
745
  * @returns Color object
622
746
  */
623
747
  static fromHex(hex) {
624
- const { red, green, blue, alpha } = parseHexColor(hex);
625
- return take(new Color(red, green, blue, alpha));
748
+ return Color.fromColorChannels(parseHexColor(hex));
626
749
  }
627
750
  /**
628
751
  * Creates a new Color instance from color in hsl format
@@ -631,8 +754,7 @@
631
754
  * @returns Color object
632
755
  */
633
756
  static fromHsl(hsl) {
634
- const { red, green, blue, alpha } = parseHslColor(hsl);
635
- return take(new Color(red, green, blue, alpha));
757
+ return Color.fromColorChannels(parseHslColor(hsl));
636
758
  }
637
759
  /**
638
760
  * Creates a new Color instance from color in rgb format
@@ -641,8 +763,7 @@
641
763
  * @returns Color object
642
764
  */
643
765
  static fromRgbString(rgb) {
644
- const { red, green, blue, alpha } = parseRgbColor(rgb);
645
- return take(new Color(red, green, blue, alpha));
766
+ return Color.fromColorChannels(parseRgbColor(rgb));
646
767
  }
647
768
  /**
648
769
  * Creates a new Color instance from color in rbga format
@@ -651,8 +772,7 @@
651
772
  * @returns Color object
652
773
  */
653
774
  static fromRgbaString(rgba) {
654
- const { red, green, blue, alpha } = parseRgbaColor(rgba);
655
- return take(new Color(red, green, blue, alpha));
775
+ return Color.fromColorChannels(parseRgbaColor(rgba));
656
776
  }
657
777
  /**
658
778
  * Creates a new Color for color channels values
@@ -664,7 +784,7 @@
664
784
  * @returns Color object
665
785
  */
666
786
  static fromValues(red, green, blue, alpha = 255) {
667
- return take(new Color(red, green, blue, alpha));
787
+ return Color.fromColorChannels({ red, green, blue, alpha });
668
788
  }
669
789
  /**
670
790
  * Checks if the given value is a valid Color object.
@@ -697,8 +817,7 @@
697
817
  * @returns true if the value is a valid hex color string (e.g., `#009edd`, `#fff`, etc.)
698
818
  */
699
819
  static isHexColorString(value) {
700
- return (typeof value === 'string' &&
701
- /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(value));
820
+ return isHexColorString(value);
702
821
  }
703
822
  /**
704
823
  * Creates new Color object
@@ -711,89 +830,13 @@
711
830
  * @param alpha number from 0 (transparent) to 255 (opaque)
712
831
  */
713
832
  constructor(red, green, blue, alpha = 255) {
714
- this.red = red;
715
- this.green = green;
716
- this.blue = blue;
717
- this.alpha = alpha;
718
- checkChannelValue('Red', red);
719
- checkChannelValue('Green', green);
720
- checkChannelValue('Blue', blue);
721
- checkChannelValue('Alpha', alpha);
833
+ super(red, green, blue, alpha);
722
834
  }
723
- /**
724
- * Shortcut for `red` property
725
- * Number from 0 to 255
726
- * @alias red
727
- */
728
- get r() {
729
- return this.red;
835
+ createColor(red, green, blue, alpha) {
836
+ return new Color(red, green, blue, alpha);
730
837
  }
731
- /**
732
- * Shortcut for `green` property
733
- * Number from 0 to 255
734
- * @alias green
735
- */
736
- get g() {
737
- return this.green;
738
- }
739
- /**
740
- * Shortcut for `blue` property
741
- * Number from 0 to 255
742
- * @alias blue
743
- */
744
- get b() {
745
- return this.blue;
746
- }
747
- /**
748
- * Shortcut for `alpha` property
749
- * Number from 0 (transparent) to 255 (opaque)
750
- * @alias alpha
751
- */
752
- get a() {
753
- return this.alpha;
754
- }
755
- /**
756
- * Shortcut for `alpha` property
757
- * Number from 0 (transparent) to 255 (opaque)
758
- * @alias alpha
759
- */
760
- get opacity() {
761
- return this.alpha;
762
- }
763
- /**
764
- * Shortcut for 1-`alpha` property
765
- */
766
- get transparency() {
767
- return 255 - this.alpha;
768
- }
769
- clone() {
770
- return take(new Color(this.red, this.green, this.blue, this.alpha));
771
- }
772
- toString() {
773
- return this.toHex();
774
- }
775
- toHex() {
776
- if (this.alpha === 255) {
777
- return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
778
- .toString(16)
779
- .padStart(2, '0')}`;
780
- }
781
- else {
782
- return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
783
- .toString(16)
784
- .padStart(2, '0')}${this.alpha.toString(16).padStart(2, '0')}`;
785
- }
786
- }
787
- toRgb() {
788
- if (this.alpha === 255) {
789
- return `rgb(${this.red}, ${this.green}, ${this.blue})`;
790
- }
791
- else {
792
- return `rgba(${this.red}, ${this.green}, ${this.blue}, ${Math.round((this.alpha / 255) * 100)}%)`;
793
- }
794
- }
795
- toHsl() {
796
- throw new Error(`Getting HSL is not implemented`);
838
+ static fromColorChannels({ red, green, blue, alpha }) {
839
+ return take(new Color(red, green, blue, alpha));
797
840
  }
798
841
  }
799
842
 
@@ -2175,120 +2218,183 @@
2175
2218
  * @public exported from `@promptbook/utils`
2176
2219
  */
2177
2220
  function checkSerializableAsJson(options) {
2178
- const { value, name, message } = options;
2221
+ checkSerializableValue(options);
2222
+ }
2223
+ // TODO: Can be return type more type-safe? like `asserts options.value is JsonValue`
2224
+ // TODO: [🧠][main] !!3 In-memory cache of same values to prevent multiple checks
2225
+ // Note: [🐠] This is how `checkSerializableAsJson` + `isSerializableAsJson` together can just retun true/false or rich error message
2226
+ /**
2227
+ * Checks one value and dispatches to the appropriate specialized validator.
2228
+ *
2229
+ * @private function of `checkSerializableAsJson`
2230
+ */
2231
+ function checkSerializableValue(options) {
2232
+ const { value } = options;
2233
+ if (isSerializablePrimitive(value)) {
2234
+ return;
2235
+ }
2179
2236
  if (value === undefined) {
2180
- throw new UnexpectedError(`${name} is undefined`);
2237
+ throw new UnexpectedError(`${options.name} is undefined`);
2181
2238
  }
2182
- else if (value === null) {
2183
- return;
2239
+ if (typeof value === 'symbol') {
2240
+ throw new UnexpectedError(`${options.name} is symbol`);
2184
2241
  }
2185
- else if (typeof value === 'boolean') {
2186
- return;
2242
+ if (typeof value === 'function') {
2243
+ throw new UnexpectedError(`${options.name} is function`);
2187
2244
  }
2188
- else if (typeof value === 'number' && !isNaN(value)) {
2245
+ if (Array.isArray(value)) {
2246
+ checkSerializableArray(options, value);
2189
2247
  return;
2190
2248
  }
2191
- else if (typeof value === 'string') {
2249
+ if (value !== null && typeof value === 'object') {
2250
+ checkSerializableObject(options, value);
2192
2251
  return;
2193
2252
  }
2194
- else if (typeof value === 'symbol') {
2195
- throw new UnexpectedError(`${name} is symbol`);
2196
- }
2197
- else if (typeof value === 'function') {
2198
- throw new UnexpectedError(`${name} is function`);
2199
- }
2200
- else if (typeof value === 'object' && Array.isArray(value)) {
2201
- for (let i = 0; i < value.length; i++) {
2202
- checkSerializableAsJson({ name: `${name}[${i}]`, value: value[i], message });
2203
- }
2253
+ throwUnknownTypeError(options);
2254
+ }
2255
+ /**
2256
+ * Checks the primitive values that are directly JSON serializable.
2257
+ *
2258
+ * @private function of `checkSerializableAsJson`
2259
+ */
2260
+ function isSerializablePrimitive(value) {
2261
+ return (value === null ||
2262
+ typeof value === 'boolean' ||
2263
+ (typeof value === 'number' && !isNaN(value)) ||
2264
+ typeof value === 'string');
2265
+ }
2266
+ /**
2267
+ * Recursively checks JSON array items.
2268
+ *
2269
+ * @private function of `checkSerializableAsJson`
2270
+ */
2271
+ function checkSerializableArray(context, arrayValue) {
2272
+ for (let index = 0; index < arrayValue.length; index++) {
2273
+ checkSerializableAsJson({
2274
+ ...context,
2275
+ name: `${context.name}[${index}]`,
2276
+ value: arrayValue[index],
2277
+ });
2204
2278
  }
2205
- else if (typeof value === 'object') {
2206
- if (value instanceof Date) {
2207
- throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2208
- \`${name}\` is Date
2279
+ }
2280
+ /**
2281
+ * Checks object-like values and dispatches special unsupported built-ins.
2282
+ *
2283
+ * @private function of `checkSerializableAsJson`
2284
+ */
2285
+ function checkSerializableObject(context, objectValue) {
2286
+ checkUnsupportedObjectType(context, objectValue);
2287
+ checkSerializableObjectEntries(context, objectValue);
2288
+ assertJsonStringificationSucceeds(context, objectValue);
2289
+ }
2290
+ /**
2291
+ * Rejects built-in objects that must be converted before JSON serialization.
2292
+ *
2293
+ * @private function of `checkSerializableAsJson`
2294
+ */
2295
+ function checkUnsupportedObjectType(context, objectValue) {
2296
+ if (objectValue instanceof Date) {
2297
+ throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2298
+ \`${context.name}\` is Date
2209
2299
 
2210
- Use \`string_date_iso8601\` instead
2300
+ Use \`string_date_iso8601\` instead
2211
2301
 
2212
- Additional message for \`${name}\`:
2213
- ${block(message || '(nothing)')}
2214
- `));
2215
- }
2216
- else if (value instanceof Map) {
2217
- throw new UnexpectedError(`${name} is Map`);
2218
- }
2219
- else if (value instanceof Set) {
2220
- throw new UnexpectedError(`${name} is Set`);
2221
- }
2222
- else if (value instanceof RegExp) {
2223
- throw new UnexpectedError(`${name} is RegExp`);
2224
- }
2225
- else if (value instanceof Error) {
2226
- throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2227
- \`${name}\` is unserialized Error
2302
+ Additional message for \`${context.name}\`:
2303
+ ${block(context.message || '(nothing)')}
2304
+ `));
2305
+ }
2306
+ if (objectValue instanceof Map) {
2307
+ throw new UnexpectedError(`${context.name} is Map`);
2308
+ }
2309
+ if (objectValue instanceof Set) {
2310
+ throw new UnexpectedError(`${context.name} is Set`);
2311
+ }
2312
+ if (objectValue instanceof RegExp) {
2313
+ throw new UnexpectedError(`${context.name} is RegExp`);
2314
+ }
2315
+ if (objectValue instanceof Error) {
2316
+ throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2317
+ \`${context.name}\` is unserialized Error
2228
2318
 
2229
- Use function \`serializeError\`
2319
+ Use function \`serializeError\`
2230
2320
 
2231
- Additional message for \`${name}\`:
2232
- ${block(message || '(nothing)')}
2321
+ Additional message for \`${context.name}\`:
2322
+ ${block(context.message || '(nothing)')}
2233
2323
 
2234
- `));
2324
+ `));
2325
+ }
2326
+ }
2327
+ /**
2328
+ * Recursively checks object properties while preserving omitted `undefined` keys.
2329
+ *
2330
+ * @private function of `checkSerializableAsJson`
2331
+ */
2332
+ function checkSerializableObjectEntries(context, objectValue) {
2333
+ for (const [subName, subValue] of Object.entries(objectValue)) {
2334
+ if (subValue === undefined) {
2335
+ // Note: undefined in object is serializable - it is just omitted
2336
+ continue;
2235
2337
  }
2236
- else {
2237
- for (const [subName, subValue] of Object.entries(value)) {
2238
- if (subValue === undefined) {
2239
- // Note: undefined in object is serializable - it is just omitted
2240
- continue;
2241
- }
2242
- checkSerializableAsJson({ name: `${name}.${subName}`, value: subValue, message });
2243
- }
2244
- try {
2245
- JSON.stringify(value); // <- TODO: [0]
2246
- }
2247
- catch (error) {
2248
- assertsError(error);
2249
- throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2250
- \`${name}\` is not serializable
2338
+ checkSerializableAsJson({
2339
+ ...context,
2340
+ name: `${context.name}.${subName}`,
2341
+ value: subValue,
2342
+ });
2343
+ }
2344
+ }
2345
+ /**
2346
+ * Uses `JSON.stringify` as the final guard for cases like circular references.
2347
+ *
2348
+ * @private function of `checkSerializableAsJson`
2349
+ */
2350
+ function assertJsonStringificationSucceeds(context, objectValue) {
2351
+ try {
2352
+ JSON.stringify(objectValue); // <- TODO: [0]
2353
+ }
2354
+ catch (error) {
2355
+ assertsError(error);
2356
+ throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2357
+ \`${context.name}\` is not serializable
2251
2358
 
2252
- ${block(error.stack || error.message)}
2359
+ ${block(error.stack || error.message)}
2253
2360
 
2254
- Additional message for \`${name}\`:
2255
- ${block(message || '(nothing)')}
2256
- `));
2361
+ Additional message for \`${context.name}\`:
2362
+ ${block(context.message || '(nothing)')}
2363
+ `));
2364
+ }
2365
+ /*
2366
+ TODO: [0] Is there some more elegant way to check circular references?
2367
+ const seen = new Set();
2368
+ const stack = [{ value }];
2369
+ while (stack.length > 0) {
2370
+ const { value } = stack.pop()!;
2371
+ if (typeof value === 'object' && value !== null) {
2372
+ if (seen.has(value)) {
2373
+ throw new UnexpectedError(`${name} has circular reference`);
2257
2374
  }
2258
- /*
2259
- TODO: [0] Is there some more elegant way to check circular references?
2260
- const seen = new Set();
2261
- const stack = [{ value }];
2262
- while (stack.length > 0) {
2263
- const { value } = stack.pop()!;
2264
- if (typeof value === 'object' && value !== null) {
2265
- if (seen.has(value)) {
2266
- throw new UnexpectedError(`${name} has circular reference`);
2267
- }
2268
- seen.add(value);
2269
- if (Array.isArray(value)) {
2270
- stack.push(...value.map((value) => ({ value })));
2271
- } else {
2272
- stack.push(...Object.values(value).map((value) => ({ value })));
2273
- }
2274
- }
2375
+ seen.add(value);
2376
+ if (Array.isArray(value)) {
2377
+ stack.push(...value.map((value) => ({ value })));
2378
+ } else {
2379
+ stack.push(...Object.values(value).map((value) => ({ value })));
2275
2380
  }
2276
- */
2277
- return;
2278
2381
  }
2279
2382
  }
2280
- else {
2281
- throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2282
- \`${name}\` is unknown type
2383
+ */
2384
+ }
2385
+ /**
2386
+ * Throws the fallback error for unsupported value types like `bigint` and `NaN`.
2387
+ *
2388
+ * @private function of `checkSerializableAsJson`
2389
+ */
2390
+ function throwUnknownTypeError(context) {
2391
+ throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2392
+ \`${context.name}\` is unknown type
2283
2393
 
2284
- Additional message for \`${name}\`:
2285
- ${block(message || '(nothing)')}
2286
- `));
2287
- }
2394
+ Additional message for \`${context.name}\`:
2395
+ ${block(context.message || '(nothing)')}
2396
+ `));
2288
2397
  }
2289
- // TODO: Can be return type more type-safe? like `asserts options.value is JsonValue`
2290
- // TODO: [🧠][main] !!3 In-memory cache of same values to prevent multiple checks
2291
- // Note: [🐠] This is how `checkSerializableAsJson` + `isSerializableAsJson` together can just retun true/false or rich error message
2292
2398
 
2293
2399
  /**
2294
2400
  * Creates a deep clone of the given object