@promptbook/markdown-utils 0.112.0-73 → 0.112.0-81

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 +313 -210
  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 +1 -1
  37. package/umd/index.umd.js +313 -210
  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
@@ -23,7 +23,7 @@
23
23
  * @generated
24
24
  * @see https://github.com/webgptorg/promptbook
25
25
  */
26
- const PROMPTBOOK_ENGINE_VERSION = '0.112.0-73';
26
+ const PROMPTBOOK_ENGINE_VERSION = '0.112.0-81';
27
27
  /**
28
28
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
29
29
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -413,6 +413,111 @@
413
413
  }
414
414
  }
415
415
 
416
+ /**
417
+ * Shared immutable channel storage and serialization helpers for `Color`.
418
+ *
419
+ * @private base class of Color
420
+ */
421
+ class ColorValue {
422
+ constructor(red, green, blue, alpha = 255) {
423
+ this.red = red;
424
+ this.green = green;
425
+ this.blue = blue;
426
+ this.alpha = alpha;
427
+ checkChannelValue('Red', red);
428
+ checkChannelValue('Green', green);
429
+ checkChannelValue('Blue', blue);
430
+ checkChannelValue('Alpha', alpha);
431
+ }
432
+ /**
433
+ * Shortcut for `red` property
434
+ * Number from 0 to 255
435
+ * @alias red
436
+ */
437
+ get r() {
438
+ return this.red;
439
+ }
440
+ /**
441
+ * Shortcut for `green` property
442
+ * Number from 0 to 255
443
+ * @alias green
444
+ */
445
+ get g() {
446
+ return this.green;
447
+ }
448
+ /**
449
+ * Shortcut for `blue` property
450
+ * Number from 0 to 255
451
+ * @alias blue
452
+ */
453
+ get b() {
454
+ return this.blue;
455
+ }
456
+ /**
457
+ * Shortcut for `alpha` property
458
+ * Number from 0 (transparent) to 255 (opaque)
459
+ * @alias alpha
460
+ */
461
+ get a() {
462
+ return this.alpha;
463
+ }
464
+ /**
465
+ * Shortcut for `alpha` property
466
+ * Number from 0 (transparent) to 255 (opaque)
467
+ * @alias alpha
468
+ */
469
+ get opacity() {
470
+ return this.alpha;
471
+ }
472
+ /**
473
+ * Shortcut for 1-`alpha` property
474
+ */
475
+ get transparency() {
476
+ return 255 - this.alpha;
477
+ }
478
+ clone() {
479
+ return take(this.createColor(this.red, this.green, this.blue, this.alpha));
480
+ }
481
+ toString() {
482
+ return this.toHex();
483
+ }
484
+ toHex() {
485
+ if (this.alpha === 255) {
486
+ return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
487
+ .toString(16)
488
+ .padStart(2, '0')}`;
489
+ }
490
+ else {
491
+ return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
492
+ .toString(16)
493
+ .padStart(2, '0')}${this.alpha.toString(16).padStart(2, '0')}`;
494
+ }
495
+ }
496
+ toRgb() {
497
+ if (this.alpha === 255) {
498
+ return `rgb(${this.red}, ${this.green}, ${this.blue})`;
499
+ }
500
+ else {
501
+ return `rgba(${this.red}, ${this.green}, ${this.blue}, ${Math.round((this.alpha / 255) * 100)}%)`;
502
+ }
503
+ }
504
+ toHsl() {
505
+ throw new Error(`Getting HSL is not implemented`);
506
+ }
507
+ }
508
+
509
+ /**
510
+ * Checks if the given value is a valid hex color string
511
+ *
512
+ * @param value - value to check
513
+ * @returns true if the value is a valid hex color string (e.g., `#009edd`, `#fff`, etc.)
514
+ *
515
+ * @private function of Color
516
+ */
517
+ function isHexColorString(value) {
518
+ 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));
519
+ }
520
+
416
521
  /**
417
522
  * Constant for short hex lengths.
418
523
  */
@@ -624,16 +729,53 @@
624
729
 
625
730
  /**
626
731
  * Pattern matching hsl regex.
732
+ *
733
+ * @private function of Color
627
734
  */
628
735
  const HSL_REGEX_PATTERN = /^hsl\(\s*([0-9.]+)\s*,\s*([0-9.]+)%\s*,\s*([0-9.]+)%\s*\)$/;
