@promptbook/google 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
@@ -842,6 +842,111 @@
842
842
  }
843
843
  }
844
844
 
845
+ /**
846
+ * Shared immutable channel storage and serialization helpers for `Color`.
847
+ *
848
+ * @private base class of Color
849
+ */
850
+ class ColorValue {
851
+ constructor(red, green, blue, alpha = 255) {
852
+ this.red = red;
853
+ this.green = green;
854
+ this.blue = blue;
855
+ this.alpha = alpha;
856
+ checkChannelValue('Red', red);
857
+ checkChannelValue('Green', green);
858
+ checkChannelValue('Blue', blue);
859
+ checkChannelValue('Alpha', alpha);
860
+ }
861
+ /**
862
+ * Shortcut for `red` property
863
+ * Number from 0 to 255
864
+ * @alias red
865
+ */
866
+ get r() {
867
+ return this.red;
868
+ }
869
+ /**
870
+ * Shortcut for `green` property
871
+ * Number from 0 to 255
872
+ * @alias green
873
+ */
874
+ get g() {
875
+ return this.green;
876
+ }
877
+ /**
878
+ * Shortcut for `blue` property
879
+ * Number from 0 to 255
880
+ * @alias blue
881
+ */
882
+ get b() {
883
+ return this.blue;
884
+ }
885
+ /**
886
+ * Shortcut for `alpha` property
887
+ * Number from 0 (transparent) to 255 (opaque)
888
+ * @alias alpha
889
+ */
890
+ get a() {
891
+ return this.alpha;
892
+ }
893
+ /**
894
+ * Shortcut for `alpha` property
895
+ * Number from 0 (transparent) to 255 (opaque)
896
+ * @alias alpha
897
+ */
898
+ get opacity() {
899
+ return this.alpha;
900
+ }
901
+ /**
902
+ * Shortcut for 1-`alpha` property
903
+ */
904
+ get transparency() {
905
+ return 255 - this.alpha;
906
+ }
907
+ clone() {
908
+ return take(this.createColor(this.red, this.green, this.blue, this.alpha));
909
+ }
910
+ toString() {
911
+ return this.toHex();
912
+ }
913
+ toHex() {
914
+ if (this.alpha === 255) {
915
+ return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
916
+ .toString(16)
917
+ .padStart(2, '0')}`;
918
+ }
919
+ else {
920
+ return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
921
+ .toString(16)
922
+ .padStart(2, '0')}${this.alpha.toString(16).padStart(2, '0')}`;
923
+ }
924
+ }
925
+ toRgb() {
926
+ if (this.alpha === 255) {
927
+ return `rgb(${this.red}, ${this.green}, ${this.blue})`;
928
+ }
929
+ else {
930
+ return `rgba(${this.red}, ${this.green}, ${this.blue}, ${Math.round((this.alpha / 255) * 100)}%)`;
931
+ }
932
+ }
933
+ toHsl() {
934
+ throw new Error(`Getting HSL is not implemented`);
935
+ }
936
+ }
937
+
938
+ /**
939
+ * Checks if the given value is a valid hex color string
940
+ *
941
+ * @param value - value to check
942
+ * @returns true if the value is a valid hex color string (e.g., `#009edd`, `#fff`, etc.)
943
+ *
944
+ * @private function of Color
945
+ */
946
+ function isHexColorString(value) {
947
+ 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));
948
+ }
949
+
845
950
  /**
846
951
  * Constant for short hex lengths.
847
952
  */
@@ -1053,16 +1158,53 @@
1053
1158
 
1054
1159
  /**
1055
1160
  * Pattern matching hsl regex.
1161
+ *
1162
+ * @private function of Color
1056
1163
  */
1057
1164
  const HSL_REGEX_PATTERN = /^hsl\(\s*([0-9.]+)\s*,\s*([0-9.]+)%\s*,\s*([0-9.]+)%\s*\)$/;
1058
1165
  /**
1059
1166
  * Pattern matching RGB regex.
1167
+ *
1168
+ * @private function of Color
1060
1169
  */
1061
1170
  const RGB_REGEX_PATTERN = /^rgb\(\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*\)$/;
1062
1171
  /**
1063
1172
  * Pattern matching rgba regex.
1173
+ *
1174
+ * @private function of Color
1064
1175
  */
1065
1176
  const RGBA_REGEX_PATTERN = /^rgba\(\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*\)$/;
1177
+ /**
1178
+ * Parses a supported color string into RGBA channels.
1179
+ *
1180
+ * @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`,...
1181
+ * @returns RGBA channel values.
1182
+ *
1183
+ * @private function of Color
1184
+ */
1185
+ function parseColorString(color) {
1186
+ const trimmed = color.trim();
1187
+ const cssColor = CSS_COLORS[trimmed];
1188
+ if (cssColor) {
1189
+ return parseColorString(cssColor);
1190
+ }
1191
+ else if (isHexColorString(trimmed)) {
1192
+ return parseHexColor(trimmed);
1193
+ }
1194
+ if (HSL_REGEX_PATTERN.test(trimmed)) {
1195
+ return parseHslColor(trimmed);
1196
+ }
1197
+ else if (RGB_REGEX_PATTERN.test(trimmed)) {
1198
+ return parseRgbColor(trimmed);
1199
+ }
1200
+ else if (RGBA_REGEX_PATTERN.test(trimmed)) {
1201
+ return parseRgbaColor(trimmed);
1202
+ }
1203
+ else {
1204
+ throw new Error(`Can not create a new Color instance from string "${trimmed}".`);
1205
+ }
1206
+ }
1207
+
1066
1208
  /**
1067
1209
  * Color object represents an RGB color with alpha channel
1068
1210
  *
@@ -1070,7 +1212,7 @@
1070
1212
  *
1071
1213
  * @public exported from `@promptbook/color`
1072
1214
  */