629
736
  /**
630
737
  * Pattern matching RGB regex.
738
+ *
739
+ * @private function of Color
631
740
  */
632
741
  const RGB_REGEX_PATTERN = /^rgb\(\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*\)$/;
633
742
  /**
634
743
  * Pattern matching rgba regex.
744
+ *
745
+ * @private function of Color
635
746
  */
636
747
  const RGBA_REGEX_PATTERN = /^rgba\(\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*\)$/;
748
+ /**
749
+ * Parses a supported color string into RGBA channels.
750
+ *
751
+ * @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`,...
752
+ * @returns RGBA channel values.
753
+ *
754
+ * @private function of Color
755
+ */
756
+ function parseColorString(color) {
757
+ const trimmed = color.trim();
758
+ const cssColor = CSS_COLORS[trimmed];
759
+ if (cssColor) {
760
+ return parseColorString(cssColor);
761
+ }
762
+ else if (isHexColorString(trimmed)) {
763
+ return parseHexColor(trimmed);
764
+ }
765
+ if (HSL_REGEX_PATTERN.test(trimmed)) {
766
+ return parseHslColor(trimmed);
767
+ }
768
+ else if (RGB_REGEX_PATTERN.test(trimmed)) {
769
+ return parseRgbColor(trimmed);
770
+ }
771
+ else if (RGBA_REGEX_PATTERN.test(trimmed)) {
772
+ return parseRgbaColor(trimmed);
773
+ }
774
+ else {
775
+ throw new Error(`Can not create a new Color instance from string "${trimmed}".`);
776
+ }
777
+ }
778
+
637
779
  /**
638
780
  * Color object represents an RGB color with alpha channel
639
781
  *
@@ -641,7 +783,7 @@
641
783
  *
642
784
  * @public exported from `@promptbook/color`
643
785
  */
644
- class Color {
786
+ class Color extends ColorValue {
645
787
  /**
646
788
  * Creates a new Color instance from miscellaneous formats
647
789
  * - It can receive Color instance and just return the same instance
@@ -714,25 +856,7 @@
714
856
  * @returns Color object
715
857
  */
716
858
  static fromString(color) {
717
- const trimmed = color.trim();
718
- if (CSS_COLORS[trimmed]) {
719
- return Color.fromString(CSS_COLORS[trimmed]);
720
- }
721
- else if (Color.isHexColorString(trimmed)) {
722
- return Color.fromHex(trimmed);
723
- }
724
- if (HSL_REGEX_PATTERN.test(trimmed)) {
725
- return Color.fromHsl(trimmed);
726
- }
727
- else if (RGB_REGEX_PATTERN.test(trimmed)) {
728
- return Color.fromRgbString(trimmed);
729
- }
730
- else if (RGBA_REGEX_PATTERN.test(trimmed)) {
731
- return Color.fromRgbaString(trimmed);
732
- }
733
- else {
734
- throw new Error(`Can not create a new Color instance from string "${trimmed}".`);
735
- }
859
+ return Color.fromColorChannels(parseColorString(color));
736
860
  }
737
861
  /**
738
862
  * Gets common color
@@ -762,8 +886,7 @@
762
886
  * @returns Color object
763
887
  */
764
888
  static fromHex(hex) {
765
- const { red, green, blue, alpha } = parseHexColor(hex);
766
- return take(new Color(red, green, blue, alpha));
889
+ return Color.fromColorChannels(parseHexColor(hex));
767
890
  }
768
891
  /**
769
892
  * Creates a new Color instance from color in hsl format
@@ -772,8 +895,7 @@
772
895
  * @returns Color object
773
896
  */
774
897
  static fromHsl(hsl) {
775
- const { red, green, blue, alpha } = parseHslColor(hsl);
776
- return take(new Color(red, green, blue, alpha));
898
+ return Color.fromColorChannels(parseHslColor(hsl));
777
899
  }
778
900
  /**
779
901
  * Creates a new Color instance from color in rgb format
@@ -782,8 +904,7 @@
782
904
  * @returns Color object
783
905
  */
784
906
  static fromRgbString(rgb) {
785
- const { red, green, blue, alpha } = parseRgbColor(rgb);
786
- return take(new Color(red, green, blue, alpha));
907
+ return Color.fromColorChannels(parseRgbColor(rgb));
787
908
  }
788
909
  /**
789
910
  * Creates a new Color instance from color in rbga format
@@ -792,8 +913,7 @@
792
913
  * @returns Color object
793
914
  */
794
915
  static fromRgbaString(rgba) {
795
- const { red, green, blue, alpha } = parseRgbaColor(rgba);
796
- return take(new Color(red, green, blue, alpha));
916
+ return Color.fromColorChannels(parseRgbaColor(rgba));
797
917
  }
798
918
  /**
799
919
  * Creates a new Color for color channels values
@@ -805,7 +925,7 @@
805
925
  * @returns Color object
806
926
  */
807
927
  static fromValues(red, green, blue, alpha = 255) {
808
- return take(new Color(red, green, blue, alpha));
928
+ return Color.fromColorChannels({ red, green, blue, alpha });
809
929
  }
810
930
  /**
811
931
  * Checks if the given value is a valid Color object.
@@ -838,8 +958,7 @@
838
958
  * @returns true if the value is a valid hex color string (e.g., `#009edd`, `#fff`, etc.)
839
959
  */
840
960
  static isHexColorString(value) {
841
- return (typeof value === 'string' &&
842
- /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(value));
961
+ return isHexColorString(value);
843
962
  }
844
963
  /**
845
964
  * Creates new Color object
@@ -852,89 +971,13 @@
852
971
  * @param alpha number from 0 (transparent) to 255 (opaque)
853
972
  */
854
973
  constructor(red, green, blue, alpha = 255) {
855
- this.red = red;
856
- this.green = green;
857
- this.blue = blue;
858
- this.alpha = alpha;
859
- checkChannelValue('Red', red);
860
- checkChannelValue('Green', green);
861
- checkChannelValue('Blue', blue);
862
- checkChannelValue('Alpha', alpha);
863
- }
864
- /**
865
- * Shortcut for `red` property
866
- * Number from 0 to 255
867
- * @alias red
868
- */
869
- get r() {
870
- return this.red;
871
- }
872
- /**
873
- * Shortcut for `green` property
874
- * Number from 0 to 255
875
- * @alias green
876
- */
877
- get g() {
878
- return this.green;
974
+ super(red, green, blue, alpha);
879
975
  }
880
- /**
881
- * Shortcut for `blue` property
882
- * Number from 0 to 255
883
- * @alias blue
884
- */
885
- get b() {
886
- return this.blue;
887
- }
888
- /**
889
- * Shortcut for `alpha` property
890
- * Number from 0 (transparent) to 255 (opaque)
891
- * @alias alpha
892
- */
893
- get a() {
894
- return this.alpha;
976
+ createColor(red, green, blue, alpha) {
977
+ return new Color(red, green, blue, alpha);
895
978
  }
896
- /**
897
- * Shortcut for `alpha` property
898
- * Number from 0 (transparent) to 255 (opaque)
899
- * @alias alpha
900
- */
901
- get opacity() {
902
- return this.alpha;
903
- }
904
- /**
905
- * Shortcut for 1-`alpha` property
906
- */
907
- get transparency() {
908
- return 255 - this.alpha;
909
- }
910
- clone() {
911
- return take(new Color(this.red, this.green, this.blue, this.alpha));
912
- }
913
- toString() {
914
- return this.toHex();
915
- }
916
- toHex() {
917
- if (this.alpha === 255) {
918
- return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
919
- .toString(16)
920
- .padStart(2, '0')}`;
921
- }
922
- else {
923
- return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
924
- .toString(16)
925
- .padStart(2, '0')}${this.alpha.toString(16).padStart(2, '0')}`;
926
- }
927
- }
928
- toRgb() {
929
- if (this.alpha === 255) {
930
- return `rgb(${this.red}, ${this.green}, ${this.blue})`;
931
- }
932
- else {
933
- return `rgba(${this.red}, ${this.green}, ${this.blue}, ${Math.round((this.alpha / 255) * 100)}%)`;
934
- }
935
- }
936
- toHsl() {
937
- throw new Error(`Getting HSL is not implemented`);
979
+ static fromColorChannels({ red, green, blue, alpha }) {
980
+ return take(new Color(red, green, blue, alpha));
938
981
  }
939
982
  }
940
983
 
@@ -1870,7 +1913,7 @@
1870
1913
  */
1871
1914
  function createPostprocessingCommands(task) {
1872
1915
  var _a;
1873
- return ((_a = task.postprocessingFunctionNames) === null || _a === void 0 ? void 0 : _a.map((postprocessingFunctionName) => `POSTPROCESSING \`${postprocessingFunctionName}\``)) || [];
1916
+ return (((_a = task.postprocessingFunctionNames) === null || _a === void 0 ? void 0 : _a.map((postprocessingFunctionName) => `POSTPROCESSING \`${postprocessingFunctionName}\``)) || []);
1874
1917
  }
1875
1918
  /**
1876
1919
  * Collects expectation commands.
@@ -2035,120 +2078,183 @@
2035
2078
  * @public exported from `@promptbook/utils`
2036
2079
  */
2037
2080
  function checkSerializableAsJson(options) {
2038
- const { value, name, message } = options;
2081
+ checkSerializableValue(options);
2082
+ }
2083
+ // TODO: Can be return type more type-safe? like `asserts options.value is JsonValue`
2084
+ // TODO: [🧠][main] !!3 In-memory cache of same values to prevent multiple checks
2085
+ // Note: [🐠] This is how `checkSerializableAsJson` + `isSerializableAsJson` together can just retun true/false or rich error message
2086
+ /**
2087
+ * Checks one value and dispatches to the appropriate specialized validator.
2088
+ *
2089
+ * @private function of `checkSerializableAsJson`
2090
+ */
2091
+ function checkSerializableValue(options) {
2092
+ const { value } = options;
2093
+ if (isSerializablePrimitive(value)) {
2094
+ return;
2095
+ }
2039
2096
  if (value === undefined) {
2040
- throw new UnexpectedError(`${name} is undefined`);
2097
+ throw new UnexpectedError(`${options.name} is undefined`);
2041
2098
  }
2042
- else if (value === null) {
2043
- return;
2099
+ if (typeof value === 'symbol') {
2100
+ throw new UnexpectedError(`${options.name} is symbol`);
2044
2101
  }
2045
- else if (typeof value === 'boolean') {
2046
- return;
2102
+ if (typeof value === 'function') {
2103
+ throw new UnexpectedError(`${options.name} is function`);
2047
2104
  }
2048
- else if (typeof value === 'number' && !isNaN(value)) {
2105
+ if (Array.isArray(value)) {
2106
+ checkSerializableArray(options, value);
2049
2107
  return;
2050
2108
  }
2051
- else if (typeof value === 'string') {
2109
+ if (value !== null && typeof value === 'object') {
2110
+ checkSerializableObject(options, value);
2052
2111
  return;
2053
2112
  }
2054
- else if (typeof value === 'symbol') {
2055
- throw new UnexpectedError(`${name} is symbol`);
2056
- }
2057
- else if (typeof value === 'function') {
2058
- throw new UnexpectedError(`${name} is function`);
2059
- }
2060
- else if (typeof value === 'object' && Array.isArray(value)) {
2061
- for (let i = 0; i < value.length; i++) {
2062
- checkSerializableAsJson({ name: `${name}[${i}]`, value: value[i], message });
2063
- }
2113
+ throwUnknownTypeError(options);
2114
+ }
2115
+ /**
2116
+ * Checks the primitive values that are directly JSON serializable.
2117
+ *
2118
+ * @private function of `checkSerializableAsJson`
2119
+ */
2120
+ function isSerializablePrimitive(value) {
2121
+ return (value === null ||
2122
+ typeof value === 'boolean' ||
2123
+ (typeof value === 'number' && !isNaN(value)) ||
2124
+ typeof value === 'string');
2125
+ }
2126
+ /**
2127
+ * Recursively checks JSON array items.
2128
+ *
2129
+ * @private function of `checkSerializableAsJson`
2130
+ */
2131
+ function checkSerializableArray(context, arrayValue) {
2132
+ for (let index = 0; index < arrayValue.length; index++) {
2133
+ checkSerializableAsJson({
2134
+ ...context,
2135
+ name: `${context.name}[${index}]`,
2136
+ value: arrayValue[index],
2137
+ });
2064
2138
  }
2065
- else if (typeof value === 'object') {
2066
- if (value instanceof Date) {
2067
- throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2068
- \`${name}\` is Date
2139
+ }
2140
+ /**
2141
+ * Checks object-like values and dispatches special unsupported built-ins.
2142
+ *
2143
+ * @private function of `checkSerializableAsJson`
2144
+ */
2145
+ function checkSerializableObject(context, objectValue) {
2146
+ checkUnsupportedObjectType(context, objectValue);
2147
+ checkSerializableObjectEntries(context, objectValue);
2148
+ assertJsonStringificationSucceeds(context, objectValue);
2149
+ }
2150
+ /**
2151
+ * Rejects built-in objects that must be converted before JSON serialization.
2152
+ *
2153
+ * @private function of `checkSerializableAsJson`
2154
+ */
2155
+ function checkUnsupportedObjectType(context, objectValue) {
2156
+ if (objectValue instanceof Date) {
2157
+ throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2158
+ \`${context.name}\` is Date
2069
2159
 
2070
- Use \`string_date_iso8601\` instead
2160
+ Use \`string_date_iso8601\` instead
2071
2161
 
2072
- Additional message for \`${name}\`:
2073
- ${block(message || '(nothing)')}
2074
- `));
2075
- }
2076
- else if (value instanceof Map) {
2077
- throw new UnexpectedError(`${name} is Map`);
2078
- }
2079
- else if (value instanceof Set) {
2080
- throw new UnexpectedError(`${name} is Set`);
2081
- }
2082
- else if (value instanceof RegExp) {
2083
- throw new UnexpectedError(`${name} is RegExp`);
2084
- }
2085
- else if (value instanceof Error) {
2086
- throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2087
- \`${name}\` is unserialized Error
2162
+ Additional message for \`${context.name}\`:
2163
+ ${block(context.message || '(nothing)')}
2164
+ `));
2165
+ }
2166
+ if (objectValue instanceof Map) {
2167
+ throw new UnexpectedError(`${context.name} is Map`);
2168
+ }
2169
+ if (objectValue instanceof Set) {
2170
+ throw new UnexpectedError(`${context.name} is Set`);
2171
+ }
2172
+ if (objectValue instanceof RegExp) {
2173
+ throw new UnexpectedError(`${context.name} is RegExp`);
2174
+ }
2175
+ if (objectValue instanceof Error) {
2176
+ throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2177
+ \`${context.name}\` is unserialized Error
2088
2178
 
2089
- Use function \`serializeError\`
2179
+ Use function \`serializeError\`
2090
2180
 
2091
- Additional message for \`${name}\`:
2092
- ${block(message || '(nothing)')}
2181
+ Additional message for \`${context.name}\`:
2182
+ ${block(context.message || '(nothing)')}
2093
2183
 
2094
- `));
2184
+ `));
2185
+ }
2186
+ }
2187
+ /**
2188
+ * Recursively checks object properties while preserving omitted `undefined` keys.
2189
+ *
2190
+ * @private function of `checkSerializableAsJson`
2191
+ */
2192
+ function checkSerializableObjectEntries(context, objectValue) {
2193
+ for (const [subName, subValue] of Object.entries(objectValue)) {
2194
+ if (subValue === undefined) {
2195
+ // Note: undefined in object is serializable - it is just omitted
2196
+ continue;
2095
2197
  }
2096
- else {
2097
- for (const [subName, subValue] of Object.entries(value)) {
2098
- if (subValue === undefined) {
2099
- // Note: undefined in object is serializable - it is just omitted
2100
- continue;
2101
- }
2102
- checkSerializableAsJson({ name: `${name}.${subName}`, value: subValue, message });
2103
- }
2104
- try {
2105
- JSON.stringify(value); // <- TODO: [0]
2106
- }
2107
- catch (error) {
2108
- assertsError(error);
2109
- throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2110
- \`${name}\` is not serializable
2198
+ checkSerializableAsJson({
2199
+ ...context,
2200
+ name: `${context.name}.${subName}`,
2201
+ value: subValue,
2202
+ });
2203
+ }
2204
+ }
2205
+ /**
2206
+ * Uses `JSON.stringify` as the final guard for cases like circular references.
2207
+ *
2208
+ * @private function of `checkSerializableAsJson`
2209
+ */
2210
+ function assertJsonStringificationSucceeds(context, objectValue) {
2211
+ try {
2212
+ JSON.stringify(objectValue); // <- TODO: [0]
2213
+ }
2214
+ catch (error) {
2215
+ assertsError(error);
2216
+ throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2217
+ \`${context.name}\` is not serializable
2111
2218
 
2112
- ${block(error.stack || error.message)}
2219
+ ${block(error.stack || error.message)}
2113
2220
 
2114
- Additional message for \`${name}\`:
2115
- ${block(message || '(nothing)')}
2116
- `));
2221
+ Additional message for \`${context.name}\`:
2222
+ ${block(context.message || '(nothing)')}
2223
+ `));
2224
+ }
2225
+ /*
2226
+ TODO: [0] Is there some more elegant way to check circular references?
2227
+ const seen = new Set();
2228
+ const stack = [{ value }];
2229
+ while (stack.length > 0) {
2230
+ const { value } = stack.pop()!;
2231
+ if (typeof value === 'object' && value !== null) {
2232
+ if (seen.has(value)) {
2233
+ throw new UnexpectedError(`${name} has circular reference`);
2117
2234
  }
2118
- /*
2119
- TODO: [0] Is there some more elegant way to check circular references?
2120
- const seen = new Set();
2121
- const stack = [{ value }];
2122
- while (stack.length > 0) {
2123
- const { value } = stack.pop()!;
2124
- if (typeof value === 'object' && value !== null) {
2125
- if (seen.has(value)) {
2126
- throw new UnexpectedError(`${name} has circular reference`);
2127
- }
2128
- seen.add(value);
2129
- if (Array.isArray(value)) {
2130
- stack.push(...value.map((value) => ({ value })));
2131
- } else {
2132
- stack.push(...Object.values(value).map((value) => ({ value })));
2133
- }
2134
- }
2235
+ seen.add(value);
2236
+ if (Array.isArray(value)) {
2237
+ stack.push(...value.map((value) => ({ value })));
2238
+ } else {
2239
+ stack.push(...Object.values(value).map((value) => ({ value })));
2135
2240
  }
2136
- */
2137
- return;
2138
2241
  }