1073
- class Color {
1215
+ class Color extends ColorValue {
1074
1216
  /**
1075
1217
  * Creates a new Color instance from miscellaneous formats
1076
1218
  * - It can receive Color instance and just return the same instance
@@ -1143,25 +1285,7 @@
1143
1285
  * @returns Color object
1144
1286
  */
1145
1287
  static fromString(color) {
1146
- const trimmed = color.trim();
1147
- if (CSS_COLORS[trimmed]) {
1148
- return Color.fromString(CSS_COLORS[trimmed]);
1149
- }
1150
- else if (Color.isHexColorString(trimmed)) {
1151
- return Color.fromHex(trimmed);
1152
- }
1153
- if (HSL_REGEX_PATTERN.test(trimmed)) {
1154
- return Color.fromHsl(trimmed);
1155
- }
1156
- else if (RGB_REGEX_PATTERN.test(trimmed)) {
1157
- return Color.fromRgbString(trimmed);
1158
- }
1159
- else if (RGBA_REGEX_PATTERN.test(trimmed)) {
1160
- return Color.fromRgbaString(trimmed);
1161
- }
1162
- else {
1163
- throw new Error(`Can not create a new Color instance from string "${trimmed}".`);
1164
- }
1288
+ return Color.fromColorChannels(parseColorString(color));
1165
1289
  }
1166
1290
  /**
1167
1291
  * Gets common color
@@ -1191,8 +1315,7 @@
1191
1315
  * @returns Color object
1192
1316
  */
1193
1317
  static fromHex(hex) {
1194
- const { red, green, blue, alpha } = parseHexColor(hex);
1195
- return take(new Color(red, green, blue, alpha));
1318
+ return Color.fromColorChannels(parseHexColor(hex));
1196
1319
  }
1197
1320
  /**
1198
1321
  * Creates a new Color instance from color in hsl format
@@ -1201,8 +1324,7 @@
1201
1324
  * @returns Color object
1202
1325
  */
1203
1326
  static fromHsl(hsl) {
1204
- const { red, green, blue, alpha } = parseHslColor(hsl);
1205
- return take(new Color(red, green, blue, alpha));
1327
+ return Color.fromColorChannels(parseHslColor(hsl));
1206
1328
  }
1207
1329
  /**
1208
1330
  * Creates a new Color instance from color in rgb format
@@ -1211,8 +1333,7 @@
1211
1333
  * @returns Color object
1212
1334
  */
1213
1335
  static fromRgbString(rgb) {
1214
- const { red, green, blue, alpha } = parseRgbColor(rgb);
1215
- return take(new Color(red, green, blue, alpha));
1336
+ return Color.fromColorChannels(parseRgbColor(rgb));
1216
1337
  }
1217
1338
  /**
1218
1339
  * Creates a new Color instance from color in rbga format
@@ -1221,8 +1342,7 @@
1221
1342
  * @returns Color object
1222
1343
  */
1223
1344
  static fromRgbaString(rgba) {
1224
- const { red, green, blue, alpha } = parseRgbaColor(rgba);
1225
- return take(new Color(red, green, blue, alpha));
1345
+ return Color.fromColorChannels(parseRgbaColor(rgba));
1226
1346
  }
1227
1347
  /**
1228
1348
  * Creates a new Color for color channels values
@@ -1234,7 +1354,7 @@
1234
1354
  * @returns Color object
1235
1355
  */
1236
1356
  static fromValues(red, green, blue, alpha = 255) {
1237
- return take(new Color(red, green, blue, alpha));
1357
+ return Color.fromColorChannels({ red, green, blue, alpha });
1238
1358
  }
1239
1359
  /**
1240
1360
  * Checks if the given value is a valid Color object.
@@ -1267,8 +1387,7 @@
1267
1387
  * @returns true if the value is a valid hex color string (e.g., `#009edd`, `#fff`, etc.)
1268
1388
  */
1269
1389
  static isHexColorString(value) {
1270
- return (typeof value === 'string' &&
1271
- /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(value));
1390
+ return isHexColorString(value);
1272
1391
  }
1273
1392
  /**
1274
1393
  * Creates new Color object
@@ -1281,89 +1400,13 @@
1281
1400
  * @param alpha number from 0 (transparent) to 255 (opaque)
1282
1401
  */
1283
1402
  constructor(red, green, blue, alpha = 255) {
1284
- this.red = red;
1285
- this.green = green;
1286
- this.blue = blue;
1287
- this.alpha = alpha;
1288
- checkChannelValue('Red', red);
1289
- checkChannelValue('Green', green);
1290
- checkChannelValue('Blue', blue);
1291
- checkChannelValue('Alpha', alpha);
1403
+ super(red, green, blue, alpha);
1292
1404
  }
1293
- /**
1294
- * Shortcut for `red` property
1295
- * Number from 0 to 255
1296
- * @alias red
1297
- */
1298
- get r() {
1299
- return this.red;
1405
+ createColor(red, green, blue, alpha) {
1406
+ return new Color(red, green, blue, alpha);
1300
1407
  }
1301
- /**
1302
- * Shortcut for `green` property
1303
- * Number from 0 to 255
1304
- * @alias green
1305
- */
1306
- get g() {
1307
- return this.green;
1308
- }
1309
- /**
1310
- * Shortcut for `blue` property
1311
- * Number from 0 to 255
1312
- * @alias blue
1313
- */
1314
- get b() {
1315
- return this.blue;
1316
- }
1317
- /**
1318
- * Shortcut for `alpha` property
1319
- * Number from 0 (transparent) to 255 (opaque)
1320
- * @alias alpha
1321
- */
1322
- get a() {
1323
- return this.alpha;
1324
- }
1325
- /**
1326
- * Shortcut for `alpha` property
1327
- * Number from 0 (transparent) to 255 (opaque)
1328
- * @alias alpha
1329
- */
1330
- get opacity() {
1331
- return this.alpha;
1332
- }
1333
- /**
1334
- * Shortcut for 1-`alpha` property
1335
- */
1336
- get transparency() {
1337
- return 255 - this.alpha;
1338
- }
1339
- clone() {
1340
- return take(new Color(this.red, this.green, this.blue, this.alpha));
1341
- }
1342
- toString() {
1343
- return this.toHex();
1344
- }
1345
- toHex() {
1346
- if (this.alpha === 255) {
1347
- return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
1348
- .toString(16)
1349
- .padStart(2, '0')}`;
1350
- }
1351
- else {
1352
- return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
1353
- .toString(16)
1354
- .padStart(2, '0')}${this.alpha.toString(16).padStart(2, '0')}`;
1355
- }
1356
- }
1357
- toRgb() {
1358
- if (this.alpha === 255) {
1359
- return `rgb(${this.red}, ${this.green}, ${this.blue})`;
1360
- }
1361
- else {
1362
- return `rgba(${this.red}, ${this.green}, ${this.blue}, ${Math.round((this.alpha / 255) * 100)}%)`;
1363
- }
1364
- }
1365
- toHsl() {
1366
- throw new Error(`Getting HSL is not implemented`);
1408
+ static fromColorChannels({ red, green, blue, alpha }) {
1409
+ return take(new Color(red, green, blue, alpha));
1367
1410
  }
1368
1411
  }
1369
1412
 
@@ -1837,120 +1880,183 @@
1837
1880
  * @public exported from `@promptbook/utils`
1838
1881
  */
1839
1882
  function checkSerializableAsJson(options) {
1840
- const { value, name, message } = options;
1883
+ checkSerializableValue(options);
1884
+ }
1885
+ // TODO: Can be return type more type-safe? like `asserts options.value is JsonValue`
1886
+ // TODO: [🧠][main] !!3 In-memory cache of same values to prevent multiple checks
1887
+ // Note: [🐠] This is how `checkSerializableAsJson` + `isSerializableAsJson` together can just retun true/false or rich error message
1888
+ /**
1889
+ * Checks one value and dispatches to the appropriate specialized validator.
1890
+ *
1891
+ * @private function of `checkSerializableAsJson`
1892
+ */
1893
+ function checkSerializableValue(options) {
1894
+ const { value } = options;
1895
+ if (isSerializablePrimitive(value)) {
1896
+ return;
1897
+ }
1841
1898
  if (value === undefined) {
1842
- throw new UnexpectedError(`${name} is undefined`);
1899
+ throw new UnexpectedError(`${options.name} is undefined`);
1843
1900
  }
1844
- else if (value === null) {
1845
- return;
1901
+ if (typeof value === 'symbol') {
1902
+ throw new UnexpectedError(`${options.name} is symbol`);
1846
1903
  }
1847
- else if (typeof value === 'boolean') {
1848
- return;
1904
+ if (typeof value === 'function') {
1905
+ throw new UnexpectedError(`${options.name} is function`);
1849
1906
  }
1850
- else if (typeof value === 'number' && !isNaN(value)) {
1907
+ if (Array.isArray(value)) {
1908
+ checkSerializableArray(options, value);
1851
1909
  return;
1852
1910
  }
1853
- else if (typeof value === 'string') {
1911
+ if (value !== null && typeof value === 'object') {
1912
+ checkSerializableObject(options, value);
1854
1913
  return;
1855
1914
  }
1856
- else if (typeof value === 'symbol') {
1857
- throw new UnexpectedError(`${name} is symbol`);
1858
- }
1859
- else if (typeof value === 'function') {
1860
- throw new UnexpectedError(`${name} is function`);
1861
- }
1862
- else if (typeof value === 'object' && Array.isArray(value)) {
1863
- for (let i = 0; i < value.length; i++) {
1864
- checkSerializableAsJson({ name: `${name}[${i}]`, value: value[i], message });
1865
- }
1915
+ throwUnknownTypeError(options);
1916
+ }
1917
+ /**
1918
+ * Checks the primitive values that are directly JSON serializable.
1919
+ *
1920
+ * @private function of `checkSerializableAsJson`
1921
+ */
1922
+ function isSerializablePrimitive(value) {
1923
+ return (value === null ||
1924
+ typeof value === 'boolean' ||
1925
+ (typeof value === 'number' && !isNaN(value)) ||
1926
+ typeof value === 'string');
1927
+ }
1928
+ /**
1929
+ * Recursively checks JSON array items.
1930
+ *
1931
+ * @private function of `checkSerializableAsJson`
1932
+ */
1933
+ function checkSerializableArray(context, arrayValue) {
1934
+ for (let index = 0; index < arrayValue.length; index++) {
1935
+ checkSerializableAsJson({
1936
+ ...context,
1937
+ name: `${context.name}[${index}]`,
1938
+ value: arrayValue[index],
1939
+ });
1866
1940
  }
1867
- else if (typeof value === 'object') {
1868
- if (value instanceof Date) {
1869
- throw new UnexpectedError(spacetrim.spaceTrim((block) => `
1870
- \`${name}\` is Date
1941
+ }
1942
+ /**
1943
+ * Checks object-like values and dispatches special unsupported built-ins.
1944
+ *
1945
+ * @private function of `checkSerializableAsJson`
1946
+ */
1947
+ function checkSerializableObject(context, objectValue) {
1948
+ checkUnsupportedObjectType(context, objectValue);
1949
+ checkSerializableObjectEntries(context, objectValue);
1950
+ assertJsonStringificationSucceeds(context, objectValue);
1951
+ }
1952
+ /**
1953
+ * Rejects built-in objects that must be converted before JSON serialization.
1954
+ *
1955
+ * @private function of `checkSerializableAsJson`
1956
+ */
1957
+ function checkUnsupportedObjectType(context, objectValue) {
1958
+ if (objectValue instanceof Date) {
1959
+ throw new UnexpectedError(spacetrim.spaceTrim((block) => `
1960
+ \`${context.name}\` is Date
1871
1961
 
1872
- Use \`string_date_iso8601\` instead
1962
+ Use \`string_date_iso8601\` instead
1873
1963
 
1874
- Additional message for \`${name}\`:
1875
- ${block(message || '(nothing)')}
1876
- `));
1877
- }
1878
- else if (value instanceof Map) {
1879
- throw new UnexpectedError(`${name} is Map`);
1880
- }
1881
- else if (value instanceof Set) {
1882
- throw new UnexpectedError(`${name} is Set`);
1883
- }
1884
- else if (value instanceof RegExp) {
1885
- throw new UnexpectedError(`${name} is RegExp`);
1886
- }
1887
- else if (value instanceof Error) {
1888
- throw new UnexpectedError(spacetrim.spaceTrim((block) => `
1889
- \`${name}\` is unserialized Error
1964
+ Additional message for \`${context.name}\`:
1965
+ ${block(context.message || '(nothing)')}
1966
+ `));
1967
+ }
1968
+ if (objectValue instanceof Map) {
1969
+ throw new UnexpectedError(`${context.name} is Map`);
1970
+ }
1971
+ if (objectValue instanceof Set) {
1972
+ throw new UnexpectedError(`${context.name} is Set`);
1973
+ }
1974
+ if (objectValue instanceof RegExp) {
1975
+ throw new UnexpectedError(`${context.name} is RegExp`);
1976
+ }
1977
+ if (objectValue instanceof Error) {
1978
+ throw new UnexpectedError(spacetrim.spaceTrim((block) => `
1979
+ \`${context.name}\` is unserialized Error
1890
1980
 
1891
- Use function \`serializeError\`
1981
+ Use function \`serializeError\`
1892
1982
 
1893
- Additional message for \`${name}\`:
1894
- ${block(message || '(nothing)')}
1983
+ Additional message for \`${context.name}\`:
1984
+ ${block(context.message || '(nothing)')}
1895
1985
 
1896
- `));
1986
+ `));
1987
+ }
1988
+ }
1989
+ /**
1990
+ * Recursively checks object properties while preserving omitted `undefined` keys.
1991
+ *
1992
+ * @private function of `checkSerializableAsJson`
1993
+ */
1994
+ function checkSerializableObjectEntries(context, objectValue) {
1995
+ for (const [subName, subValue] of Object.entries(objectValue)) {
1996
+ if (subValue === undefined) {
1997
+ // Note: undefined in object is serializable - it is just omitted
1998
+ continue;
1897
1999
  }
1898
- else {
1899
- for (const [subName, subValue] of Object.entries(value)) {
1900
- if (subValue === undefined) {
1901
- // Note: undefined in object is serializable - it is just omitted
1902
- continue;
1903
- }
1904
- checkSerializableAsJson({ name: `${name}.${subName}`, value: subValue, message });
1905
- }
1906
- try {
1907
- JSON.stringify(value); // <- TODO: [0]
1908
- }
1909
- catch (error) {
1910
- assertsError(error);
1911
- throw new UnexpectedError(spacetrim.spaceTrim((block) => `
1912
- \`${name}\` is not serializable
2000
+ checkSerializableAsJson({
2001
+ ...context,
2002
+ name: `${context.name}.${subName}`,
2003
+ value: subValue,
2004
+ });
2005
+ }
2006
+ }
2007
+ /**
2008
+ * Uses `JSON.stringify` as the final guard for cases like circular references.
2009
+ *
2010
+ * @private function of `checkSerializableAsJson`
2011
+ */
2012
+ function assertJsonStringificationSucceeds(context, objectValue) {
2013
+ try {
2014
+ JSON.stringify(objectValue); // <- TODO: [0]
2015
+ }
2016
+ catch (error) {
2017
+ assertsError(error);
2018
+ throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2019
+ \`${context.name}\` is not serializable
1913
2020
 
1914
- ${block(error.stack || error.message)}
2021
+ ${block(error.stack || error.message)}
1915
2022
 
1916
- Additional message for \`${name}\`:
1917
- ${block(message || '(nothing)')}
1918
- `));
2023
+ Additional message for \`${context.name}\`:
2024
+ ${block(context.message || '(nothing)')}
2025
+ `));
2026
+ }
2027
+ /*
2028
+ TODO: [0] Is there some more elegant way to check circular references?
2029
+ const seen = new Set();
2030
+ const stack = [{ value }];
2031
+ while (stack.length > 0) {
2032
+ const { value } = stack.pop()!;
2033
+ if (typeof value === 'object' && value !== null) {
2034
+ if (seen.has(value)) {
2035
+ throw new UnexpectedError(`${name} has circular reference`);
1919
2036
  }
1920
- /*
1921
- TODO: [0] Is there some more elegant way to check circular references?
1922
- const seen = new Set();
1923
- const stack = [{ value }];
1924
- while (stack.length > 0) {
1925
- const { value } = stack.pop()!;
1926
- if (typeof value === 'object' && value !== null) {
1927
- if (seen.has(value)) {
1928
- throw new UnexpectedError(`${name} has circular reference`);
1929
- }
1930
- seen.add(value);
1931
- if (Array.isArray(value)) {
1932
- stack.push(...value.map((value) => ({ value })));
1933
- } else {
1934
- stack.push(...Object.values(value).map((value) => ({ value })));
1935
- }
1936
- }
2037
+ seen.add(value);
2038
+ if (Array.isArray(value)) {
2039
+ stack.push(...value.map((value) => ({ value })));
2040
+ } else {
2041
+ stack.push(...Object.values(value).map((value) => ({ value })));
1937
2042
  }
1938
- */
1939
- return;
1940
2043
  }
1941
2044
  }
1942
- else {
1943
- throw new UnexpectedError(spacetrim.spaceTrim((block) => `
1944
- \`${name}\` is unknown type
2045
+ */
2046
+ }
2047
+ /**
2048
+ * Throws the fallback error for unsupported value types like `bigint` and `NaN`.
2049
+ *
2050
+ * @private function of `checkSerializableAsJson`
2051
+ */
2052
+ function throwUnknownTypeError(context) {
2053
+ throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2054
+ \`${context.name}\` is unknown type
1945
2055
 
1946
- Additional message for \`${name}\`:
1947
- ${block(message || '(nothing)')}
1948
- `));
1949
- }
2056
+ Additional message for \`${context.name}\`:
2057
+ ${block(context.message || '(nothing)')}
2058
+ `));
1950
2059
  }
1951
- // TODO: Can be return type more type-safe? like `asserts options.value is JsonValue`
1952
- // TODO: [🧠][main] !!3 In-memory cache of same values to prevent multiple checks
1953
- // Note: [🐠] This is how `checkSerializableAsJson` + `isSerializableAsJson` together can just retun true/false or rich error message
1954
2060
 
1955
2061
  /**
1956
2062
  * Creates a deep clone of the given object