2139
2242
  }
2140
- else {
2141
- throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2142
- \`${name}\` is unknown type
2243
+ */
2244
+ }
2245
+ /**
2246
+ * Throws the fallback error for unsupported value types like `bigint` and `NaN`.
2247
+ *
2248
+ * @private function of `checkSerializableAsJson`
2249
+ */
2250
+ function throwUnknownTypeError(context) {
2251
+ throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2252
+ \`${context.name}\` is unknown type
2143
2253
 
2144
- Additional message for \`${name}\`:
2145
- ${block(message || '(nothing)')}
2146
- `));
2147
- }
2254
+ Additional message for \`${context.name}\`:
2255
+ ${block(context.message || '(nothing)')}
2256
+ `));
2148
2257
  }
2149
- // TODO: Can be return type more type-safe? like `asserts options.value is JsonValue`
2150
- // TODO: [🧠][main] !!3 In-memory cache of same values to prevent multiple checks
2151
- // Note: [🐠] This is how `checkSerializableAsJson` + `isSerializableAsJson` together can just retun true/false or rich error message
2152
2258
 
2153
2259
  /**
2154
2260
  * Creates a deep clone of the given object
@@ -2712,8 +2818,7 @@
2712
2818
  * @private internal utility of `validatePipeline`
2713
2819
  */
2714
2820
  function validateTaskSupportsJokers(task, pipelineIdentification) {
2715
- if (task.format ||
2716
- task.expectations /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
2821
+ if (task.format || task.expectations /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
2717
2822
  return;
2718
2823
  }
2719
2824
  throw new PipelineLogicError(spacetrim.spaceTrim((block) => `
@@ -7103,9 +7208,7 @@
7103
7208
  ${block(quoteMultilineText(((_b = failure.error) === null || _b === void 0 ? void 0 : _b.message) || ''))}
7104
7209
 
7105
7210
  Result:
7106
- ${block(failure.result === null
7107
- ? 'null'
7108
- : quoteMultilineText(spacetrim.spaceTrim(failure.result)))}
7211
+ ${block(failure.result === null ? 'null' : quoteMultilineText(spacetrim.spaceTrim(failure.result)))}
7109
7212
  `;
7110
7213
  }))
7111
7214
  .join('\n\n---\n\n');