@stackframe/stack-shared 2.8.25 → 2.8.27

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 (124) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/config/format.d.mts +20 -5
  3. package/dist/config/format.d.ts +20 -5
  4. package/dist/config/format.js +39 -14
  5. package/dist/config/format.js.map +1 -1
  6. package/dist/config/schema.d.mts +795 -317
  7. package/dist/config/schema.d.ts +795 -317
  8. package/dist/config/schema.js +471 -84
  9. package/dist/config/schema.js.map +1 -1
  10. package/dist/crud.d.mts +1 -0
  11. package/dist/crud.d.ts +1 -0
  12. package/dist/esm/config/format.js +37 -14
  13. package/dist/esm/config/format.js.map +1 -1
  14. package/dist/esm/config/schema.js +460 -80
  15. package/dist/esm/config/schema.js.map +1 -1
  16. package/dist/esm/helpers/emails.js +136 -30
  17. package/dist/esm/helpers/emails.js.map +1 -1
  18. package/dist/esm/interface/admin-interface.js +19 -29
  19. package/dist/esm/interface/admin-interface.js.map +1 -1
  20. package/dist/esm/known-errors.js +24 -1
  21. package/dist/esm/known-errors.js.map +1 -1
  22. package/dist/esm/schema-fields.js +92 -27
  23. package/dist/esm/schema-fields.js.map +1 -1
  24. package/dist/esm/utils/currencies.js +52 -0
  25. package/dist/esm/utils/currencies.js.map +1 -0
  26. package/dist/esm/utils/dates.js +55 -1
  27. package/dist/esm/utils/dates.js.map +1 -1
  28. package/dist/esm/utils/errors.js.map +1 -1
  29. package/dist/esm/utils/objects.js +2 -0
  30. package/dist/esm/utils/objects.js.map +1 -1
  31. package/dist/esm/utils/strings.js +4 -0
  32. package/dist/esm/utils/strings.js.map +1 -1
  33. package/dist/esm/utils/types.js +45 -0
  34. package/dist/esm/utils/types.js.map +1 -1
  35. package/dist/helpers/emails.d.mts +32 -6
  36. package/dist/helpers/emails.d.ts +32 -6
  37. package/dist/helpers/emails.js +138 -30
  38. package/dist/helpers/emails.js.map +1 -1
  39. package/dist/helpers/password.d.mts +1 -0
  40. package/dist/helpers/password.d.ts +1 -0
  41. package/dist/helpers/production-mode.d.mts +1 -0
  42. package/dist/helpers/production-mode.d.ts +1 -0
  43. package/dist/index.d.mts +2 -2
  44. package/dist/index.d.ts +2 -2
  45. package/dist/interface/admin-interface.d.mts +8 -8
  46. package/dist/interface/admin-interface.d.ts +8 -8
  47. package/dist/interface/admin-interface.js +19 -29
  48. package/dist/interface/admin-interface.js.map +1 -1
  49. package/dist/interface/client-interface.d.mts +1 -0
  50. package/dist/interface/client-interface.d.ts +1 -0
  51. package/dist/interface/crud/connected-accounts.d.mts +1 -0
  52. package/dist/interface/crud/connected-accounts.d.ts +1 -0
  53. package/dist/interface/crud/contact-channels.d.mts +1 -0
  54. package/dist/interface/crud/contact-channels.d.ts +1 -0
  55. package/dist/interface/crud/current-user.d.mts +1 -0
  56. package/dist/interface/crud/current-user.d.ts +1 -0
  57. package/dist/interface/crud/email-templates.d.mts +1 -0
  58. package/dist/interface/crud/email-templates.d.ts +1 -0
  59. package/dist/interface/crud/emails.d.mts +1 -0
  60. package/dist/interface/crud/emails.d.ts +1 -0
  61. package/dist/interface/crud/internal-api-keys.d.mts +1 -0
  62. package/dist/interface/crud/internal-api-keys.d.ts +1 -0
  63. package/dist/interface/crud/notification-preferences.d.mts +1 -0
  64. package/dist/interface/crud/notification-preferences.d.ts +1 -0
  65. package/dist/interface/crud/oauth-providers.d.mts +5 -4
  66. package/dist/interface/crud/oauth-providers.d.ts +5 -4
  67. package/dist/interface/crud/project-api-keys.d.mts +3 -2
  68. package/dist/interface/crud/project-api-keys.d.ts +3 -2
  69. package/dist/interface/crud/project-permissions.d.mts +1 -0
  70. package/dist/interface/crud/project-permissions.d.ts +1 -0
  71. package/dist/interface/crud/projects.d.mts +8 -7
  72. package/dist/interface/crud/projects.d.ts +8 -7
  73. package/dist/interface/crud/sessions.d.mts +1 -0
  74. package/dist/interface/crud/sessions.d.ts +1 -0
  75. package/dist/interface/crud/svix-token.d.mts +1 -0
  76. package/dist/interface/crud/svix-token.d.ts +1 -0
  77. package/dist/interface/crud/team-invitation-details.d.mts +1 -0
  78. package/dist/interface/crud/team-invitation-details.d.ts +1 -0
  79. package/dist/interface/crud/team-invitation.d.mts +1 -0
  80. package/dist/interface/crud/team-invitation.d.ts +1 -0
  81. package/dist/interface/crud/team-member-profiles.d.mts +1 -0
  82. package/dist/interface/crud/team-member-profiles.d.ts +1 -0
  83. package/dist/interface/crud/team-memberships.d.mts +1 -0
  84. package/dist/interface/crud/team-memberships.d.ts +1 -0
  85. package/dist/interface/crud/team-permissions.d.mts +1 -0
  86. package/dist/interface/crud/team-permissions.d.ts +1 -0
  87. package/dist/interface/crud/teams.d.mts +1 -0
  88. package/dist/interface/crud/teams.d.ts +1 -0
  89. package/dist/interface/crud/users.d.mts +1 -0
  90. package/dist/interface/crud/users.d.ts +1 -0
  91. package/dist/interface/server-interface.d.mts +1 -0
  92. package/dist/interface/server-interface.d.ts +1 -0
  93. package/dist/known-errors.d.mts +6 -0
  94. package/dist/known-errors.d.ts +6 -0
  95. package/dist/known-errors.js +24 -1
  96. package/dist/known-errors.js.map +1 -1
  97. package/dist/schema-fields.d.mts +39 -8
  98. package/dist/schema-fields.d.ts +39 -8
  99. package/dist/schema-fields.js +101 -27
  100. package/dist/schema-fields.js.map +1 -1
  101. package/dist/utils/currencies.d.mts +39 -0
  102. package/dist/utils/currencies.d.ts +39 -0
  103. package/dist/utils/currencies.js +78 -0
  104. package/dist/utils/currencies.js.map +1 -0
  105. package/dist/utils/dates.d.mts +5 -1
  106. package/dist/utils/dates.d.ts +5 -1
  107. package/dist/utils/dates.js +58 -2
  108. package/dist/utils/dates.js.map +1 -1
  109. package/dist/utils/errors.d.mts +9 -0
  110. package/dist/utils/errors.d.ts +9 -0
  111. package/dist/utils/errors.js.map +1 -1
  112. package/dist/utils/objects.d.mts +23 -8
  113. package/dist/utils/objects.d.ts +23 -8
  114. package/dist/utils/objects.js +2 -0
  115. package/dist/utils/objects.js.map +1 -1
  116. package/dist/utils/strings.d.mts +3 -1
  117. package/dist/utils/strings.d.ts +3 -1
  118. package/dist/utils/strings.js +5 -0
  119. package/dist/utils/strings.js.map +1 -1
  120. package/dist/utils/types.d.mts +73 -2
  121. package/dist/utils/types.d.ts +73 -2
  122. package/dist/utils/types.js +54 -0
  123. package/dist/utils/types.js.map +1 -1
  124. package/package.json +1 -1
@@ -1,4 +1,6 @@
1
1
  // src/utils/dates.tsx
2
+ import { intervalSchema } from "../schema-fields.js";
3
+ import { StackAssertionError } from "./errors.js";
2
4
  import { remainder } from "./math.js";
3
5
  function isWeekend(date) {
4
6
  return date.getDay() === 0 || date.getDay() === 6;
@@ -55,10 +57,62 @@ function getInputDatetimeLocalString(date) {
55
57
  date.setMinutes(date.getMinutes() - date.getTimezoneOffset());
56
58
  return date.toISOString().slice(0, 19);
57
59
  }
60
+ function applyInterval(date, times, interval) {
61
+ if (!intervalSchema.isValidSync(interval)) {
62
+ throw new StackAssertionError(`Invalid interval`, { interval });
63
+ }
64
+ const [amount, unit] = interval;
65
+ switch (unit) {
66
+ case "millisecond": {
67
+ date.setMilliseconds(date.getMilliseconds() + amount * times);
68
+ break;
69
+ }
70
+ case "second": {
71
+ date.setSeconds(date.getSeconds() + amount * times);
72
+ break;
73
+ }
74
+ case "minute": {
75
+ date.setMinutes(date.getMinutes() + amount * times);
76
+ break;
77
+ }
78
+ case "hour": {
79
+ date.setHours(date.getHours() + amount * times);
80
+ break;
81
+ }
82
+ case "day": {
83
+ date.setDate(date.getDate() + amount * times);
84
+ break;
85
+ }
86
+ case "week": {
87
+ date.setDate(date.getDate() + amount * times * 7);
88
+ break;
89
+ }
90
+ case "month": {
91
+ date.setMonth(date.getMonth() + amount * times);
92
+ break;
93
+ }
94
+ case "year": {
95
+ date.setFullYear(date.getFullYear() + amount * times);
96
+ break;
97
+ }
98
+ default: {
99
+ throw new StackAssertionError(`Invalid interval despite schema validation`, { interval });
100
+ }
101
+ }
102
+ return date;
103
+ }
104
+ function subtractInterval(date, interval) {
105
+ return applyInterval(date, -1, interval);
106
+ }
107
+ function addInterval(date, interval) {
108
+ return applyInterval(date, 1, interval);
109
+ }
58
110
  export {
111
+ addInterval,
59
112
  fromNow,
60
113
  fromNowDetailed,
61
114
  getInputDatetimeLocalString,
62
- isWeekend
115
+ isWeekend,
116
+ subtractInterval
63
117
  };
64
118
  //# sourceMappingURL=dates.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utils/dates.tsx"],"sourcesContent":["import { remainder } from \"./math\";\n\nexport function isWeekend(date: Date): boolean {\n return date.getDay() === 0 || date.getDay() === 6;\n}\n\nundefined?.test(\"isWeekend\", ({ expect }) => {\n // Sunday (day 0)\n expect(isWeekend(new Date(2023, 0, 1))).toBe(true);\n // Saturday (day 6)\n expect(isWeekend(new Date(2023, 0, 7))).toBe(true);\n // Monday (day 1)\n expect(isWeekend(new Date(2023, 0, 2))).toBe(false);\n // Friday (day 5)\n expect(isWeekend(new Date(2023, 0, 6))).toBe(false);\n});\n\nconst agoUnits = [\n [60, 'second'],\n [60, 'minute'],\n [24, 'hour'],\n [7, 'day'],\n [5, 'week'],\n] as const;\n\nexport function fromNow(date: Date): string {\n return fromNowDetailed(date).result;\n}\n\nundefined?.test(\"fromNow\", ({ expect }) => {\n // Set a fixed date for testing\n const fixedDate = new Date(\"2023-01-15T12:00:00.000Z\");\n\n // Use Vitest's fake timers\n undefined?.vi.useFakeTimers();\n undefined?.vi.setSystemTime(fixedDate);\n\n // Test past times\n expect(fromNow(new Date(\"2023-01-15T11:59:50.000Z\"))).toBe(\"just now\");\n expect(fromNow(new Date(\"2023-01-15T11:59:00.000Z\"))).toBe(\"1 minute ago\");\n expect(fromNow(new Date(\"2023-01-15T11:00:00.000Z\"))).toBe(\"1 hour ago\");\n expect(fromNow(new Date(\"2023-01-14T12:00:00.000Z\"))).toBe(\"1 day ago\");\n expect(fromNow(new Date(\"2023-01-08T12:00:00.000Z\"))).toBe(\"1 week ago\");\n\n // Test future times\n expect(fromNow(new Date(\"2023-01-15T12:00:10.000Z\"))).toBe(\"just now\");\n expect(fromNow(new Date(\"2023-01-15T12:01:00.000Z\"))).toBe(\"in 1 minute\");\n expect(fromNow(new Date(\"2023-01-15T13:00:00.000Z\"))).toBe(\"in 1 hour\");\n expect(fromNow(new Date(\"2023-01-16T12:00:00.000Z\"))).toBe(\"in 1 day\");\n expect(fromNow(new Date(\"2023-01-22T12:00:00.000Z\"))).toBe(\"in 1 week\");\n\n // Test very old dates (should use date format)\n expect(fromNow(new Date(\"2022-01-15T12:00:00.000Z\"))).toMatch(/Jan 15, 2022/);\n\n // Restore real timers\n undefined?.vi.useRealTimers();\n});\n\nexport function fromNowDetailed(date: Date): {\n result: string,\n /**\n * May be Infinity if the result will never change.\n */\n secondsUntilChange: number,\n} {\n if (!(date instanceof Date)) {\n throw new Error(`fromNow only accepts Date objects (received: ${date})`);\n }\n\n const now = new Date();\n const elapsed = now.getTime() - date.getTime();\n\n let remainingInUnit = Math.abs(elapsed) / 1000;\n if (remainingInUnit < 15) {\n return {\n result: 'just now',\n secondsUntilChange: 15 - remainingInUnit,\n };\n }\n let unitInSeconds = 1;\n for (const [nextUnitSize, unitName] of agoUnits) {\n const rounded = Math.round(remainingInUnit);\n if (rounded < nextUnitSize) {\n if (elapsed < 0) {\n return {\n result: `in ${rounded} ${unitName}${rounded === 1 ? '' : 's'}`,\n secondsUntilChange: remainder((remainingInUnit - rounded + 0.5) * unitInSeconds, unitInSeconds),\n };\n } else {\n return {\n result: `${rounded} ${unitName}${rounded === 1 ? '' : 's'} ago`,\n secondsUntilChange: remainder((rounded - remainingInUnit - 0.5) * unitInSeconds, unitInSeconds),\n };\n }\n }\n unitInSeconds *= nextUnitSize;\n remainingInUnit /= nextUnitSize;\n }\n\n return {\n result: date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' }),\n secondsUntilChange: Infinity,\n };\n}\n\n/**\n * Returns a string representation of the given date in the format expected by the `datetime-local` input type.\n */\nexport function getInputDatetimeLocalString(date: Date): string {\n date = new Date(date);\n date.setMinutes(date.getMinutes() - date.getTimezoneOffset());\n return date.toISOString().slice(0, 19);\n}\n\nundefined?.test(\"getInputDatetimeLocalString\", ({ expect }) => {\n // Use Vitest's fake timers to ensure consistent timezone behavior\n undefined?.vi.useFakeTimers();\n\n // Test with a specific date\n const mockDate = new Date(\"2023-01-15T12:30:45.000Z\");\n const result = getInputDatetimeLocalString(mockDate);\n\n // The result should be in the format YYYY-MM-DDTHH:MM:SS\n expect(result).toMatch(/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$/);\n\n // Test with different dates\n const dates = [\n new Date(\"2023-01-01T00:00:00.000Z\"),\n new Date(\"2023-06-15T23:59:59.000Z\"),\n new Date(\"2023-12-31T12:34:56.000Z\"),\n ];\n\n for (const date of dates) {\n const result = getInputDatetimeLocalString(date);\n expect(result).toMatch(/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$/);\n }\n\n // Restore real timers\n undefined?.vi.useRealTimers();\n});\n"],"mappings":";AAAA,SAAS,iBAAiB;AAEnB,SAAS,UAAU,MAAqB;AAC7C,SAAO,KAAK,OAAO,MAAM,KAAK,KAAK,OAAO,MAAM;AAClD;AAaA,IAAM,WAAW;AAAA,EACf,CAAC,IAAI,QAAQ;AAAA,EACb,CAAC,IAAI,QAAQ;AAAA,EACb,CAAC,IAAI,MAAM;AAAA,EACX,CAAC,GAAG,KAAK;AAAA,EACT,CAAC,GAAG,MAAM;AACZ;AAEO,SAAS,QAAQ,MAAoB;AAC1C,SAAO,gBAAgB,IAAI,EAAE;AAC/B;AA+BO,SAAS,gBAAgB,MAM9B;AACA,MAAI,EAAE,gBAAgB,OAAO;AAC3B,UAAM,IAAI,MAAM,gDAAgD,IAAI,GAAG;AAAA,EACzE;AAEA,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,UAAU,IAAI,QAAQ,IAAI,KAAK,QAAQ;AAE7C,MAAI,kBAAkB,KAAK,IAAI,OAAO,IAAI;AAC1C,MAAI,kBAAkB,IAAI;AACxB,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,oBAAoB,KAAK;AAAA,IAC3B;AAAA,EACF;AACA,MAAI,gBAAgB;AACpB,aAAW,CAAC,cAAc,QAAQ,KAAK,UAAU;AAC/C,UAAM,UAAU,KAAK,MAAM,eAAe;AAC1C,QAAI,UAAU,cAAc;AAC1B,UAAI,UAAU,GAAG;AACf,eAAO;AAAA,UACL,QAAQ,MAAM,OAAO,IAAI,QAAQ,GAAG,YAAY,IAAI,KAAK,GAAG;AAAA,UAC5D,oBAAoB,WAAW,kBAAkB,UAAU,OAAO,eAAe,aAAa;AAAA,QAChG;AAAA,MACF,OAAO;AACL,eAAO;AAAA,UACL,QAAQ,GAAG,OAAO,IAAI,QAAQ,GAAG,YAAY,IAAI,KAAK,GAAG;AAAA,UACzD,oBAAoB,WAAW,UAAU,kBAAkB,OAAO,eAAe,aAAa;AAAA,QAChG;AAAA,MACF;AAAA,IACF;AACA,qBAAiB;AACjB,uBAAmB;AAAA,EACrB;AAEA,SAAO;AAAA,IACL,QAAQ,KAAK,mBAAmB,SAAS,EAAE,MAAM,WAAW,OAAO,SAAS,KAAK,UAAU,CAAC;AAAA,IAC5F,oBAAoB;AAAA,EACtB;AACF;AAKO,SAAS,4BAA4B,MAAoB;AAC9D,SAAO,IAAI,KAAK,IAAI;AACpB,OAAK,WAAW,KAAK,WAAW,IAAI,KAAK,kBAAkB,CAAC;AAC5D,SAAO,KAAK,YAAY,EAAE,MAAM,GAAG,EAAE;AACvC;","names":[]}
1
+ {"version":3,"sources":["../../../src/utils/dates.tsx"],"sourcesContent":["import { intervalSchema } from \"../schema-fields\";\nimport { StackAssertionError } from \"./errors\";\nimport { remainder } from \"./math\";\n\nexport function isWeekend(date: Date): boolean {\n return date.getDay() === 0 || date.getDay() === 6;\n}\n\nundefined?.test(\"isWeekend\", ({ expect }) => {\n // Sunday (day 0)\n expect(isWeekend(new Date(2023, 0, 1))).toBe(true);\n // Saturday (day 6)\n expect(isWeekend(new Date(2023, 0, 7))).toBe(true);\n // Monday (day 1)\n expect(isWeekend(new Date(2023, 0, 2))).toBe(false);\n // Friday (day 5)\n expect(isWeekend(new Date(2023, 0, 6))).toBe(false);\n});\n\nconst agoUnits = [\n [60, 'second'],\n [60, 'minute'],\n [24, 'hour'],\n [7, 'day'],\n [5, 'week'],\n] as const;\n\nexport function fromNow(date: Date): string {\n return fromNowDetailed(date).result;\n}\n\nundefined?.test(\"fromNow\", ({ expect }) => {\n // Set a fixed date for testing\n const fixedDate = new Date(\"2023-01-15T12:00:00.000Z\");\n\n // Use Vitest's fake timers\n undefined?.vi.useFakeTimers();\n undefined?.vi.setSystemTime(fixedDate);\n\n // Test past times\n expect(fromNow(new Date(\"2023-01-15T11:59:50.000Z\"))).toBe(\"just now\");\n expect(fromNow(new Date(\"2023-01-15T11:59:00.000Z\"))).toBe(\"1 minute ago\");\n expect(fromNow(new Date(\"2023-01-15T11:00:00.000Z\"))).toBe(\"1 hour ago\");\n expect(fromNow(new Date(\"2023-01-14T12:00:00.000Z\"))).toBe(\"1 day ago\");\n expect(fromNow(new Date(\"2023-01-08T12:00:00.000Z\"))).toBe(\"1 week ago\");\n\n // Test future times\n expect(fromNow(new Date(\"2023-01-15T12:00:10.000Z\"))).toBe(\"just now\");\n expect(fromNow(new Date(\"2023-01-15T12:01:00.000Z\"))).toBe(\"in 1 minute\");\n expect(fromNow(new Date(\"2023-01-15T13:00:00.000Z\"))).toBe(\"in 1 hour\");\n expect(fromNow(new Date(\"2023-01-16T12:00:00.000Z\"))).toBe(\"in 1 day\");\n expect(fromNow(new Date(\"2023-01-22T12:00:00.000Z\"))).toBe(\"in 1 week\");\n\n // Test very old dates (should use date format)\n expect(fromNow(new Date(\"2022-01-15T12:00:00.000Z\"))).toMatch(/Jan 15, 2022/);\n\n // Restore real timers\n undefined?.vi.useRealTimers();\n});\n\nexport function fromNowDetailed(date: Date): {\n result: string,\n /**\n * May be Infinity if the result will never change.\n */\n secondsUntilChange: number,\n} {\n if (!(date instanceof Date)) {\n throw new Error(`fromNow only accepts Date objects (received: ${date})`);\n }\n\n const now = new Date();\n const elapsed = now.getTime() - date.getTime();\n\n let remainingInUnit = Math.abs(elapsed) / 1000;\n if (remainingInUnit < 15) {\n return {\n result: 'just now',\n secondsUntilChange: 15 - remainingInUnit,\n };\n }\n let unitInSeconds = 1;\n for (const [nextUnitSize, unitName] of agoUnits) {\n const rounded = Math.round(remainingInUnit);\n if (rounded < nextUnitSize) {\n if (elapsed < 0) {\n return {\n result: `in ${rounded} ${unitName}${rounded === 1 ? '' : 's'}`,\n secondsUntilChange: remainder((remainingInUnit - rounded + 0.5) * unitInSeconds, unitInSeconds),\n };\n } else {\n return {\n result: `${rounded} ${unitName}${rounded === 1 ? '' : 's'} ago`,\n secondsUntilChange: remainder((rounded - remainingInUnit - 0.5) * unitInSeconds, unitInSeconds),\n };\n }\n }\n unitInSeconds *= nextUnitSize;\n remainingInUnit /= nextUnitSize;\n }\n\n return {\n result: date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' }),\n secondsUntilChange: Infinity,\n };\n}\n\n/**\n * Returns a string representation of the given date in the format expected by the `datetime-local` input type.\n */\nexport function getInputDatetimeLocalString(date: Date): string {\n date = new Date(date);\n date.setMinutes(date.getMinutes() - date.getTimezoneOffset());\n return date.toISOString().slice(0, 19);\n}\n\nundefined?.test(\"getInputDatetimeLocalString\", ({ expect }) => {\n // Use Vitest's fake timers to ensure consistent timezone behavior\n undefined?.vi.useFakeTimers();\n\n // Test with a specific date\n const mockDate = new Date(\"2023-01-15T12:30:45.000Z\");\n const result = getInputDatetimeLocalString(mockDate);\n\n // The result should be in the format YYYY-MM-DDTHH:MM:SS\n expect(result).toMatch(/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$/);\n\n // Test with different dates\n const dates = [\n new Date(\"2023-01-01T00:00:00.000Z\"),\n new Date(\"2023-06-15T23:59:59.000Z\"),\n new Date(\"2023-12-31T12:34:56.000Z\"),\n ];\n\n for (const date of dates) {\n const result = getInputDatetimeLocalString(date);\n expect(result).toMatch(/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$/);\n }\n\n // Restore real timers\n undefined?.vi.useRealTimers();\n});\n\n\nexport type Interval = [number, 'millisecond' | 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'];\nexport type DayInterval = [number, 'day' | 'week' | 'month' | 'year'];\n\nfunction applyInterval(date: Date, times: number, interval: Interval): Date {\n if (!intervalSchema.isValidSync(interval)) {\n throw new StackAssertionError(`Invalid interval`, { interval });\n }\n const [amount, unit] = interval;\n switch (unit) {\n case 'millisecond': {\n date.setMilliseconds(date.getMilliseconds() + amount * times);\n break;\n }\n case 'second': {\n date.setSeconds(date.getSeconds() + amount * times);\n break;\n }\n case 'minute': {\n date.setMinutes(date.getMinutes() + amount * times);\n break;\n }\n case 'hour': {\n date.setHours(date.getHours() + amount * times);\n break;\n }\n case 'day': {\n date.setDate(date.getDate() + amount * times);\n break;\n }\n case 'week': {\n date.setDate(date.getDate() + amount * times * 7);\n break;\n }\n case 'month': {\n date.setMonth(date.getMonth() + amount * times);\n break;\n }\n case 'year': {\n date.setFullYear(date.getFullYear() + amount * times);\n break;\n }\n default: {\n throw new StackAssertionError(`Invalid interval despite schema validation`, { interval });\n }\n }\n return date;\n}\n\nexport function subtractInterval(date: Date, interval: Interval): Date {\n return applyInterval(date, -1, interval);\n}\n\nexport function addInterval(date: Date, interval: Interval): Date {\n return applyInterval(date, 1, interval);\n}\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utils/errors.tsx"],"sourcesContent":["import { globalVar } from \"./globals\";\nimport { Json } from \"./json\";\nimport { pick } from \"./objects\";\nimport { nicify } from \"./strings\";\n\n\nexport function throwErr(errorMessage: string, extraData?: any): never;\nexport function throwErr(error: Error): never;\nexport function throwErr(...args: StatusErrorConstructorParameters): never;\nexport function throwErr(...args: any[]): never {\n if (typeof args[0] === \"string\") {\n throw new StackAssertionError(args[0], args[1]);\n } else if (args[0] instanceof Error) {\n throw args[0];\n } else {\n // @ts-expect-error\n throw new StatusError(...args);\n }\n}\n\nfunction removeStacktraceNameLine(stack: string): string {\n // some browsers (eg. Chrome) prepend the stack with an extra line with the error name\n const addsNameLine = new Error().stack?.startsWith(\"Error\\n\");\n return stack.split(\"\\n\").slice(addsNameLine ? 1 : 0).join(\"\\n\");\n}\n\n\n/**\n * Concatenates the (original) stacktraces of the given errors onto the first.\n *\n * Useful when you invoke an async function to receive a promise without awaiting it immediately. Browsers are smart\n * enough to keep track of the call stack in async function calls when you invoke `.then` within the same async tick,\n * but if you don't, the stacktrace will be lost.\n *\n * Here's an example of the unwanted behavior:\n *\n * ```tsx\n * async function log() {\n * await wait(0); // simulate an put the task on the event loop\n * console.log(new Error().stack);\n * }\n *\n * async function main() {\n * await log(); // good; prints both \"log\" and \"main\" on the stacktrace\n * log(); // bad; prints only \"log\" on the stacktrace\n * }\n * ```\n */\nexport function concatStacktraces(first: Error, ...errors: Error[]): void {\n // some browsers (eg. Firefox) add an extra empty line at the end\n const addsEmptyLineAtEnd = first.stack?.endsWith(\"\\n\");\n\n\n // Add a reference to this function itself so that we know that stacktraces were concatenated\n // If you are coming here from a stacktrace, please know that the two parts before and after this line are different\n // stacktraces that were concatenated with concatStacktraces\n const separator = removeStacktraceNameLine(new Error().stack ?? \"\").split(\"\\n\")[0];\n\n\n for (const error of errors) {\n const toAppend = removeStacktraceNameLine(error.stack ?? \"\");\n first.stack += (addsEmptyLineAtEnd ? \"\" : \"\\n\") + separator + \"\\n\" + toAppend;\n }\n}\n\n\nexport class StackAssertionError extends Error {\n constructor(message: string, public readonly extraData?: Record<string, any> & ErrorOptions) {\n const disclaimer = `\\n\\nThis is likely an error in Stack. Please make sure you are running the newest version and report it.`;\n super(`${message}${message.endsWith(disclaimer) ? \"\" : disclaimer}`, pick(extraData ?? {}, [\"cause\"]));\n\n Object.defineProperty(this, \"customCaptureExtraArgs\", {\n get() {\n return [this.extraData];\n },\n enumerable: false,\n });\n\n if (process.env.NEXT_PUBLIC_STACK_DEBUGGER_ON_ASSERTION_ERROR === \"true\") {\n debugger;\n }\n }\n}\nStackAssertionError.prototype.name = \"StackAssertionError\";\n\n\nexport function errorToNiceString(error: unknown): string {\n if (!(error instanceof Error)) return `${typeof error}<${nicify(error)}>`;\n return nicify(error, { maxDepth: 8 });\n}\n\n\nconst errorSinks = new Set<(location: string, error: unknown, ...extraArgs: unknown[]) => void>();\nexport function registerErrorSink(sink: (location: string, error: unknown) => void): void {\n if (errorSinks.has(sink)) {\n return;\n }\n errorSinks.add(sink);\n}\nregisterErrorSink((location, error, ...extraArgs) => {\n console.error(\n `\\x1b[41mCaptured error in ${location}:`,\n // HACK: Log a nicified version of the error to get around buggy Next.js pretty-printing\n // https://www.reddit.com/r/nextjs/comments/1gkxdqe/comment/m19kxgn/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button\n errorToNiceString(error),\n ...extraArgs,\n \"\\x1b[0m\",\n );\n});\nregisterErrorSink((location, error, ...extraArgs) => {\n globalVar.stackCapturedErrors = globalVar.stackCapturedErrors ?? [];\n globalVar.stackCapturedErrors.push({ location, error, extraArgs });\n});\n\nexport function captureError(location: string, error: unknown): void {\n for (const sink of errorSinks) {\n sink(\n location,\n error,\n ...error && (typeof error === 'object' || typeof error === 'function') && \"customCaptureExtraArgs\" in error && Array.isArray(error.customCaptureExtraArgs) ? (error.customCaptureExtraArgs as any[]) : [],\n );\n }\n}\n\n\ntype Status = {\n statusCode: number,\n message: string,\n};\n\ntype StatusErrorConstructorParameters =\n| [\n status: Status,\n message?: string\n]\n| [\n statusCode: number | Status,\n message: string,\n];\n\nexport class StatusError extends Error {\n private readonly __stackStatusErrorBrand = \"stack-status-error-brand-sentinel\" as const;\n public name = \"StatusError\";\n public readonly statusCode: number;\n\n public static BadRequest = { statusCode: 400, message: \"Bad Request\" };\n public static Unauthorized = { statusCode: 401, message: \"Unauthorized\" };\n public static PaymentRequired = { statusCode: 402, message: \"Payment Required\" };\n public static Forbidden = { statusCode: 403, message: \"Forbidden\" };\n public static NotFound = { statusCode: 404, message: \"Not Found\" };\n public static MethodNotAllowed = { statusCode: 405, message: \"Method Not Allowed\" };\n public static NotAcceptable = { statusCode: 406, message: \"Not Acceptable\" };\n public static ProxyAuthenticationRequired = { statusCode: 407, message: \"Proxy Authentication Required\" };\n public static RequestTimeout = { statusCode: 408, message: \"Request Timeout\" };\n public static Conflict = { statusCode: 409, message: \"Conflict\" };\n public static Gone = { statusCode: 410, message: \"Gone\" };\n public static LengthRequired = { statusCode: 411, message: \"Length Required\" };\n public static PreconditionFailed = { statusCode: 412, message: \"Precondition Failed\" };\n public static PayloadTooLarge = { statusCode: 413, message: \"Payload Too Large\" };\n public static URITooLong = { statusCode: 414, message: \"URI Too Long\" };\n public static UnsupportedMediaType = { statusCode: 415, message: \"Unsupported Media Type\" };\n public static RangeNotSatisfiable = { statusCode: 416, message: \"Range Not Satisfiable\" };\n public static ExpectationFailed = { statusCode: 417, message: \"Expectation Failed\" };\n public static ImATeapot = { statusCode: 418, message: \"I'm a teapot\" };\n public static MisdirectedRequest = { statusCode: 421, message: \"Misdirected Request\" };\n public static UnprocessableEntity = { statusCode: 422, message: \"Unprocessable Entity\" };\n public static Locked = { statusCode: 423, message: \"Locked\" };\n public static FailedDependency = { statusCode: 424, message: \"Failed Dependency\" };\n public static TooEarly = { statusCode: 425, message: \"Too Early\" };\n public static UpgradeRequired = { statusCode: 426, message: \"Upgrade Required\" };\n public static PreconditionRequired = { statusCode: 428, message: \"Precondition Required\" };\n public static TooManyRequests = { statusCode: 429, message: \"Too Many Requests\" };\n public static RequestHeaderFieldsTooLarge = { statusCode: 431, message: \"Request Header Fields Too Large\" };\n public static UnavailableForLegalReasons = { statusCode: 451, message: \"Unavailable For Legal Reasons\" };\n\n public static InternalServerError = { statusCode: 500, message: \"Internal Server Error\" };\n public static NotImplemented = { statusCode: 501, message: \"Not Implemented\" };\n public static BadGateway = { statusCode: 502, message: \"Bad Gateway\" };\n public static ServiceUnavailable = { statusCode: 503, message: \"Service Unavailable\" };\n public static GatewayTimeout = { statusCode: 504, message: \"Gateway Timeout\" };\n public static HTTPVersionNotSupported = { statusCode: 505, message: \"HTTP Version Not Supported\" };\n public static VariantAlsoNegotiates = { statusCode: 506, message: \"Variant Also Negotiates\" };\n public static InsufficientStorage = { statusCode: 507, message: \"Insufficient Storage\" };\n public static LoopDetected = { statusCode: 508, message: \"Loop Detected\" };\n public static NotExtended = { statusCode: 510, message: \"Not Extended\" };\n public static NetworkAuthenticationRequired = { statusCode: 511, message: \"Network Authentication Required\" };\n\n\n constructor(...args: StatusErrorConstructorParameters);\n constructor(\n status: number | Status,\n message?: string,\n ) {\n if (typeof status === \"object\") {\n message ??= status.message;\n status = status.statusCode;\n }\n super(message);\n this.statusCode = status;\n if (!message) {\n throw new StackAssertionError(\"StatusError always requires a message unless a Status object is passed\", { cause: this });\n }\n }\n\n public static isStatusError(error: unknown): error is StatusError {\n // like instanceof, but also works for errors thrown in other realms or by different versions of the same package\n return typeof error === \"object\" && error !== null && \"__stackStatusErrorBrand\" in error && error.__stackStatusErrorBrand === \"stack-status-error-brand-sentinel\";\n }\n\n public isClientError() {\n return this.statusCode >= 400 && this.statusCode < 500;\n }\n\n public isServerError() {\n return !this.isClientError();\n }\n\n public getStatusCode(): number {\n return this.statusCode;\n }\n\n public getBody(): Uint8Array {\n return new TextEncoder().encode(this.message);\n }\n\n public getHeaders(): Record<string, string[]> {\n return {\n \"Content-Type\": [\"text/plain; charset=utf-8\"],\n };\n }\n\n public toDescriptiveJson(): Json {\n return {\n status_code: this.getStatusCode(),\n message: this.message,\n headers: this.getHeaders(),\n };\n }\n\n /**\n * @deprecated this is not a good way to make status errors human-readable, use toDescriptiveJson instead\n */\n public toHttpJson(): Json {\n return {\n status_code: this.statusCode,\n body: this.message,\n headers: this.getHeaders(),\n };\n }\n}\nStatusError.prototype.name = \"StatusError\";\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/utils/errors.tsx"],"sourcesContent":["import { globalVar } from \"./globals\";\nimport { Json } from \"./json\";\nimport { pick } from \"./objects\";\nimport { nicify } from \"./strings\";\n\n\nexport function throwErr(errorMessage: string, extraData?: any): never;\nexport function throwErr(error: Error): never;\nexport function throwErr(...args: StatusErrorConstructorParameters): never;\nexport function throwErr(...args: any[]): never {\n if (typeof args[0] === \"string\") {\n throw new StackAssertionError(args[0], args[1]);\n } else if (args[0] instanceof Error) {\n throw args[0];\n } else {\n // @ts-expect-error\n throw new StatusError(...args);\n }\n}\n\nfunction removeStacktraceNameLine(stack: string): string {\n // some browsers (eg. Chrome) prepend the stack with an extra line with the error name\n const addsNameLine = new Error().stack?.startsWith(\"Error\\n\");\n return stack.split(\"\\n\").slice(addsNameLine ? 1 : 0).join(\"\\n\");\n}\n\n\n/**\n * Concatenates the (original) stacktraces of the given errors onto the first.\n *\n * Useful when you invoke an async function to receive a promise without awaiting it immediately. Browsers are smart\n * enough to keep track of the call stack in async function calls when you invoke `.then` within the same async tick,\n * but if you don't, the stacktrace will be lost.\n *\n * Here's an example of the unwanted behavior:\n *\n * ```tsx\n * async function log() {\n * await wait(0); // simulate an put the task on the event loop\n * console.log(new Error().stack);\n * }\n *\n * async function main() {\n * await log(); // good; prints both \"log\" and \"main\" on the stacktrace\n * log(); // bad; prints only \"log\" on the stacktrace\n * }\n * ```\n */\nexport function concatStacktraces(first: Error, ...errors: Error[]): void {\n // some browsers (eg. Firefox) add an extra empty line at the end\n const addsEmptyLineAtEnd = first.stack?.endsWith(\"\\n\");\n\n\n // Add a reference to this function itself so that we know that stacktraces were concatenated\n // If you are coming here from a stacktrace, please know that the two parts before and after this line are different\n // stacktraces that were concatenated with concatStacktraces\n const separator = removeStacktraceNameLine(new Error().stack ?? \"\").split(\"\\n\")[0];\n\n\n for (const error of errors) {\n const toAppend = removeStacktraceNameLine(error.stack ?? \"\");\n first.stack += (addsEmptyLineAtEnd ? \"\" : \"\\n\") + separator + \"\\n\" + toAppend;\n }\n}\n\n\nexport class StackAssertionError extends Error {\n constructor(message: string, public readonly extraData?: Record<string, any> & ErrorOptions) {\n const disclaimer = `\\n\\nThis is likely an error in Stack. Please make sure you are running the newest version and report it.`;\n super(`${message}${message.endsWith(disclaimer) ? \"\" : disclaimer}`, pick(extraData ?? {}, [\"cause\"]));\n\n Object.defineProperty(this, \"customCaptureExtraArgs\", {\n get() {\n return [this.extraData];\n },\n enumerable: false,\n });\n\n if (process.env.NEXT_PUBLIC_STACK_DEBUGGER_ON_ASSERTION_ERROR === \"true\") {\n debugger;\n }\n }\n}\nStackAssertionError.prototype.name = \"StackAssertionError\";\n\n\nexport function errorToNiceString(error: unknown): string {\n if (!(error instanceof Error)) return `${typeof error}<${nicify(error)}>`;\n return nicify(error, { maxDepth: 8 });\n}\n\n\nconst errorSinks = new Set<(location: string, error: unknown, ...extraArgs: unknown[]) => void>();\nexport function registerErrorSink(sink: (location: string, error: unknown) => void): void {\n if (errorSinks.has(sink)) {\n return;\n }\n errorSinks.add(sink);\n}\nregisterErrorSink((location, error, ...extraArgs) => {\n console.error(\n `\\x1b[41mCaptured error in ${location}:`,\n // HACK: Log a nicified version of the error to get around buggy Next.js pretty-printing\n // https://www.reddit.com/r/nextjs/comments/1gkxdqe/comment/m19kxgn/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button\n errorToNiceString(error),\n ...extraArgs,\n \"\\x1b[0m\",\n );\n});\nregisterErrorSink((location, error, ...extraArgs) => {\n globalVar.stackCapturedErrors = globalVar.stackCapturedErrors ?? [];\n globalVar.stackCapturedErrors.push({ location, error, extraArgs });\n});\n\n/**\n * Captures an error and sends it to the error sinks (most notably, Sentry). Errors caught with captureError are\n * supposed to be seen by an engineer, so they should be actionable and important.\n *\n * The location string is a machine-readable ID, and should hence not contain spaces or anything like that. Good\n * examples are: \"api-route-handler\", \"renderPart()\", etc.\n *\n * Errors that bubble up to the top of runAsynchronously or a route handler are already captured with captureError.\n */\nexport function captureError(location: string, error: unknown): void {\n for (const sink of errorSinks) {\n sink(\n location,\n error,\n ...error && (typeof error === 'object' || typeof error === 'function') && \"customCaptureExtraArgs\" in error && Array.isArray(error.customCaptureExtraArgs) ? (error.customCaptureExtraArgs as any[]) : [],\n );\n }\n}\n\n\ntype Status = {\n statusCode: number,\n message: string,\n};\n\ntype StatusErrorConstructorParameters =\n| [\n status: Status,\n message?: string\n]\n| [\n statusCode: number | Status,\n message: string,\n];\n\nexport class StatusError extends Error {\n private readonly __stackStatusErrorBrand = \"stack-status-error-brand-sentinel\" as const;\n public name = \"StatusError\";\n public readonly statusCode: number;\n\n public static BadRequest = { statusCode: 400, message: \"Bad Request\" };\n public static Unauthorized = { statusCode: 401, message: \"Unauthorized\" };\n public static PaymentRequired = { statusCode: 402, message: \"Payment Required\" };\n public static Forbidden = { statusCode: 403, message: \"Forbidden\" };\n public static NotFound = { statusCode: 404, message: \"Not Found\" };\n public static MethodNotAllowed = { statusCode: 405, message: \"Method Not Allowed\" };\n public static NotAcceptable = { statusCode: 406, message: \"Not Acceptable\" };\n public static ProxyAuthenticationRequired = { statusCode: 407, message: \"Proxy Authentication Required\" };\n public static RequestTimeout = { statusCode: 408, message: \"Request Timeout\" };\n public static Conflict = { statusCode: 409, message: \"Conflict\" };\n public static Gone = { statusCode: 410, message: \"Gone\" };\n public static LengthRequired = { statusCode: 411, message: \"Length Required\" };\n public static PreconditionFailed = { statusCode: 412, message: \"Precondition Failed\" };\n public static PayloadTooLarge = { statusCode: 413, message: \"Payload Too Large\" };\n public static URITooLong = { statusCode: 414, message: \"URI Too Long\" };\n public static UnsupportedMediaType = { statusCode: 415, message: \"Unsupported Media Type\" };\n public static RangeNotSatisfiable = { statusCode: 416, message: \"Range Not Satisfiable\" };\n public static ExpectationFailed = { statusCode: 417, message: \"Expectation Failed\" };\n public static ImATeapot = { statusCode: 418, message: \"I'm a teapot\" };\n public static MisdirectedRequest = { statusCode: 421, message: \"Misdirected Request\" };\n public static UnprocessableEntity = { statusCode: 422, message: \"Unprocessable Entity\" };\n public static Locked = { statusCode: 423, message: \"Locked\" };\n public static FailedDependency = { statusCode: 424, message: \"Failed Dependency\" };\n public static TooEarly = { statusCode: 425, message: \"Too Early\" };\n public static UpgradeRequired = { statusCode: 426, message: \"Upgrade Required\" };\n public static PreconditionRequired = { statusCode: 428, message: \"Precondition Required\" };\n public static TooManyRequests = { statusCode: 429, message: \"Too Many Requests\" };\n public static RequestHeaderFieldsTooLarge = { statusCode: 431, message: \"Request Header Fields Too Large\" };\n public static UnavailableForLegalReasons = { statusCode: 451, message: \"Unavailable For Legal Reasons\" };\n\n public static InternalServerError = { statusCode: 500, message: \"Internal Server Error\" };\n public static NotImplemented = { statusCode: 501, message: \"Not Implemented\" };\n public static BadGateway = { statusCode: 502, message: \"Bad Gateway\" };\n public static ServiceUnavailable = { statusCode: 503, message: \"Service Unavailable\" };\n public static GatewayTimeout = { statusCode: 504, message: \"Gateway Timeout\" };\n public static HTTPVersionNotSupported = { statusCode: 505, message: \"HTTP Version Not Supported\" };\n public static VariantAlsoNegotiates = { statusCode: 506, message: \"Variant Also Negotiates\" };\n public static InsufficientStorage = { statusCode: 507, message: \"Insufficient Storage\" };\n public static LoopDetected = { statusCode: 508, message: \"Loop Detected\" };\n public static NotExtended = { statusCode: 510, message: \"Not Extended\" };\n public static NetworkAuthenticationRequired = { statusCode: 511, message: \"Network Authentication Required\" };\n\n\n constructor(...args: StatusErrorConstructorParameters);\n constructor(\n status: number | Status,\n message?: string,\n ) {\n if (typeof status === \"object\") {\n message ??= status.message;\n status = status.statusCode;\n }\n super(message);\n this.statusCode = status;\n if (!message) {\n throw new StackAssertionError(\"StatusError always requires a message unless a Status object is passed\", { cause: this });\n }\n }\n\n public static isStatusError(error: unknown): error is StatusError {\n // like instanceof, but also works for errors thrown in other realms or by different versions of the same package\n return typeof error === \"object\" && error !== null && \"__stackStatusErrorBrand\" in error && error.__stackStatusErrorBrand === \"stack-status-error-brand-sentinel\";\n }\n\n public isClientError() {\n return this.statusCode >= 400 && this.statusCode < 500;\n }\n\n public isServerError() {\n return !this.isClientError();\n }\n\n public getStatusCode(): number {\n return this.statusCode;\n }\n\n public getBody(): Uint8Array {\n return new TextEncoder().encode(this.message);\n }\n\n public getHeaders(): Record<string, string[]> {\n return {\n \"Content-Type\": [\"text/plain; charset=utf-8\"],\n };\n }\n\n public toDescriptiveJson(): Json {\n return {\n status_code: this.getStatusCode(),\n message: this.message,\n headers: this.getHeaders(),\n };\n }\n\n /**\n * @deprecated this is not a good way to make status errors human-readable, use toDescriptiveJson instead\n */\n public toHttpJson(): Json {\n return {\n status_code: this.statusCode,\n body: this.message,\n headers: this.getHeaders(),\n };\n }\n}\nStatusError.prototype.name = \"StatusError\";\n"],"mappings":"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","names":[]}
@@ -2,6 +2,7 @@
2
2
  import { StackAssertionError } from "./errors.js";
3
3
  import { identity } from "./functions.js";
4
4
  import { stringCompare } from "./strings.js";
5
+ import { typeAssertIs } from "./types.js";
5
6
  function isNotNull(value) {
6
7
  return value !== null && value !== void 0;
7
8
  }
@@ -90,6 +91,7 @@ function filterUndefined(obj) {
90
91
  function filterUndefinedOrNull(obj) {
91
92
  return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== void 0 && v !== null));
92
93
  }
94
+ typeAssertIs()();
93
95
  function deepFilterUndefined(obj) {
94
96
  return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== void 0).map(([k, v]) => [k, isObjectLike(v) ? deepFilterUndefined(v) : v]));
95
97
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utils/objects.tsx"],"sourcesContent":["import { StackAssertionError } from \"./errors\";\nimport { identity } from \"./functions\";\nimport { stringCompare } from \"./strings\";\n\nexport function isNotNull<T>(value: T): value is NonNullable<T> {\n return value !== null && value !== undefined;\n}\nundefined?.test(\"isNotNull\", ({ expect }) => {\n expect(isNotNull(null)).toBe(false);\n expect(isNotNull(undefined)).toBe(false);\n expect(isNotNull(0)).toBe(true);\n expect(isNotNull(\"\")).toBe(true);\n expect(isNotNull(false)).toBe(true);\n expect(isNotNull({})).toBe(true);\n expect(isNotNull([])).toBe(true);\n});\n\nexport type DeepPartial<T> = T extends object ? (T extends (infer E)[] ? T : { [P in keyof T]?: DeepPartial<T[P]> }) : T;\nexport type DeepRequired<T> = T extends object ? (T extends (infer E)[] ? T : { [P in keyof T]-?: DeepRequired<T[P]> }) : T;\n\n/**\n * Assumes both objects are primitives, arrays, or non-function plain objects, and compares them deeply.\n *\n * Note that since they are assumed to be plain objects, this function does not compare prototypes.\n */\nexport function deepPlainEquals<T>(obj1: T, obj2: unknown, options: { ignoreUndefinedValues?: boolean } = {}): obj2 is T {\n if (typeof obj1 !== typeof obj2) return false;\n if (obj1 === obj2) return true;\n\n switch (typeof obj1) {\n case 'object': {\n if (!obj1 || !obj2) return false;\n\n if (Array.isArray(obj1) || Array.isArray(obj2)) {\n if (!Array.isArray(obj1) || !Array.isArray(obj2)) return false;\n if (obj1.length !== obj2.length) return false;\n return obj1.every((v, i) => deepPlainEquals(v, obj2[i], options));\n }\n\n const entries1 = Object.entries(obj1).filter(([k, v]) => !options.ignoreUndefinedValues || v !== undefined);\n const entries2 = Object.entries(obj2).filter(([k, v]) => !options.ignoreUndefinedValues || v !== undefined);\n if (entries1.length !== entries2.length) return false;\n return entries1.every(([k, v1]) => {\n const e2 = entries2.find(([k2]) => k === k2);\n if (!e2) return false;\n return deepPlainEquals(v1, e2[1], options);\n });\n }\n case 'undefined':\n case 'string':\n case 'number':\n case 'boolean':\n case 'bigint':\n case 'symbol':\n case 'function':{\n return false;\n }\n default: {\n throw new Error(\"Unexpected typeof \" + typeof obj1);\n }\n }\n}\nundefined?.test(\"deepPlainEquals\", ({ expect }) => {\n // Simple values\n expect(deepPlainEquals(1, 1)).toBe(true);\n expect(deepPlainEquals(\"test\", \"test\")).toBe(true);\n expect(deepPlainEquals(1, 2)).toBe(false);\n expect(deepPlainEquals(\"test\", \"other\")).toBe(false);\n\n // Arrays\n expect(deepPlainEquals([1, 2, 3], [1, 2, 3])).toBe(true);\n expect(deepPlainEquals([1, 2, 3], [1, 2, 4])).toBe(false);\n expect(deepPlainEquals([1, 2, 3], [1, 2])).toBe(false);\n\n // Objects\n expect(deepPlainEquals({ a: 1, b: 2 }, { a: 1, b: 2 })).toBe(true);\n expect(deepPlainEquals({ a: 1, b: 2 }, { a: 1, b: 3 })).toBe(false);\n expect(deepPlainEquals({ a: 1, b: 2 }, { a: 1 })).toBe(false);\n\n // Nested structures\n expect(deepPlainEquals({ a: 1, b: [1, 2, { c: 3 }] }, { a: 1, b: [1, 2, { c: 3 }] })).toBe(true);\n expect(deepPlainEquals({ a: 1, b: [1, 2, { c: 3 }] }, { a: 1, b: [1, 2, { c: 4 }] })).toBe(false);\n\n // With options\n expect(deepPlainEquals({ a: 1, b: undefined }, { a: 1 }, { ignoreUndefinedValues: true })).toBe(true);\n expect(deepPlainEquals({ a: 1, b: undefined }, { a: 1 })).toBe(false);\n});\n\nexport function isCloneable<T>(obj: T): obj is Exclude<T, symbol | Function> {\n return typeof obj !== 'symbol' && typeof obj !== 'function';\n}\n\nexport function shallowClone<T extends object>(obj: T): T {\n if (!isCloneable(obj)) throw new StackAssertionError(\"shallowClone does not support symbols or functions\", { obj });\n\n if (Array.isArray(obj)) return obj.map(identity) as T;\n return { ...obj };\n}\nundefined?.test(\"shallowClone\", ({ expect }) => {\n expect(shallowClone({ a: 1, b: 2 })).toEqual({ a: 1, b: 2 });\n expect(shallowClone([1, 2, 3])).toEqual([1, 2, 3]);\n expect(() => shallowClone(() => {})).toThrow();\n});\n\nexport function deepPlainClone<T>(obj: T): T {\n if (typeof obj === 'function') throw new StackAssertionError(\"deepPlainClone does not support functions\");\n if (typeof obj === 'symbol') throw new StackAssertionError(\"deepPlainClone does not support symbols\");\n if (typeof obj !== 'object' || !obj) return obj;\n if (Array.isArray(obj)) return obj.map(deepPlainClone) as any;\n return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, deepPlainClone(v)])) as any;\n}\nundefined?.test(\"deepPlainClone\", ({ expect }) => {\n // Primitive values\n expect(deepPlainClone(1)).toBe(1);\n expect(deepPlainClone(\"test\")).toBe(\"test\");\n expect(deepPlainClone(null)).toBe(null);\n expect(deepPlainClone(undefined)).toBe(undefined);\n\n // Arrays\n const arr = [1, 2, 3];\n const clonedArr = deepPlainClone(arr);\n expect(clonedArr).toEqual(arr);\n expect(clonedArr).not.toBe(arr); // Different reference\n\n // Objects\n const obj = { a: 1, b: 2 };\n const clonedObj = deepPlainClone(obj);\n expect(clonedObj).toEqual(obj);\n expect(clonedObj).not.toBe(obj); // Different reference\n\n // Nested structures\n const nested = { a: 1, b: [1, 2, { c: 3 }] };\n const clonedNested = deepPlainClone(nested);\n expect(clonedNested).toEqual(nested);\n expect(clonedNested).not.toBe(nested); // Different reference\n expect(clonedNested.b).not.toBe(nested.b); // Different reference for nested array\n expect(clonedNested.b[2]).not.toBe(nested.b[2]); // Different reference for nested object\n\n // Error cases\n expect(() => deepPlainClone(() => {})).toThrow();\n expect(() => deepPlainClone(Symbol())).toThrow();\n});\n\nexport type DeepMerge<T, U> = U extends any ? DeepMergeNonDistributive<T, U> : never; // distributive conditional type https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types\ntype DeepMergeNonDistributive<T, U> = Omit<T, keyof U> & Omit<U, keyof T> & DeepMergeInner<Pick<T, keyof U & keyof T>, Pick<U, keyof U & keyof T>>;\ntype DeepMergeInner<T, U> = {\n [K in keyof U]-?:\n undefined extends U[K]\n ? K extends keyof T\n ? T[K] extends object\n ? Exclude<U[K], undefined> extends object\n ? DeepMerge<T[K], Exclude<U[K], undefined>>\n : T[K] | Exclude<U[K], undefined>\n : T[K] | Exclude<U[K], undefined>\n : Exclude<U[K], undefined>\n : K extends keyof T\n ? T[K] extends object\n ? U[K] extends object\n ? DeepMerge<T[K], U[K]>\n : U[K]\n : U[K]\n : U[K];\n};\nexport function deepMerge<T extends {}, U extends {}>(baseObj: T, mergeObj: U): DeepMerge<T, U> {\n if ([baseObj, mergeObj, ...Object.values(baseObj), ...Object.values(mergeObj)].some(o => !isCloneable(o))) throw new StackAssertionError(\"deepMerge does not support functions or symbols\", { baseObj, mergeObj });\n\n const res: any = shallowClone(baseObj);\n for (const [key, mergeValue] of Object.entries(mergeObj)) {\n if (has(res, key as any)) {\n const baseValue = get(res, key as any);\n if (isObjectLike(baseValue) && isObjectLike(mergeValue)) {\n set(res, key, deepMerge(baseValue, mergeValue));\n continue;\n }\n }\n set(res, key, mergeValue);\n }\n return res as any;\n}\nundefined?.test(\"deepMerge\", ({ expect }) => {\n // Test merging flat objects\n expect(deepMerge({ a: 1 }, { b: 2 })).toEqual({ a: 1, b: 2 });\n expect(deepMerge({ a: 1 }, { a: 2 })).toEqual({ a: 2 });\n expect(deepMerge({ a: 1, b: 2 }, { b: 3, c: 4 })).toEqual({ a: 1, b: 3, c: 4 });\n\n // Test with nested objects\n expect(deepMerge(\n { a: { x: 1, y: 2 }, b: 3 },\n { a: { y: 3, z: 4 }, c: 5 }\n )).toEqual({ a: { x: 1, y: 3, z: 4 }, b: 3, c: 5 });\n\n // Test with arrays\n expect(deepMerge(\n { a: [1, 2], b: 3 },\n { a: [3, 4], c: 5 }\n )).toEqual({ a: [3, 4], b: 3, c: 5 });\n\n // Test with null values\n expect(deepMerge(\n { a: { x: 1 }, b: null },\n { a: { y: 2 }, b: { z: 3 } }\n )).toEqual({ a: { x: 1, y: 2 }, b: { z: 3 } });\n\n // Test with undefined values\n expect(deepMerge(\n { a: 1, b: undefined },\n { b: 2, c: 3 }\n )).toEqual({ a: 1, b: 2, c: 3 });\n\n // Test deeply nested structures\n expect(deepMerge(\n {\n a: {\n x: { deep: 1 },\n y: [1, 2]\n },\n b: 2\n },\n {\n a: {\n x: { deeper: 3 },\n y: [3, 4]\n },\n c: 3\n }\n )).toEqual({\n a: {\n x: { deep: 1, deeper: 3 },\n y: [3, 4]\n },\n b: 2,\n c: 3\n });\n\n // Test with empty objects\n expect(deepMerge({}, { a: 1 })).toEqual({ a: 1 });\n expect(deepMerge({ a: 1 }, {})).toEqual({ a: 1 });\n expect(deepMerge({}, {})).toEqual({});\n\n // Test that original objects are not modified\n const base = { a: { x: 1 }, b: 2 };\n const merge = { a: { y: 2 }, c: 3 };\n const baseClone = deepPlainClone(base);\n const mergeClone = deepPlainClone(merge);\n\n const result = deepMerge(base, merge);\n expect(base).toEqual(baseClone);\n expect(merge).toEqual(mergeClone);\n expect(result).toEqual({ a: { x: 1, y: 2 }, b: 2, c: 3 });\n\n // Test error cases\n expect(() => deepMerge({ a: () => {} }, { b: 2 })).toThrow();\n expect(() => deepMerge({ a: 1 }, { b: () => {} })).toThrow();\n expect(() => deepMerge({ a: Symbol() }, { b: 2 })).toThrow();\n expect(() => deepMerge({ a: 1 }, { b: Symbol() })).toThrow();\n});\n\nexport function typedEntries<T extends {}>(obj: T): [keyof T, T[keyof T]][] {\n return Object.entries(obj) as any;\n}\nundefined?.test(\"typedEntries\", ({ expect }) => {\n expect(typedEntries({})).toEqual([]);\n expect(typedEntries({ a: 1, b: 2 })).toEqual([[\"a\", 1], [\"b\", 2]]);\n expect(typedEntries({ a: \"hello\", b: true, c: null })).toEqual([[\"a\", \"hello\"], [\"b\", true], [\"c\", null]]);\n\n // Test with object containing methods\n const objWithMethod = { a: 1, b: () => \"test\" };\n const entries = typedEntries(objWithMethod);\n expect(entries.length).toBe(2);\n expect(entries[0][0]).toBe(\"a\");\n expect(entries[0][1]).toBe(1);\n expect(entries[1][0]).toBe(\"b\");\n expect(typeof entries[1][1]).toBe(\"function\");\n});\n\nexport function typedFromEntries<K extends PropertyKey, V>(entries: (readonly [K, V])[]): Record<K, V> {\n return Object.fromEntries(entries) as any;\n}\nundefined?.test(\"typedFromEntries\", ({ expect }) => {\n expect(typedFromEntries([])).toEqual({});\n expect(typedFromEntries([[\"a\", 1], [\"b\", 2]])).toEqual({ a: 1, b: 2 });\n\n // Test with mixed types (using type assertion)\n const mixedEntries = [[\"a\", \"hello\"], [\"b\", true], [\"c\", null]] as [string, string | boolean | null][];\n const mixedObj = typedFromEntries(mixedEntries);\n expect(mixedObj).toEqual({ a: \"hello\", b: true, c: null });\n\n // Test with function values\n const fn = () => \"test\";\n type MixedValue = number | (() => string);\n const fnEntries: [string, MixedValue][] = [[\"a\", 1], [\"b\", fn]];\n const obj = typedFromEntries(fnEntries);\n expect(obj.a).toBe(1);\n expect(typeof obj.b).toBe(\"function\");\n // Type assertion needed for the function call\n expect((obj.b as () => string)()).toBe(\"test\");\n});\n\nexport function typedKeys<T extends {}>(obj: T): (keyof T)[] {\n return Object.keys(obj) as any;\n}\nundefined?.test(\"typedKeys\", ({ expect }) => {\n expect(typedKeys({})).toEqual([]);\n expect(typedKeys({ a: 1, b: 2 })).toEqual([\"a\", \"b\"]);\n expect(typedKeys({ a: \"hello\", b: true, c: null })).toEqual([\"a\", \"b\", \"c\"]);\n\n // Test with object containing methods\n const objWithMethod = { a: 1, b: () => \"test\" };\n expect(typedKeys(objWithMethod)).toEqual([\"a\", \"b\"]);\n});\n\nexport function typedValues<T extends {}>(obj: T): T[keyof T][] {\n return Object.values(obj) as any;\n}\nundefined?.test(\"typedValues\", ({ expect }) => {\n expect(typedValues({})).toEqual([]);\n expect(typedValues({ a: 1, b: 2 })).toEqual([1, 2]);\n\n // Test with mixed types\n type MixedObj = { a: string, b: boolean, c: null };\n const mixedObj: MixedObj = { a: \"hello\", b: true, c: null };\n expect(typedValues(mixedObj)).toEqual([\"hello\", true, null]);\n\n // Test with object containing methods\n type ObjWithFn = { a: number, b: () => string };\n const fn = () => \"test\";\n const objWithMethod: ObjWithFn = { a: 1, b: fn };\n const values = typedValues(objWithMethod);\n expect(values.length).toBe(2);\n expect(values[0]).toBe(1);\n expect(typeof values[1]).toBe(\"function\");\n // Need to cast to the correct type\n const fnValue = values[1] as () => string;\n expect(fnValue()).toBe(\"test\");\n});\n\nexport function typedAssign<T extends {}, U extends {}>(target: T, source: U): T & U {\n return Object.assign(target, source);\n}\nundefined?.test(\"typedAssign\", ({ expect }) => {\n // Test with empty objects\n const emptyTarget = {};\n const emptyResult = typedAssign(emptyTarget, { a: 1 });\n expect(emptyResult).toEqual({ a: 1 });\n expect(emptyResult).toBe(emptyTarget); // Same reference\n\n // Test with non-empty target\n const target = { a: 1, b: 2 };\n const result = typedAssign(target, { c: 3, d: 4 });\n expect(result).toEqual({ a: 1, b: 2, c: 3, d: 4 });\n expect(result).toBe(target); // Same reference\n\n // Test with overlapping properties\n const targetWithOverlap = { a: 1, b: 2 };\n const resultWithOverlap = typedAssign(targetWithOverlap, { b: 3, c: 4 });\n expect(resultWithOverlap).toEqual({ a: 1, b: 3, c: 4 });\n expect(resultWithOverlap).toBe(targetWithOverlap); // Same reference\n});\n\nexport type FilterUndefined<T> =\n & { [k in keyof T as (undefined extends T[k] ? (T[k] extends undefined | void ? never : k) : never)]+?: T[k] & ({} | null) }\n & { [k in keyof T as (undefined extends T[k] ? never : k)]: T[k] & ({} | null) }\n\n/**\n * Returns a new object with all undefined values removed. Useful when spreading optional parameters on an object, as\n * TypeScript's `Partial<XYZ>` type allows `undefined` values.\n */\nexport function filterUndefined<T extends object>(obj: T): FilterUndefined<T> {\n return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined)) as any;\n}\nundefined?.test(\"filterUndefined\", ({ expect }) => {\n expect(filterUndefined({})).toEqual({});\n expect(filterUndefined({ a: 1, b: 2 })).toEqual({ a: 1, b: 2 });\n expect(filterUndefined({ a: 1, b: undefined })).toEqual({ a: 1 });\n expect(filterUndefined({ a: undefined, b: undefined })).toEqual({});\n expect(filterUndefined({ a: null, b: undefined })).toEqual({ a: null });\n expect(filterUndefined({ a: 0, b: \"\", c: false, d: undefined })).toEqual({ a: 0, b: \"\", c: false });\n});\n\nexport type FilterUndefinedOrNull<T> = FilterUndefined<{ [k in keyof T]: null extends T[k] ? NonNullable<T[k]> | undefined : T[k] }>;\n\n/**\n * Returns a new object with all undefined and null values removed. Useful when spreading optional parameters on an object, as\n * TypeScript's `Partial<XYZ>` type allows `undefined` values.\n */\nexport function filterUndefinedOrNull<T extends object>(obj: T): FilterUndefinedOrNull<T> {\n return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined && v !== null)) as any;\n}\nundefined?.test(\"filterUndefinedOrNull\", ({ expect }) => {\n expect(filterUndefinedOrNull({})).toEqual({});\n expect(filterUndefinedOrNull({ a: 1, b: 2 })).toEqual({ a: 1, b: 2 });\n});\n\nexport type DeepFilterUndefined<T> = T extends object ? FilterUndefined<{ [K in keyof T]: DeepFilterUndefined<T[K]> }> : T;\n\nexport function deepFilterUndefined<T extends object>(obj: T): DeepFilterUndefined<T> {\n return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined).map(([k, v]) => [k, isObjectLike(v) ? deepFilterUndefined(v) : v])) as any;\n}\nundefined?.test(\"deepFilterUndefined\", ({ expect }) => {\n expect(deepFilterUndefined({ a: 1, b: undefined })).toEqual({ a: 1 });\n});\n\nexport function pick<T extends {}, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {\n return Object.fromEntries(Object.entries(obj).filter(([k]) => keys.includes(k as K))) as any;\n}\nundefined?.test(\"pick\", ({ expect }) => {\n const obj = { a: 1, b: 2, c: 3, d: 4 };\n expect(pick(obj, [\"a\", \"c\"])).toEqual({ a: 1, c: 3 });\n expect(pick(obj, [])).toEqual({});\n expect(pick(obj, [\"a\", \"e\" as keyof typeof obj])).toEqual({ a: 1 });\n // Use type assertion for empty object to avoid TypeScript error\n expect(pick({} as Record<string, unknown>, [\"a\"])).toEqual({});\n});\n\nexport function omit<T extends {}, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> {\n if (!Array.isArray(keys)) throw new StackAssertionError(\"omit: keys must be an array\", { obj, keys });\n return Object.fromEntries(Object.entries(obj).filter(([k]) => !keys.includes(k as K))) as any;\n}\nundefined?.test(\"omit\", ({ expect }) => {\n const obj = { a: 1, b: 2, c: 3, d: 4 };\n expect(omit(obj, [\"a\", \"c\"])).toEqual({ b: 2, d: 4 });\n expect(omit(obj, [])).toEqual(obj);\n expect(omit(obj, [\"a\", \"e\" as keyof typeof obj])).toEqual({ b: 2, c: 3, d: 4 });\n // Use type assertion for empty object to avoid TypeScript error\n expect(omit({} as Record<string, unknown>, [\"a\"])).toEqual({});\n});\n\nexport function split<T extends {}, K extends keyof T>(obj: T, keys: K[]): [Pick<T, K>, Omit<T, K>] {\n return [pick(obj, keys), omit(obj, keys)];\n}\nundefined?.test(\"split\", ({ expect }) => {\n const obj = { a: 1, b: 2, c: 3, d: 4 };\n expect(split(obj, [\"a\", \"c\"])).toEqual([{ a: 1, c: 3 }, { b: 2, d: 4 }]);\n expect(split(obj, [])).toEqual([{}, obj]);\n expect(split(obj, [\"a\", \"e\" as keyof typeof obj])).toEqual([{ a: 1 }, { b: 2, c: 3, d: 4 }]);\n // Use type assertion for empty object to avoid TypeScript error\n expect(split({} as Record<string, unknown>, [\"a\"])).toEqual([{}, {}]);\n});\n\nexport function mapValues<T extends object, U>(obj: T, fn: (value: T extends (infer E)[] ? E : T[keyof T]) => U): Record<keyof T, U> {\n if (Array.isArray(obj)) {\n return obj.map(v => fn(v)) as any;\n }\n return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, fn(v)])) as any;\n}\nundefined?.test(\"mapValues\", ({ expect }) => {\n expect(mapValues({ a: 1, b: 2 }, v => v * 2)).toEqual({ a: 2, b: 4 });\n expect(mapValues([1, 2, 3], v => v * 2)).toEqual([2, 4, 6]);\n});\n\nexport function sortKeys<T extends object>(obj: T): T {\n if (Array.isArray(obj)) {\n return [...obj] as any;\n }\n return Object.fromEntries(Object.entries(obj).sort(([a], [b]) => stringCompare(a, b))) as any;\n}\nundefined?.test(\"sortKeys\", ({ expect }) => {\n const obj = {\n \"1\": 0,\n \"10\": 1,\n b: 2,\n \"2\": 3,\n a: 4,\n \"-3.33\": 5,\n \"-4\": 6,\n \"-3\": 7,\n abc: 8,\n \"a-b\": 9,\n ab: 10,\n ac: 11,\n aa: 12,\n aab: 13,\n };\n expect(Object.entries(sortKeys(obj))).toEqual([\n [\"1\", 0],\n [\"2\", 3],\n [\"10\", 1],\n [\"-3\", 7],\n [\"-3.33\", 5],\n [\"-4\", 6],\n [\"a\", 4],\n [\"a-b\", 9],\n [\"aa\", 12],\n [\"aab\", 13],\n [\"ab\", 10],\n [\"abc\", 8],\n [\"ac\", 11],\n [\"b\", 2],\n ]);\n});\n\nexport function deepSortKeys<T extends object>(obj: T): T {\n return sortKeys(mapValues(obj, v => isObjectLike(v) ? deepSortKeys(v) : v)) as any;\n}\nundefined?.test(\"deepSortKeys\", ({ expect }) => {\n const obj = {\n h: { i: { k: 9, j: 8 }, l: 10 },\n b: { d: 3, c: 2 },\n a: 1,\n e: [4, 5, { g: 7, f: 6 }],\n };\n const sorted = deepSortKeys(obj);\n expect(Object.entries(sorted)).toEqual([\n [\"a\", 1],\n [\"b\", { c: 2, d: 3 }],\n [\"e\", [4, 5, { f: 6, g: 7 }]],\n [\"h\", { i: { j: 8, k: 9 }, l: 10 }],\n ]);\n expect(Object.entries(sorted.b)).toEqual([\n [\"c\", 2],\n [\"d\", 3],\n ]);\n expect(Object.entries(sorted.e[2])).toEqual([\n [\"f\", 6],\n [\"g\", 7],\n ]);\n expect(Object.entries(sorted.h)).toEqual([\n [\"i\", { j: 8, k: 9 }],\n [\"l\", 10],\n ]);\n expect(Object.entries(sorted.h.i)).toEqual([\n [\"j\", 8],\n [\"k\", 9],\n ]);\n});\n\nexport function set<T extends object, K extends keyof T>(obj: T, key: K, value: T[K]) {\n Object.defineProperty(obj, key, { value, writable: true, configurable: true, enumerable: true });\n}\n\nexport function get<T extends object, K extends keyof T>(obj: T, key: K): T[K] {\n const descriptor = Object.getOwnPropertyDescriptor(obj, key);\n if (!descriptor) throw new StackAssertionError(`get: key ${String(key)} does not exist`, { obj, key });\n return descriptor.value;\n}\n\nexport function getOrUndefined<T extends object, K extends keyof T>(obj: T, key: K): T[K] | undefined {\n return has(obj, key) ? get(obj, key) : undefined;\n}\n\nexport function has<T extends object, K extends keyof T>(obj: T, key: K): obj is T & { [k in K]: unknown } {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\n\nundefined?.test(\"has\", ({ expect }) => {\n const obj = { a: 1, b: undefined, c: null };\n expect(has(obj, \"a\")).toBe(true);\n expect(has(obj, \"b\")).toBe(true);\n expect(has(obj, \"c\")).toBe(true);\n expect(has(obj, \"d\" as keyof typeof obj)).toBe(false);\n});\n\n\nexport function hasAndNotUndefined<T extends object, K extends keyof T>(obj: T, key: K): obj is T & { [k in K]: Exclude<T[K], undefined> } {\n return has(obj, key) && get(obj, key) !== undefined;\n}\n\nexport function deleteKey<T extends object, K extends keyof T>(obj: T, key: K) {\n if (has(obj, key)) {\n Reflect.deleteProperty(obj, key);\n } else {\n throw new StackAssertionError(`deleteKey: key ${String(key)} does not exist`, { obj, key });\n }\n}\n\nexport function isObjectLike(value: unknown): value is object {\n return (typeof value === 'object' || typeof value === 'function') && value !== null;\n}\n"],"mappings":";AAAA,SAAS,2BAA2B;AACpC,SAAS,gBAAgB;AACzB,SAAS,qBAAqB;AAEvB,SAAS,UAAa,OAAmC;AAC9D,SAAO,UAAU,QAAQ,UAAU;AACrC;AAmBO,SAAS,gBAAmB,MAAS,MAAe,UAA+C,CAAC,GAAc;AACvH,MAAI,OAAO,SAAS,OAAO,KAAM,QAAO;AACxC,MAAI,SAAS,KAAM,QAAO;AAE1B,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK,UAAU;AACb,UAAI,CAAC,QAAQ,CAAC,KAAM,QAAO;AAE3B,UAAI,MAAM,QAAQ,IAAI,KAAK,MAAM,QAAQ,IAAI,GAAG;AAC9C,YAAI,CAAC,MAAM,QAAQ,IAAI,KAAK,CAAC,MAAM,QAAQ,IAAI,EAAG,QAAO;AACzD,YAAI,KAAK,WAAW,KAAK,OAAQ,QAAO;AACxC,eAAO,KAAK,MAAM,CAAC,GAAG,MAAM,gBAAgB,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC;AAAA,MAClE;AAEA,YAAM,WAAW,OAAO,QAAQ,IAAI,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,yBAAyB,MAAM,MAAS;AAC1G,YAAM,WAAW,OAAO,QAAQ,IAAI,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,yBAAyB,MAAM,MAAS;AAC1G,UAAI,SAAS,WAAW,SAAS,OAAQ,QAAO;AAChD,aAAO,SAAS,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM;AACjC,cAAM,KAAK,SAAS,KAAK,CAAC,CAAC,EAAE,MAAM,MAAM,EAAE;AAC3C,YAAI,CAAC,GAAI,QAAO;AAChB,eAAO,gBAAgB,IAAI,GAAG,CAAC,GAAG,OAAO;AAAA,MAC3C,CAAC;AAAA,IACH;AAAA,IACA,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK,YAAW;AACd,aAAO;AAAA,IACT;AAAA,IACA,SAAS;AACP,YAAM,IAAI,MAAM,uBAAuB,OAAO,IAAI;AAAA,IACpD;AAAA,EACF;AACF;AA2BO,SAAS,YAAe,KAA8C;AAC3E,SAAO,OAAO,QAAQ,YAAY,OAAO,QAAQ;AACnD;AAEO,SAAS,aAA+B,KAAW;AACxD,MAAI,CAAC,YAAY,GAAG,EAAG,OAAM,IAAI,oBAAoB,sDAAsD,EAAE,IAAI,CAAC;AAElH,MAAI,MAAM,QAAQ,GAAG,EAAG,QAAO,IAAI,IAAI,QAAQ;AAC/C,SAAO,EAAE,GAAG,IAAI;AAClB;AAOO,SAAS,eAAkB,KAAW;AAC3C,MAAI,OAAO,QAAQ,WAAY,OAAM,IAAI,oBAAoB,2CAA2C;AACxG,MAAI,OAAO,QAAQ,SAAU,OAAM,IAAI,oBAAoB,yCAAyC;AACpG,MAAI,OAAO,QAAQ,YAAY,CAAC,IAAK,QAAO;AAC5C,MAAI,MAAM,QAAQ,GAAG,EAAG,QAAO,IAAI,IAAI,cAAc;AACrD,SAAO,OAAO,YAAY,OAAO,QAAQ,GAAG,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;AACvF;AAqDO,SAAS,UAAsC,SAAY,UAA8B;AAC9F,MAAI,CAAC,SAAS,UAAU,GAAG,OAAO,OAAO,OAAO,GAAG,GAAG,OAAO,OAAO,QAAQ,CAAC,EAAE,KAAK,OAAK,CAAC,YAAY,CAAC,CAAC,EAAG,OAAM,IAAI,oBAAoB,mDAAmD,EAAE,SAAS,SAAS,CAAC;AAEjN,QAAM,MAAW,aAAa,OAAO;AACrC,aAAW,CAAC,KAAK,UAAU,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACxD,QAAI,IAAI,KAAK,GAAU,GAAG;AACxB,YAAM,YAAY,IAAI,KAAK,GAAU;AACrC,UAAI,aAAa,SAAS,KAAK,aAAa,UAAU,GAAG;AACvD,YAAI,KAAK,KAAK,UAAU,WAAW,UAAU,CAAC;AAC9C;AAAA,MACF;AAAA,IACF;AACA,QAAI,KAAK,KAAK,UAAU;AAAA,EAC1B;AACA,SAAO;AACT;AA+EO,SAAS,aAA2B,KAAiC;AAC1E,SAAO,OAAO,QAAQ,GAAG;AAC3B;AAgBO,SAAS,iBAA2C,SAA4C;AACrG,SAAO,OAAO,YAAY,OAAO;AACnC;AAqBO,SAAS,UAAwB,KAAqB;AAC3D,SAAO,OAAO,KAAK,GAAG;AACxB;AAWO,SAAS,YAA0B,KAAsB;AAC9D,SAAO,OAAO,OAAO,GAAG;AAC1B;AAuBO,SAAS,YAAwC,QAAW,QAAkB;AACnF,SAAO,OAAO,OAAO,QAAQ,MAAM;AACrC;AA6BO,SAAS,gBAAkC,KAA4B;AAC5E,SAAO,OAAO,YAAY,OAAO,QAAQ,GAAG,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,MAAM,MAAS,CAAC;AAClF;AAgBO,SAAS,sBAAwC,KAAkC;AACxF,SAAO,OAAO,YAAY,OAAO,QAAQ,GAAG,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,MAAM,UAAa,MAAM,IAAI,CAAC;AAChG;AAQO,SAAS,oBAAsC,KAAgC;AACpF,SAAO,OAAO,YAAY,OAAO,QAAQ,GAAG,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,MAAM,MAAS,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,aAAa,CAAC,IAAI,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC;AACrJ;AAKO,SAAS,KAAsC,KAAQ,MAAuB;AACnF,SAAO,OAAO,YAAY,OAAO,QAAQ,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAM,CAAC,CAAC;AACtF;AAUO,SAAS,KAAsC,KAAQ,MAAuB;AACnF,MAAI,CAAC,MAAM,QAAQ,IAAI,EAAG,OAAM,IAAI,oBAAoB,+BAA+B,EAAE,KAAK,KAAK,CAAC;AACpG,SAAO,OAAO,YAAY,OAAO,QAAQ,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,SAAS,CAAM,CAAC,CAAC;AACvF;AAUO,SAAS,MAAuC,KAAQ,MAAqC;AAClG,SAAO,CAAC,KAAK,KAAK,IAAI,GAAG,KAAK,KAAK,IAAI,CAAC;AAC1C;AAUO,SAAS,UAA+B,KAAQ,IAA8E;AACnI,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,WAAO,IAAI,IAAI,OAAK,GAAG,CAAC,CAAC;AAAA,EAC3B;AACA,SAAO,OAAO,YAAY,OAAO,QAAQ,GAAG,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;AAC3E;AAMO,SAAS,SAA2B,KAAW;AACpD,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,WAAO,CAAC,GAAG,GAAG;AAAA,EAChB;AACA,SAAO,OAAO,YAAY,OAAO,QAAQ,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,CAAC;AACvF;AAoCO,SAAS,aAA+B,KAAW;AACxD,SAAO,SAAS,UAAU,KAAK,OAAK,aAAa,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC;AAC5E;AAiCO,SAAS,IAAyC,KAAQ,KAAQ,OAAa;AACpF,SAAO,eAAe,KAAK,KAAK,EAAE,OAAO,UAAU,MAAM,cAAc,MAAM,YAAY,KAAK,CAAC;AACjG;AAEO,SAAS,IAAyC,KAAQ,KAAc;AAC7E,QAAM,aAAa,OAAO,yBAAyB,KAAK,GAAG;AAC3D,MAAI,CAAC,WAAY,OAAM,IAAI,oBAAoB,YAAY,OAAO,GAAG,CAAC,mBAAmB,EAAE,KAAK,IAAI,CAAC;AACrG,SAAO,WAAW;AACpB;AAEO,SAAS,eAAoD,KAAQ,KAA0B;AACpG,SAAO,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,IAAI;AACzC;AAEO,SAAS,IAAyC,KAAQ,KAA0C;AACzG,SAAO,OAAO,UAAU,eAAe,KAAK,KAAK,GAAG;AACtD;AAWO,SAAS,mBAAwD,KAAQ,KAA2D;AACzI,SAAO,IAAI,KAAK,GAAG,KAAK,IAAI,KAAK,GAAG,MAAM;AAC5C;AAEO,SAAS,UAA+C,KAAQ,KAAQ;AAC7E,MAAI,IAAI,KAAK,GAAG,GAAG;AACjB,YAAQ,eAAe,KAAK,GAAG;AAAA,EACjC,OAAO;AACL,UAAM,IAAI,oBAAoB,kBAAkB,OAAO,GAAG,CAAC,mBAAmB,EAAE,KAAK,IAAI,CAAC;AAAA,EAC5F;AACF;AAEO,SAAS,aAAa,OAAiC;AAC5D,UAAQ,OAAO,UAAU,YAAY,OAAO,UAAU,eAAe,UAAU;AACjF;","names":[]}
1
+ {"version":3,"sources":["../../../src/utils/objects.tsx"],"sourcesContent":["import { StackAssertionError } from \"./errors\";\nimport { identity } from \"./functions\";\nimport { stringCompare } from \"./strings\";\nimport { typeAssertIs } from \"./types\";\n\nexport function isNotNull<T>(value: T): value is NonNullable<T> {\n return value !== null && value !== undefined;\n}\nundefined?.test(\"isNotNull\", ({ expect }) => {\n expect(isNotNull(null)).toBe(false);\n expect(isNotNull(undefined)).toBe(false);\n expect(isNotNull(0)).toBe(true);\n expect(isNotNull(\"\")).toBe(true);\n expect(isNotNull(false)).toBe(true);\n expect(isNotNull({})).toBe(true);\n expect(isNotNull([])).toBe(true);\n});\n\nexport type DeepPartial<T> = T extends object ? (T extends any[] ? { [P in keyof T]: DeepPartial<T[P]> } : { [P in keyof T]?: DeepPartial<T[P]> }) : T;\nexport type DeepRequired<T> = T extends object ? { [P in keyof T]-?: DeepRequired<T[P]> } : T;\nexport type DeepRequiredOrUndefined<T> = T extends object ? { [P in keyof { [K in keyof T]-?: K}]: DeepRequiredOrUndefined<T[P]> } : T;\n\n\n/**\n * Assumes both objects are primitives, arrays, or non-function plain objects, and compares them deeply.\n *\n * Note that since they are assumed to be plain objects, this function does not compare prototypes.\n */\nexport function deepPlainEquals<T>(obj1: T, obj2: unknown, options: { ignoreUndefinedValues?: boolean } = {}): obj2 is T {\n if (typeof obj1 !== typeof obj2) return false;\n if (obj1 === obj2) return true;\n\n switch (typeof obj1) {\n case 'object': {\n if (!obj1 || !obj2) return false;\n\n if (Array.isArray(obj1) || Array.isArray(obj2)) {\n if (!Array.isArray(obj1) || !Array.isArray(obj2)) return false;\n if (obj1.length !== obj2.length) return false;\n return obj1.every((v, i) => deepPlainEquals(v, obj2[i], options));\n }\n\n const entries1 = Object.entries(obj1).filter(([k, v]) => !options.ignoreUndefinedValues || v !== undefined);\n const entries2 = Object.entries(obj2).filter(([k, v]) => !options.ignoreUndefinedValues || v !== undefined);\n if (entries1.length !== entries2.length) return false;\n return entries1.every(([k, v1]) => {\n const e2 = entries2.find(([k2]) => k === k2);\n if (!e2) return false;\n return deepPlainEquals(v1, e2[1], options);\n });\n }\n case 'undefined':\n case 'string':\n case 'number':\n case 'boolean':\n case 'bigint':\n case 'symbol':\n case 'function':{\n return false;\n }\n default: {\n throw new Error(\"Unexpected typeof \" + typeof obj1);\n }\n }\n}\nundefined?.test(\"deepPlainEquals\", ({ expect }) => {\n // Simple values\n expect(deepPlainEquals(1, 1)).toBe(true);\n expect(deepPlainEquals(\"test\", \"test\")).toBe(true);\n expect(deepPlainEquals(1, 2)).toBe(false);\n expect(deepPlainEquals(\"test\", \"other\")).toBe(false);\n\n // Arrays\n expect(deepPlainEquals([1, 2, 3], [1, 2, 3])).toBe(true);\n expect(deepPlainEquals([1, 2, 3], [1, 2, 4])).toBe(false);\n expect(deepPlainEquals([1, 2, 3], [1, 2])).toBe(false);\n\n // Objects\n expect(deepPlainEquals({ a: 1, b: 2 }, { a: 1, b: 2 })).toBe(true);\n expect(deepPlainEquals({ a: 1, b: 2 }, { a: 1, b: 3 })).toBe(false);\n expect(deepPlainEquals({ a: 1, b: 2 }, { a: 1 })).toBe(false);\n\n // Nested structures\n expect(deepPlainEquals({ a: 1, b: [1, 2, { c: 3 }] }, { a: 1, b: [1, 2, { c: 3 }] })).toBe(true);\n expect(deepPlainEquals({ a: 1, b: [1, 2, { c: 3 }] }, { a: 1, b: [1, 2, { c: 4 }] })).toBe(false);\n\n // With options\n expect(deepPlainEquals({ a: 1, b: undefined }, { a: 1 }, { ignoreUndefinedValues: true })).toBe(true);\n expect(deepPlainEquals({ a: 1, b: undefined }, { a: 1 })).toBe(false);\n});\n\nexport function isCloneable<T>(obj: T): obj is Exclude<T, symbol | Function> {\n return typeof obj !== 'symbol' && typeof obj !== 'function';\n}\n\nexport function shallowClone<T extends object>(obj: T): T {\n if (!isCloneable(obj)) throw new StackAssertionError(\"shallowClone does not support symbols or functions\", { obj });\n\n if (Array.isArray(obj)) return obj.map(identity) as T;\n return { ...obj };\n}\nundefined?.test(\"shallowClone\", ({ expect }) => {\n expect(shallowClone({ a: 1, b: 2 })).toEqual({ a: 1, b: 2 });\n expect(shallowClone([1, 2, 3])).toEqual([1, 2, 3]);\n expect(() => shallowClone(() => {})).toThrow();\n});\n\nexport function deepPlainClone<T>(obj: T): T {\n if (typeof obj === 'function') throw new StackAssertionError(\"deepPlainClone does not support functions\");\n if (typeof obj === 'symbol') throw new StackAssertionError(\"deepPlainClone does not support symbols\");\n if (typeof obj !== 'object' || !obj) return obj;\n if (Array.isArray(obj)) return obj.map(deepPlainClone) as any;\n return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, deepPlainClone(v)])) as any;\n}\nundefined?.test(\"deepPlainClone\", ({ expect }) => {\n // Primitive values\n expect(deepPlainClone(1)).toBe(1);\n expect(deepPlainClone(\"test\")).toBe(\"test\");\n expect(deepPlainClone(null)).toBe(null);\n expect(deepPlainClone(undefined)).toBe(undefined);\n\n // Arrays\n const arr = [1, 2, 3];\n const clonedArr = deepPlainClone(arr);\n expect(clonedArr).toEqual(arr);\n expect(clonedArr).not.toBe(arr); // Different reference\n\n // Objects\n const obj = { a: 1, b: 2 };\n const clonedObj = deepPlainClone(obj);\n expect(clonedObj).toEqual(obj);\n expect(clonedObj).not.toBe(obj); // Different reference\n\n // Nested structures\n const nested = { a: 1, b: [1, 2, { c: 3 }] };\n const clonedNested = deepPlainClone(nested);\n expect(clonedNested).toEqual(nested);\n expect(clonedNested).not.toBe(nested); // Different reference\n expect(clonedNested.b).not.toBe(nested.b); // Different reference for nested array\n expect(clonedNested.b[2]).not.toBe(nested.b[2]); // Different reference for nested object\n\n // Error cases\n expect(() => deepPlainClone(() => {})).toThrow();\n expect(() => deepPlainClone(Symbol())).toThrow();\n});\n\nexport type DeepMerge<T, U> = U extends any ? DeepMergeNonDistributive<T, U> : never; // distributive conditional type https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types\ntype DeepMergeNonDistributive<T, U> = Omit<T, keyof U> & Omit<U, keyof T> & DeepMergeInner<Pick<T, keyof U & keyof T>, Pick<U, keyof U & keyof T>>;\ntype DeepMergeInner<T, U> = {\n [K in { [Ki in keyof U]-?: Ki }[keyof U]]: // we use this weird construct instead of just `keyof U` because TypeScript automatically removes the `undefined` key when using `-?` as a modifier; this is a workaround to make TypeScript not recognize the -? and for us to get the `undefined` key back\n undefined extends U[K]\n ? K extends keyof T\n ? T[K] extends object\n ? Exclude<U[K], undefined> extends object\n ? DeepMerge<T[K], Exclude<U[K], undefined>>\n : T[K] | Exclude<U[K], undefined>\n : T[K] | Exclude<U[K], undefined>\n : Exclude<U[K], undefined>\n : K extends keyof T\n ? T[K] extends object\n ? U[K] extends object\n ? DeepMerge<T[K], U[K]>\n : U[K]\n : U[K]\n : U[K];\n};\nexport function deepMerge<T extends {}, U extends {}>(baseObj: T, mergeObj: U): DeepMerge<T, U> {\n if ([baseObj, mergeObj, ...Object.values(baseObj), ...Object.values(mergeObj)].some(o => !isCloneable(o))) throw new StackAssertionError(\"deepMerge does not support functions or symbols\", { baseObj, mergeObj });\n\n const res: any = shallowClone(baseObj);\n for (const [key, mergeValue] of Object.entries(mergeObj)) {\n if (has(res, key as any)) {\n const baseValue = get(res, key as any);\n if (isObjectLike(baseValue) && isObjectLike(mergeValue)) {\n set(res, key, deepMerge(baseValue, mergeValue));\n continue;\n }\n }\n set(res, key, mergeValue);\n }\n return res as any;\n}\nundefined?.test(\"deepMerge\", ({ expect }) => {\n // Test merging flat objects\n expect(deepMerge({ a: 1 }, { b: 2 })).toEqual({ a: 1, b: 2 });\n expect(deepMerge({ a: 1 }, { a: 2 })).toEqual({ a: 2 });\n expect(deepMerge({ a: 1, b: 2 }, { b: 3, c: 4 })).toEqual({ a: 1, b: 3, c: 4 });\n\n // Test with nested objects\n expect(deepMerge(\n { a: { x: 1, y: 2 }, b: 3 },\n { a: { y: 3, z: 4 }, c: 5 }\n )).toEqual({ a: { x: 1, y: 3, z: 4 }, b: 3, c: 5 });\n\n // Test with arrays\n expect(deepMerge(\n { a: [1, 2], b: 3 },\n { a: [3, 4], c: 5 }\n )).toEqual({ a: [3, 4], b: 3, c: 5 });\n\n // Test with null values\n expect(deepMerge(\n { a: { x: 1 }, b: null },\n { a: { y: 2 }, b: { z: 3 } }\n )).toEqual({ a: { x: 1, y: 2 }, b: { z: 3 } });\n\n // Test with undefined values\n expect(deepMerge(\n { a: 1, b: undefined },\n { b: 2, c: 3 }\n )).toEqual({ a: 1, b: 2, c: 3 });\n\n // Test deeply nested structures\n expect(deepMerge(\n {\n a: {\n x: { deep: 1 },\n y: [1, 2]\n },\n b: 2\n },\n {\n a: {\n x: { deeper: 3 },\n y: [3, 4]\n },\n c: 3\n }\n )).toEqual({\n a: {\n x: { deep: 1, deeper: 3 },\n y: [3, 4]\n },\n b: 2,\n c: 3\n });\n\n // Test with empty objects\n expect(deepMerge({}, { a: 1 })).toEqual({ a: 1 });\n expect(deepMerge({ a: 1 }, {})).toEqual({ a: 1 });\n expect(deepMerge({}, {})).toEqual({});\n\n // Test that original objects are not modified\n const base = { a: { x: 1 }, b: 2 };\n const merge = { a: { y: 2 }, c: 3 };\n const baseClone = deepPlainClone(base);\n const mergeClone = deepPlainClone(merge);\n\n const result = deepMerge(base, merge);\n expect(base).toEqual(baseClone);\n expect(merge).toEqual(mergeClone);\n expect(result).toEqual({ a: { x: 1, y: 2 }, b: 2, c: 3 });\n\n // Test error cases\n expect(() => deepMerge({ a: () => {} }, { b: 2 })).toThrow();\n expect(() => deepMerge({ a: 1 }, { b: () => {} })).toThrow();\n expect(() => deepMerge({ a: Symbol() }, { b: 2 })).toThrow();\n expect(() => deepMerge({ a: 1 }, { b: Symbol() })).toThrow();\n});\n\nexport type DeepOmit<T, U> = T extends object ? { [K in keyof T]: K extends keyof U ? (T[K] extends U[K] ? undefined : T[K]) : T[K] } : (T extends U ? undefined : T);\n\nexport function typedEntries<T extends {}>(obj: T): [Exclude<keyof T, number>, T[keyof T]][] {\n return Object.entries(obj) as any;\n}\nundefined?.test(\"typedEntries\", ({ expect }) => {\n expect(typedEntries({})).toEqual([]);\n expect(typedEntries({ a: 1, b: 2 })).toEqual([[\"a\", 1], [\"b\", 2]]);\n expect(typedEntries({ a: \"hello\", b: true, c: null })).toEqual([[\"a\", \"hello\"], [\"b\", true], [\"c\", null]]);\n\n // Test with object containing methods\n const objWithMethod = { a: 1, b: () => \"test\" };\n const entries = typedEntries(objWithMethod);\n expect(entries.length).toBe(2);\n expect(entries[0][0]).toBe(\"a\");\n expect(entries[0][1]).toBe(1);\n expect(entries[1][0]).toBe(\"b\");\n expect(typeof entries[1][1]).toBe(\"function\");\n});\n\nexport function typedFromEntries<K extends PropertyKey, V>(entries: (readonly [K, V])[]): Record<K, V> {\n return Object.fromEntries(entries) as any;\n}\nundefined?.test(\"typedFromEntries\", ({ expect }) => {\n expect(typedFromEntries([])).toEqual({});\n expect(typedFromEntries([[\"a\", 1], [\"b\", 2]])).toEqual({ a: 1, b: 2 });\n\n // Test with mixed types (using type assertion)\n const mixedEntries = [[\"a\", \"hello\"], [\"b\", true], [\"c\", null]] as [string, string | boolean | null][];\n const mixedObj = typedFromEntries(mixedEntries);\n expect(mixedObj).toEqual({ a: \"hello\", b: true, c: null });\n\n // Test with function values\n const fn = () => \"test\";\n type MixedValue = number | (() => string);\n const fnEntries: [string, MixedValue][] = [[\"a\", 1], [\"b\", fn]];\n const obj = typedFromEntries(fnEntries);\n expect(obj.a).toBe(1);\n expect(typeof obj.b).toBe(\"function\");\n // Type assertion needed for the function call\n expect((obj.b as () => string)()).toBe(\"test\");\n});\n\nexport function typedKeys<T extends {}>(obj: T): (Exclude<keyof T, number>)[] {\n return Object.keys(obj) as any;\n}\nundefined?.test(\"typedKeys\", ({ expect }) => {\n expect(typedKeys({})).toEqual([]);\n expect(typedKeys({ a: 1, b: 2 })).toEqual([\"a\", \"b\"]);\n expect(typedKeys({ a: \"hello\", b: true, c: null })).toEqual([\"a\", \"b\", \"c\"]);\n\n // Test with object containing methods\n const objWithMethod = { a: 1, b: () => \"test\" };\n expect(typedKeys(objWithMethod)).toEqual([\"a\", \"b\"]);\n});\n\nexport function typedValues<T extends {}>(obj: T): T[keyof T][] {\n return Object.values(obj) as any;\n}\nundefined?.test(\"typedValues\", ({ expect }) => {\n expect(typedValues({})).toEqual([]);\n expect(typedValues({ a: 1, b: 2 })).toEqual([1, 2]);\n\n // Test with mixed types\n type MixedObj = { a: string, b: boolean, c: null };\n const mixedObj: MixedObj = { a: \"hello\", b: true, c: null };\n expect(typedValues(mixedObj)).toEqual([\"hello\", true, null]);\n\n // Test with object containing methods\n type ObjWithFn = { a: number, b: () => string };\n const fn = () => \"test\";\n const objWithMethod: ObjWithFn = { a: 1, b: fn };\n const values = typedValues(objWithMethod);\n expect(values.length).toBe(2);\n expect(values[0]).toBe(1);\n expect(typeof values[1]).toBe(\"function\");\n // Need to cast to the correct type\n const fnValue = values[1] as () => string;\n expect(fnValue()).toBe(\"test\");\n});\n\nexport function typedAssign<T extends {}, U extends {}>(target: T, source: U): T & U {\n return Object.assign(target, source);\n}\nundefined?.test(\"typedAssign\", ({ expect }) => {\n // Test with empty objects\n const emptyTarget = {};\n const emptyResult = typedAssign(emptyTarget, { a: 1 });\n expect(emptyResult).toEqual({ a: 1 });\n expect(emptyResult).toBe(emptyTarget); // Same reference\n\n // Test with non-empty target\n const target = { a: 1, b: 2 };\n const result = typedAssign(target, { c: 3, d: 4 });\n expect(result).toEqual({ a: 1, b: 2, c: 3, d: 4 });\n expect(result).toBe(target); // Same reference\n\n // Test with overlapping properties\n const targetWithOverlap = { a: 1, b: 2 };\n const resultWithOverlap = typedAssign(targetWithOverlap, { b: 3, c: 4 });\n expect(resultWithOverlap).toEqual({ a: 1, b: 3, c: 4 });\n expect(resultWithOverlap).toBe(targetWithOverlap); // Same reference\n});\n\nexport type FilterUndefined<T> =\n & { [k in keyof T as (undefined extends T[k] ? (T[k] extends undefined | void ? never : k) : never)]+?: T[k] & ({} | null) }\n & { [k in keyof T as (undefined extends T[k] ? never : k)]: T[k] & ({} | null) }\n\n/**\n * Returns a new object with all undefined values removed. Useful when spreading optional parameters on an object, as\n * TypeScript's `Partial<XYZ>` type allows `undefined` values.\n */\nexport function filterUndefined<T extends object>(obj: T): FilterUndefined<T> {\n return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined)) as any;\n}\nundefined?.test(\"filterUndefined\", ({ expect }) => {\n expect(filterUndefined({})).toEqual({});\n expect(filterUndefined({ a: 1, b: 2 })).toEqual({ a: 1, b: 2 });\n expect(filterUndefined({ a: 1, b: undefined })).toEqual({ a: 1 });\n expect(filterUndefined({ a: undefined, b: undefined })).toEqual({});\n expect(filterUndefined({ a: null, b: undefined })).toEqual({ a: null });\n expect(filterUndefined({ a: 0, b: \"\", c: false, d: undefined })).toEqual({ a: 0, b: \"\", c: false });\n});\n\nexport type FilterUndefinedOrNull<T> = FilterUndefined<{ [k in keyof T]: null extends T[k] ? NonNullable<T[k]> | undefined : T[k] }>;\n\n/**\n * Returns a new object with all undefined and null values removed. Useful when spreading optional parameters on an object, as\n * TypeScript's `Partial<XYZ>` type allows `undefined` values.\n */\nexport function filterUndefinedOrNull<T extends object>(obj: T): FilterUndefinedOrNull<T> {\n return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined && v !== null)) as any;\n}\nundefined?.test(\"filterUndefinedOrNull\", ({ expect }) => {\n expect(filterUndefinedOrNull({})).toEqual({});\n expect(filterUndefinedOrNull({ a: 1, b: 2 })).toEqual({ a: 1, b: 2 });\n});\n\nexport type DeepFilterUndefined<T> = T extends object ? FilterUndefined<{ [K in keyof T]: DeepFilterUndefined<T[K]> }> : T;\ntypeAssertIs<DeepFilterUndefined<{ a: { b: { c?: undefined, d?: 123 } } }>, { a: { b: { d?: 123 } } }>()();\n\nexport function deepFilterUndefined<T extends object>(obj: T): DeepFilterUndefined<T> {\n return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined).map(([k, v]) => [k, isObjectLike(v) ? deepFilterUndefined(v) : v])) as any;\n}\nundefined?.test(\"deepFilterUndefined\", ({ expect }) => {\n expect(deepFilterUndefined({ a: 1, b: undefined })).toEqual({ a: 1 });\n});\n\nexport function pick<T extends {}, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {\n return Object.fromEntries(Object.entries(obj).filter(([k]) => keys.includes(k as K))) as any;\n}\nundefined?.test(\"pick\", ({ expect }) => {\n const obj = { a: 1, b: 2, c: 3, d: 4 };\n expect(pick(obj, [\"a\", \"c\"])).toEqual({ a: 1, c: 3 });\n expect(pick(obj, [])).toEqual({});\n expect(pick(obj, [\"a\", \"e\" as keyof typeof obj])).toEqual({ a: 1 });\n // Use type assertion for empty object to avoid TypeScript error\n expect(pick({} as Record<string, unknown>, [\"a\"])).toEqual({});\n});\n\nexport function omit<T extends {}, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> {\n if (!Array.isArray(keys)) throw new StackAssertionError(\"omit: keys must be an array\", { obj, keys });\n return Object.fromEntries(Object.entries(obj).filter(([k]) => !keys.includes(k as K))) as any;\n}\nundefined?.test(\"omit\", ({ expect }) => {\n const obj = { a: 1, b: 2, c: 3, d: 4 };\n expect(omit(obj, [\"a\", \"c\"])).toEqual({ b: 2, d: 4 });\n expect(omit(obj, [])).toEqual(obj);\n expect(omit(obj, [\"a\", \"e\" as keyof typeof obj])).toEqual({ b: 2, c: 3, d: 4 });\n // Use type assertion for empty object to avoid TypeScript error\n expect(omit({} as Record<string, unknown>, [\"a\"])).toEqual({});\n});\n\nexport function split<T extends {}, K extends keyof T>(obj: T, keys: K[]): [Pick<T, K>, Omit<T, K>] {\n return [pick(obj, keys), omit(obj, keys)];\n}\nundefined?.test(\"split\", ({ expect }) => {\n const obj = { a: 1, b: 2, c: 3, d: 4 };\n expect(split(obj, [\"a\", \"c\"])).toEqual([{ a: 1, c: 3 }, { b: 2, d: 4 }]);\n expect(split(obj, [])).toEqual([{}, obj]);\n expect(split(obj, [\"a\", \"e\" as keyof typeof obj])).toEqual([{ a: 1 }, { b: 2, c: 3, d: 4 }]);\n // Use type assertion for empty object to avoid TypeScript error\n expect(split({} as Record<string, unknown>, [\"a\"])).toEqual([{}, {}]);\n});\n\nexport function mapValues<T extends object, U>(obj: T, fn: (value: T extends (infer E)[] ? E : T[keyof T]) => U): Record<keyof T, U> {\n if (Array.isArray(obj)) {\n return obj.map(v => fn(v)) as any;\n }\n return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, fn(v)])) as any;\n}\nundefined?.test(\"mapValues\", ({ expect }) => {\n expect(mapValues({ a: 1, b: 2 }, v => v * 2)).toEqual({ a: 2, b: 4 });\n expect(mapValues([1, 2, 3], v => v * 2)).toEqual([2, 4, 6]);\n});\n\nexport function sortKeys<T extends object>(obj: T): T {\n if (Array.isArray(obj)) {\n return [...obj] as any;\n }\n return Object.fromEntries(Object.entries(obj).sort(([a], [b]) => stringCompare(a, b))) as any;\n}\nundefined?.test(\"sortKeys\", ({ expect }) => {\n const obj = {\n \"1\": 0,\n \"10\": 1,\n b: 2,\n \"2\": 3,\n a: 4,\n \"-3.33\": 5,\n \"-4\": 6,\n \"-3\": 7,\n abc: 8,\n \"a-b\": 9,\n ab: 10,\n ac: 11,\n aa: 12,\n aab: 13,\n };\n expect(Object.entries(sortKeys(obj))).toEqual([\n [\"1\", 0],\n [\"2\", 3],\n [\"10\", 1],\n [\"-3\", 7],\n [\"-3.33\", 5],\n [\"-4\", 6],\n [\"a\", 4],\n [\"a-b\", 9],\n [\"aa\", 12],\n [\"aab\", 13],\n [\"ab\", 10],\n [\"abc\", 8],\n [\"ac\", 11],\n [\"b\", 2],\n ]);\n});\n\nexport function deepSortKeys<T extends object>(obj: T): T {\n return sortKeys(mapValues(obj, v => isObjectLike(v) ? deepSortKeys(v) : v)) as any;\n}\nundefined?.test(\"deepSortKeys\", ({ expect }) => {\n const obj = {\n h: { i: { k: 9, j: 8 }, l: 10 },\n b: { d: 3, c: 2 },\n a: 1,\n e: [4, 5, { g: 7, f: 6 }],\n };\n const sorted = deepSortKeys(obj);\n expect(Object.entries(sorted)).toEqual([\n [\"a\", 1],\n [\"b\", { c: 2, d: 3 }],\n [\"e\", [4, 5, { f: 6, g: 7 }]],\n [\"h\", { i: { j: 8, k: 9 }, l: 10 }],\n ]);\n expect(Object.entries(sorted.b)).toEqual([\n [\"c\", 2],\n [\"d\", 3],\n ]);\n expect(Object.entries(sorted.e[2])).toEqual([\n [\"f\", 6],\n [\"g\", 7],\n ]);\n expect(Object.entries(sorted.h)).toEqual([\n [\"i\", { j: 8, k: 9 }],\n [\"l\", 10],\n ]);\n expect(Object.entries(sorted.h.i)).toEqual([\n [\"j\", 8],\n [\"k\", 9],\n ]);\n});\n\nexport function set<T extends object, K extends keyof T>(obj: T, key: K, value: T[K]) {\n Object.defineProperty(obj, key, { value, writable: true, configurable: true, enumerable: true });\n}\n\nexport function get<T extends object, K extends keyof T>(obj: T, key: K): T[K] {\n const descriptor = Object.getOwnPropertyDescriptor(obj, key);\n if (!descriptor) throw new StackAssertionError(`get: key ${String(key)} does not exist`, { obj, key });\n return descriptor.value;\n}\n\nexport function getOrUndefined<T extends object, K extends keyof T>(obj: T, key: K): T[K] | undefined {\n return has(obj, key) ? get(obj, key) : undefined;\n}\n\nexport function has<T extends object, K extends keyof T>(obj: T, key: K): obj is T & { [k in K]: unknown } {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\n\nundefined?.test(\"has\", ({ expect }) => {\n const obj = { a: 1, b: undefined, c: null };\n expect(has(obj, \"a\")).toBe(true);\n expect(has(obj, \"b\")).toBe(true);\n expect(has(obj, \"c\")).toBe(true);\n expect(has(obj, \"d\" as keyof typeof obj)).toBe(false);\n});\n\n\nexport function hasAndNotUndefined<T extends object, K extends keyof T>(obj: T, key: K): obj is T & { [k in K]: Exclude<T[K], undefined> } {\n return has(obj, key) && get(obj, key) !== undefined;\n}\n\nexport function deleteKey<T extends object, K extends keyof T>(obj: T, key: K) {\n if (has(obj, key)) {\n Reflect.deleteProperty(obj, key);\n } else {\n throw new StackAssertionError(`deleteKey: key ${String(key)} does not exist`, { obj, key });\n }\n}\n\n/**\n * Returns true iff the value is an object or a function, but not null.\n */\nexport function isObjectLike(value: unknown): value is object | Function {\n return (typeof value === 'object' || typeof value === 'function') && value !== null;\n}\n"],"mappings":"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","names":[]}
@@ -2,6 +2,9 @@
2
2
  import { findLastIndex, unique } from "./arrays.js";
3
3
  import { StackAssertionError } from "./errors.js";
4
4
  import { filterUndefined } from "./objects.js";
5
+ function typedJoin(strings, separator) {
6
+ return strings.join(separator);
7
+ }
5
8
  function typedToLowercase(s) {
6
9
  if (typeof s !== "string") throw new StackAssertionError("Expected a string for typedToLowercase", { s });
7
10
  return s.toLowerCase();
@@ -292,6 +295,7 @@ export {
292
295
  trimEmptyLinesStart,
293
296
  trimLines,
294
297
  typedCapitalize,
298
+ typedJoin,
295
299
  typedToLowercase,
296
300
  typedToUppercase
297
301
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utils/strings.tsx"],"sourcesContent":["import { findLastIndex, unique } from \"./arrays\";\nimport { StackAssertionError } from \"./errors\";\nimport { filterUndefined } from \"./objects\";\n\nexport function typedToLowercase<S extends string>(s: S): Lowercase<S> {\n if (typeof s !== \"string\") throw new StackAssertionError(\"Expected a string for typedToLowercase\", { s });\n return s.toLowerCase() as Lowercase<S>;\n}\nundefined?.test(\"typedToLowercase\", ({ expect }) => {\n expect(typedToLowercase(\"\")).toBe(\"\");\n expect(typedToLowercase(\"HELLO\")).toBe(\"hello\");\n expect(typedToLowercase(\"Hello World\")).toBe(\"hello world\");\n expect(typedToLowercase(\"hello\")).toBe(\"hello\");\n expect(typedToLowercase(\"123\")).toBe(\"123\");\n expect(typedToLowercase(\"MIXED123case\")).toBe(\"mixed123case\");\n expect(typedToLowercase(\"Special@Chars!\")).toBe(\"special@chars!\");\n expect(() => typedToLowercase(123 as any)).toThrow(\"Expected a string for typedToLowercase\");\n});\n\nexport function typedToUppercase<S extends string>(s: S): Uppercase<S> {\n if (typeof s !== \"string\") throw new StackAssertionError(\"Expected a string for typedToUppercase\", { s });\n return s.toUpperCase() as Uppercase<S>;\n}\nundefined?.test(\"typedToUppercase\", ({ expect }) => {\n expect(typedToUppercase(\"\")).toBe(\"\");\n expect(typedToUppercase(\"hello\")).toBe(\"HELLO\");\n expect(typedToUppercase(\"Hello World\")).toBe(\"HELLO WORLD\");\n expect(typedToUppercase(\"HELLO\")).toBe(\"HELLO\");\n expect(typedToUppercase(\"123\")).toBe(\"123\");\n expect(typedToUppercase(\"mixed123Case\")).toBe(\"MIXED123CASE\");\n expect(typedToUppercase(\"special@chars!\")).toBe(\"SPECIAL@CHARS!\");\n expect(() => typedToUppercase(123 as any)).toThrow(\"Expected a string for typedToUppercase\");\n});\n\nexport function typedCapitalize<S extends string>(s: S): Capitalize<S> {\n return s.charAt(0).toUpperCase() + s.slice(1) as Capitalize<S>;\n}\nundefined?.test(\"typedCapitalize\", ({ expect }) => {\n expect(typedCapitalize(\"\")).toBe(\"\");\n expect(typedCapitalize(\"hello\")).toBe(\"Hello\");\n expect(typedCapitalize(\"hello world\")).toBe(\"Hello world\");\n expect(typedCapitalize(\"HELLO\")).toBe(\"HELLO\");\n expect(typedCapitalize(\"123test\")).toBe(\"123test\");\n expect(typedCapitalize(\"already Capitalized\")).toBe(\"Already Capitalized\");\n expect(typedCapitalize(\"h\")).toBe(\"H\");\n});\n\n/**\n * Compares two strings in a way that is not dependent on the current locale.\n */\nexport function stringCompare(a: string, b: string): number {\n if (typeof a !== \"string\" || typeof b !== \"string\") throw new StackAssertionError(`Expected two strings for stringCompare, found ${typeof a} and ${typeof b}`, { a, b });\n const cmp = (a: string, b: string) => a < b ? -1 : a > b ? 1 : 0;\n return cmp(a.toUpperCase(), b.toUpperCase()) || cmp(b, a);\n}\nundefined?.test(\"stringCompare\", ({ expect }) => {\n // Equal strings\n expect(stringCompare(\"a\", \"a\")).toBe(0);\n expect(stringCompare(\"\", \"\")).toBe(0);\n\n // Case comparison - note that this function is NOT case-insensitive\n // It compares uppercase versions first, then original strings\n expect(stringCompare(\"a\", \"A\")).toBe(-1); // lowercase comes after uppercase\n expect(stringCompare(\"A\", \"a\")).toBe(1); // uppercase comes before lowercase\n expect(stringCompare(\"abc\", \"ABC\")).toBe(-1);\n expect(stringCompare(\"ABC\", \"abc\")).toBe(1);\n\n // Different strings\n expect(stringCompare(\"a\", \"b\")).toBe(-1);\n expect(stringCompare(\"b\", \"a\")).toBe(1);\n\n // Strings with different lengths\n expect(stringCompare(\"abc\", \"abcd\")).toBe(-1);\n expect(stringCompare(\"abcd\", \"abc\")).toBe(1);\n\n // Strings with numbers\n expect(stringCompare(\"a1\", \"a2\")).toBe(-1);\n expect(stringCompare(\"a10\", \"a2\")).toBe(-1);\n\n // Strings with special characters\n expect(stringCompare(\"a\", \"a!\")).toBe(-1);\n expect(stringCompare(\"a!\", \"a\")).toBe(1);\n});\n\n/**\n * Returns all whitespace character at the start of the string.\n *\n * Uses the same definition for whitespace as `String.prototype.trim()`.\n */\nexport function getWhitespacePrefix(s: string): string {\n return s.substring(0, s.length - s.trimStart().length);\n}\nundefined?.test(\"getWhitespacePrefix\", ({ expect }) => {\n expect(getWhitespacePrefix(\"\")).toBe(\"\");\n expect(getWhitespacePrefix(\"hello\")).toBe(\"\");\n expect(getWhitespacePrefix(\" hello\")).toBe(\" \");\n expect(getWhitespacePrefix(\" hello\")).toBe(\" \");\n expect(getWhitespacePrefix(\"\\thello\")).toBe(\"\\t\");\n expect(getWhitespacePrefix(\"\\n hello\")).toBe(\"\\n \");\n expect(getWhitespacePrefix(\" \")).toBe(\" \");\n expect(getWhitespacePrefix(\" \\t\\n\\r\")).toBe(\" \\t\\n\\r\");\n});\n\n/**\n * Returns all whitespace character at the end of the string.\n *\n * Uses the same definition for whitespace as `String.prototype.trim()`.\n */\nexport function getWhitespaceSuffix(s: string): string {\n return s.substring(s.trimEnd().length);\n}\nundefined?.test(\"getWhitespaceSuffix\", ({ expect }) => {\n expect(getWhitespaceSuffix(\"\")).toBe(\"\");\n expect(getWhitespaceSuffix(\"hello\")).toBe(\"\");\n expect(getWhitespaceSuffix(\"hello \")).toBe(\" \");\n expect(getWhitespaceSuffix(\"hello \")).toBe(\" \");\n expect(getWhitespaceSuffix(\"hello\\t\")).toBe(\"\\t\");\n expect(getWhitespaceSuffix(\"hello \\n\")).toBe(\" \\n\");\n expect(getWhitespaceSuffix(\" \")).toBe(\" \");\n expect(getWhitespaceSuffix(\" \\t\\n\\r\")).toBe(\" \\t\\n\\r\");\n});\n\n/**\n * Returns a string with all empty or whitespace-only lines at the start removed.\n *\n * Uses the same definition for whitespace as `String.prototype.trim()`.\n */\nexport function trimEmptyLinesStart(s: string): string {\n const lines = s.split(\"\\n\");\n const firstNonEmptyLineIndex = lines.findIndex((line) => line.trim() !== \"\");\n // If all lines are empty or whitespace-only, return an empty string\n if (firstNonEmptyLineIndex === -1) return \"\";\n return lines.slice(firstNonEmptyLineIndex).join(\"\\n\");\n}\nundefined?.test(\"trimEmptyLinesStart\", ({ expect }) => {\n expect(trimEmptyLinesStart(\"\")).toBe(\"\");\n expect(trimEmptyLinesStart(\"hello\")).toBe(\"hello\");\n expect(trimEmptyLinesStart(\"\\nhello\")).toBe(\"hello\");\n expect(trimEmptyLinesStart(\"\\n\\nhello\")).toBe(\"hello\");\n expect(trimEmptyLinesStart(\" \\n\\t\\nhello\")).toBe(\"hello\");\n expect(trimEmptyLinesStart(\"\\n\\nhello\\nworld\")).toBe(\"hello\\nworld\");\n expect(trimEmptyLinesStart(\"hello\\n\\nworld\")).toBe(\"hello\\n\\nworld\");\n expect(trimEmptyLinesStart(\"hello\\nworld\\n\")).toBe(\"hello\\nworld\\n\");\n expect(trimEmptyLinesStart(\"\\n \\n\\nhello\\n \\nworld\")).toBe(\"hello\\n \\nworld\");\n // Edge case: all lines are empty\n expect(trimEmptyLinesStart(\"\\n\\n \\n\\t\")).toBe(\"\");\n});\n\n/**\n * Returns a string with all empty or whitespace-only lines at the end removed.\n *\n * Uses the same definition for whitespace as `String.prototype.trim()`.\n */\nexport function trimEmptyLinesEnd(s: string): string {\n const lines = s.split(\"\\n\");\n const lastNonEmptyLineIndex = findLastIndex(lines, (line) => line.trim() !== \"\");\n return lines.slice(0, lastNonEmptyLineIndex + 1).join(\"\\n\");\n}\nundefined?.test(\"trimEmptyLinesEnd\", ({ expect }) => {\n expect(trimEmptyLinesEnd(\"\")).toBe(\"\");\n expect(trimEmptyLinesEnd(\"hello\")).toBe(\"hello\");\n expect(trimEmptyLinesEnd(\"hello\\n\")).toBe(\"hello\");\n expect(trimEmptyLinesEnd(\"hello\\n\\n\")).toBe(\"hello\");\n expect(trimEmptyLinesEnd(\"hello\\n \\n\\t\")).toBe(\"hello\");\n expect(trimEmptyLinesEnd(\"hello\\nworld\\n\\n\")).toBe(\"hello\\nworld\");\n expect(trimEmptyLinesEnd(\"hello\\n\\nworld\")).toBe(\"hello\\n\\nworld\");\n expect(trimEmptyLinesEnd(\"\\nhello\\nworld\")).toBe(\"\\nhello\\nworld\");\n expect(trimEmptyLinesEnd(\"hello\\n \\nworld\\n\\n \")).toBe(\"hello\\n \\nworld\");\n // Edge case: all lines are empty\n expect(trimEmptyLinesEnd(\"\\n\\n \\n\\t\")).toBe(\"\");\n});\n\n/**\n * Returns a string with all empty or whitespace-only lines trimmed at the start and end.\n *\n * Uses the same definition for whitespace as `String.prototype.trim()`.\n */\nexport function trimLines(s: string): string {\n return trimEmptyLinesEnd(trimEmptyLinesStart(s));\n}\nundefined?.test(\"trimLines\", ({ expect }) => {\n expect(trimLines(\"\")).toBe(\"\");\n expect(trimLines(\" \")).toBe(\"\");\n expect(trimLines(\" \\n \")).toBe(\"\");\n expect(trimLines(\" abc \")).toBe(\" abc \");\n expect(trimLines(\"\\n \\nLine1\\nLine2\\n \\n\")).toBe(\"Line1\\nLine2\");\n expect(trimLines(\"Line1\\n \\nLine2\")).toBe(\"Line1\\n \\nLine2\");\n expect(trimLines(\" \\n \\n\\t\")).toBe(\"\");\n expect(trimLines(\" Hello World\")).toBe(\" Hello World\");\n expect(trimLines(\"\\n\")).toBe(\"\");\n expect(trimLines(\"\\t \\n\\t\\tLine1 \\n \\nLine2\\t\\t\\n\\t \")).toBe(\"\\t\\tLine1 \\n \\nLine2\\t\\t\");\n});\n\n\n/**\n * A template literal tag that returns the same string as the template literal without a tag.\n *\n * Useful for implementing your own template literal tags.\n */\nexport function templateIdentity(strings: TemplateStringsArray | readonly string[], ...values: string[]): string {\n if (values.length !== strings.length - 1) throw new StackAssertionError(\"Invalid number of values; must be one less than strings\", { strings, values });\n\n return strings.reduce((result, str, i) => result + str + (values[i] ?? ''), '');\n}\nundefined?.test(\"templateIdentity\", ({ expect }) => {\n expect(templateIdentity`Hello World`).toBe(\"Hello World\");\n expect(templateIdentity`${\"Hello\"}`).toBe(\"Hello\");\n const greeting = \"Hello\";\n const subject = \"World\";\n expect(templateIdentity`${greeting}, ${subject}!`).toBe(\"Hello, World!\");\n expect(templateIdentity`${\"A\"}${\"B\"}${\"C\"}`).toBe(\"ABC\");\n expect(templateIdentity`Start${\"\"}Middle${\"\"}End`).toBe(\"StartMiddleEnd\");\n expect(templateIdentity``).toBe(\"\");\n expect(templateIdentity`Line1\nLine2`).toBe(\"Line1\\nLine2\");\n expect(templateIdentity([\"a \", \" scientific \", \"gun\"], \"certain\", \"rail\")).toBe(\"a certain scientific railgun\");\n expect(templateIdentity([\"only one part\"])).toBe(\"only one part\");\n expect(() => templateIdentity([\"a \", \"b\", \"c\"], \"only one\")).toThrow(\"Invalid number of values\");\n expect(() => templateIdentity([\"a\", \"b\"], \"x\", \"y\")).toThrow(\"Invalid number of values\");\n});\n\n\nexport function deindent(code: string): string;\nexport function deindent(strings: TemplateStringsArray | readonly string[], ...values: any[]): string;\nexport function deindent(strings: string | readonly string[], ...values: any[]): string {\n if (typeof strings === \"string\") return deindent([strings]);\n return templateIdentity(...deindentTemplate(strings, ...values));\n}\n\nexport function deindentTemplate(strings: TemplateStringsArray | readonly string[], ...values: any[]): [string[], ...string[]] {\n if (values.length !== strings.length - 1) throw new StackAssertionError(\"Invalid number of values; must be one less than strings\", { strings, values });\n\n const trimmedStrings = [...strings];\n trimmedStrings[0] = trimEmptyLinesStart(trimmedStrings[0] + \"+\").slice(0, -1);\n trimmedStrings[trimmedStrings.length - 1] = trimEmptyLinesEnd(\"+\" + trimmedStrings[trimmedStrings.length - 1]).slice(1);\n\n const indentation = trimmedStrings\n .join(\"${SOME_VALUE}\")\n .split(\"\\n\")\n .filter((line) => line.trim() !== \"\")\n .map((line) => getWhitespacePrefix(line).length)\n .reduce((min, current) => Math.min(min, current), Infinity);\n\n const deindentedStrings = trimmedStrings\n .map((string, stringIndex) => {\n return string\n .split(\"\\n\")\n .map((line, lineIndex) => stringIndex !== 0 && lineIndex === 0 ? line : line.substring(indentation))\n .join(\"\\n\");\n });\n\n const indentedValues = values.map((value, i) => {\n const firstLineIndentation = getWhitespacePrefix(deindentedStrings[i].split(\"\\n\").at(-1)!);\n return `${value}`.replaceAll(\"\\n\", `\\n${firstLineIndentation}`);\n });\n\n return [deindentedStrings, ...indentedValues];\n}\nundefined?.test(\"deindent\", ({ expect }) => {\n // Test with string input\n expect(deindent(\" hello\")).toBe(\"hello\");\n expect(deindent(\" hello\\n world\")).toBe(\"hello\\nworld\");\n expect(deindent(\" hello\\n world\")).toBe(\"hello\\n world\");\n expect(deindent(\"\\n hello\\n world\\n\")).toBe(\"hello\\nworld\");\n\n // Test with empty input\n expect(deindent(\"\")).toBe(\"\");\n\n // Test with template literal\n expect(deindent`\n hello\n world\n `).toBe(\"hello\\nworld\");\n\n expect(deindent`\n hello\n world\n `).toBe(\"hello\\n world\");\n\n // Test with values\n const value = \"test\";\n expect(deindent`\n hello ${value}\n world\n `).toBe(`hello ${value}\\nworld`);\n\n // Test with multiline values\n expect(deindent`\n hello\n to ${\"line1\\n line2\"}\n world\n `).toBe(`hello\\n to line1\\n line2\\nworld`);\n\n // Leading whitespace values\n expect(deindent`\n ${\" \"}A\n ${\" \"}B\n ${\" \"}C\n `).toBe(` A\\n B\\n C`);\n\n // Trailing whitespaces (note: there are two whitespaces each after A and after C)\n expect(deindent`\n A \n B ${\" \"}\n C \n `).toBe(`A \\nB \\nC `);\n\n // Test with mixed indentation\n expect(deindent`\n hello\n world\n !\n `).toBe(\"hello\\n world\\n !\");\n\n // Test error cases\n expect(() => deindent([\"a\", \"b\", \"c\"], \"too\", \"many\", \"values\")).toThrow(\"Invalid number of values\");\n});\n\nexport function extractScopes(scope: string, removeDuplicates=true): string[] {\n // TODO what is this for? can we move this into the OAuth code in the backend?\n const trimmedString = scope.trim();\n const scopesArray = trimmedString.split(/\\s+/);\n const filtered = scopesArray.filter(scope => scope.length > 0);\n return removeDuplicates ? [...new Set(filtered)] : filtered;\n}\nundefined?.test(\"extractScopes\", ({ expect }) => {\n // Test with empty string\n expect(extractScopes(\"\")).toEqual([]);\n\n // Test with single scope\n expect(extractScopes(\"read\")).toEqual([\"read\"]);\n\n // Test with multiple scopes\n expect(extractScopes(\"read write\")).toEqual([\"read\", \"write\"]);\n\n // Test with extra whitespace\n expect(extractScopes(\" read write \")).toEqual([\"read\", \"write\"]);\n\n // Test with newlines and tabs\n expect(extractScopes(\"read\\nwrite\\tdelete\")).toEqual([\"read\", \"write\", \"delete\"]);\n\n // Test with duplicates (default behavior)\n expect(extractScopes(\"read write read\")).toEqual([\"read\", \"write\"]);\n\n // Test with duplicates (explicitly set to remove)\n expect(extractScopes(\"read write read\", true)).toEqual([\"read\", \"write\"]);\n\n // Test with duplicates (explicitly set to keep)\n expect(extractScopes(\"read write read\", false)).toEqual([\"read\", \"write\", \"read\"]);\n});\n\nexport function mergeScopeStrings(...scopes: string[]): string {\n // TODO what is this for? can we move this into the OAuth code in the backend?\n const allScope = scopes.map((s) => extractScopes(s)).flat().join(\" \");\n return extractScopes(allScope).join(\" \");\n}\nundefined?.test(\"mergeScopeStrings\", ({ expect }) => {\n // Test with empty input\n expect(mergeScopeStrings()).toBe(\"\");\n\n // Test with single scope string\n expect(mergeScopeStrings(\"read write\")).toBe(\"read write\");\n\n // Test with multiple scope strings\n expect(mergeScopeStrings(\"read\", \"write\")).toBe(\"read write\");\n\n // Test with overlapping scopes\n expect(mergeScopeStrings(\"read write\", \"write delete\")).toBe(\"read write delete\");\n\n // Test with extra whitespace\n expect(mergeScopeStrings(\" read write \", \" delete \")).toBe(\"read write delete\");\n\n // Test with duplicates across strings\n expect(mergeScopeStrings(\"read write\", \"write delete\", \"read\")).toBe(\"read write delete\");\n\n // Test with empty strings\n expect(mergeScopeStrings(\"read write\", \"\", \"delete\")).toBe(\"read write delete\");\n});\n\nexport function escapeTemplateLiteral(s: string): string {\n return s.replaceAll(\"`\", \"\\\\`\").replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll(\"$\", \"\\\\$\");\n}\nundefined?.test(\"escapeTemplateLiteral\", ({ expect }) => {\n // Test with empty string\n expect(escapeTemplateLiteral(\"\")).toBe(\"\");\n\n // Test with normal string (no special characters)\n expect(escapeTemplateLiteral(\"hello world\")).toBe(\"hello world\");\n\n // Test with backtick\n const input1 = \"hello `world`\";\n const output1 = escapeTemplateLiteral(input1);\n // Verify backticks are escaped\n expect(output1.includes(\"\\\\`\")).toBe(true);\n expect(output1).not.toBe(input1);\n\n // Test with backslash\n const input2 = \"hello \\\\world\";\n const output2 = escapeTemplateLiteral(input2);\n // Verify backslashes are escaped\n expect(output2.includes(\"\\\\\\\\\")).toBe(true);\n expect(output2).not.toBe(input2);\n\n // Test with dollar sign\n const input3 = \"hello $world\";\n const output3 = escapeTemplateLiteral(input3);\n // Verify dollar signs are escaped\n expect(output3.includes(\"\\\\$\")).toBe(true);\n expect(output3).not.toBe(input3);\n\n // Test with multiple special characters\n const input4 = \"`hello` $world\\\\\";\n const output4 = escapeTemplateLiteral(input4);\n // Verify all special characters are escaped\n expect(output4.includes(\"\\\\`\")).toBe(true);\n expect(output4.includes(\"\\\\$\")).toBe(true);\n expect(output4.includes(\"\\\\\\\\\")).toBe(true);\n expect(output4).not.toBe(input4);\n\n // Test with already escaped characters\n const input5 = \"\\\\`hello\\\\`\";\n const output5 = escapeTemplateLiteral(input5);\n // Verify already escaped characters are properly escaped\n expect(output5).not.toBe(input5);\n});\n\n/**\n * Some classes have different constructor names in different environments (eg. `Headers` is sometimes called `_Headers`,\n * so we create an object of overrides to handle these cases.\n */\nconst nicifiableClassNameOverrides = new Map(Object.entries({\n Headers,\n} as Record<string, unknown>).map(([k, v]) => [v, k]));\nexport type Nicifiable = {\n getNicifiableKeys?(): PropertyKey[],\n getNicifiedObjectExtraLines?(): string[],\n};\nexport type NicifyOptions = {\n maxDepth: number,\n currentIndent: string,\n lineIndent: string,\n multiline: boolean,\n refs: Map<unknown, string>,\n path: string,\n parent: null | {\n options: NicifyOptions,\n value: unknown,\n },\n keyInParent: PropertyKey | null,\n hideFields: PropertyKey[],\n overrides: (...args: Parameters<typeof nicify>) => string | null,\n};\nexport function nicify(\n value: unknown,\n options: Partial<NicifyOptions> = {},\n): string {\n const fullOptions: NicifyOptions = {\n maxDepth: 5,\n currentIndent: \"\",\n lineIndent: \" \",\n multiline: true,\n refs: new Map(),\n path: \"value\",\n parent: null,\n overrides: () => null,\n keyInParent: null,\n hideFields: [],\n ...filterUndefined(options),\n };\n const {\n maxDepth,\n currentIndent,\n lineIndent,\n multiline,\n refs,\n path,\n overrides,\n hideFields,\n } = fullOptions;\n const nl = `\\n${currentIndent}`;\n\n const overrideResult = overrides(value, options);\n if (overrideResult !== null) return overrideResult;\n\n if ([\"function\", \"object\", \"symbol\"].includes(typeof value) && value !== null) {\n if (refs.has(value)) {\n return `Ref<${refs.get(value)}>`;\n }\n refs.set(value, path);\n }\n\n const newOptions: NicifyOptions = {\n maxDepth: maxDepth - 1,\n currentIndent,\n lineIndent,\n multiline,\n refs,\n path: path + \"->[unknown property]\",\n overrides,\n parent: { value, options: fullOptions },\n keyInParent: null,\n hideFields: [],\n };\n const nestedNicify = (newValue: unknown, newPath: string, keyInParent: PropertyKey | null, options: Partial<NicifyOptions> = {}) => {\n return nicify(newValue, {\n ...newOptions,\n path: newPath,\n currentIndent: currentIndent + lineIndent,\n keyInParent,\n ...options,\n });\n };\n\n switch (typeof value) {\n case \"boolean\": case \"number\": {\n return JSON.stringify(value);\n }\n case \"string\": {\n const isDeindentable = (v: string) => deindent(v) === v && v.includes(\"\\n\");\n const wrapInDeindent = (v: string) => deindent`\n deindent\\`\n ${currentIndent + lineIndent}${escapeTemplateLiteral(v).replaceAll(\"\\n\", nl + lineIndent)}\n ${currentIndent}\\`\n `;\n if (isDeindentable(value)) {\n return wrapInDeindent(value);\n } else if (value.endsWith(\"\\n\") && isDeindentable(value.slice(0, -1))) {\n return wrapInDeindent(value.slice(0, -1)) + ' + \"\\\\n\"';\n } else {\n return JSON.stringify(value);\n }\n }\n case \"undefined\": {\n return \"undefined\";\n }\n case \"symbol\": {\n return value.toString();\n }\n case \"bigint\": {\n return `${value}n`;\n }\n case \"function\": {\n if (value.name) return `function ${value.name}(...) { ... }`;\n return `(...) => { ... }`;\n }\n case \"object\": {\n if (value === null) return \"null\";\n if (Array.isArray(value)) {\n const extraLines = getNicifiedObjectExtraLines(value);\n const resValueLength = value.length + extraLines.length;\n if (maxDepth <= 0 && resValueLength === 0) return \"[...]\";\n const resValues = value.map((v, i) => nestedNicify(v, `${path}[${i}]`, i));\n resValues.push(...extraLines);\n if (resValues.length !== resValueLength) throw new StackAssertionError(\"nicify of object: resValues.length !== resValueLength\", { value, resValues, resValueLength });\n const shouldIndent = resValues.length > 4 || resValues.some(x => (resValues.length > 1 && x.length > 4) || x.includes(\"\\n\"));\n if (shouldIndent) {\n return `[${nl}${resValues.map(x => `${lineIndent}${x},${nl}`).join(\"\")}]`;\n } else {\n return `[${resValues.join(\", \")}]`;\n }\n }\n if (value instanceof URL) {\n return `URL(${nestedNicify(value.toString(), `${path}.toString()`, null)})`;\n }\n if (ArrayBuffer.isView(value)) {\n return `${value.constructor.name}([${value.toString()}])`;\n }\n if (value instanceof Error) {\n let stack = value.stack ?? \"\";\n const toString = value.toString();\n if (!stack.startsWith(toString)) stack = `${toString}\\n${stack}`; // some browsers don't include the error message in the stack, some do\n stack = stack.trimEnd();\n stack = stack.replace(/\\n\\s+/g, `\\n${lineIndent}${lineIndent}`);\n stack = stack.replace(\"\\n\", `\\n${lineIndent}Stack:\\n`);\n if (Object.keys(value).length > 0) {\n stack += `\\n${lineIndent}Extra properties: ${nestedNicify(Object.fromEntries(Object.entries(value)), path, null)}`;\n }\n if (value.cause) {\n stack += `\\n${lineIndent}Cause:\\n${lineIndent}${lineIndent}${nestedNicify(value.cause, path, null, { currentIndent: currentIndent + lineIndent + lineIndent })}`;\n }\n stack = stack.replaceAll(\"\\n\", `\\n${currentIndent}`);\n return stack;\n }\n\n const constructorName = [null, Object.prototype].includes(Object.getPrototypeOf(value)) ? null : (nicifiableClassNameOverrides.get(value.constructor) ?? value.constructor.name);\n const constructorString = constructorName ? `${constructorName} ` : \"\";\n\n const entries = getNicifiableEntries(value).filter(([k]) => !hideFields.includes(k));\n const extraLines = [\n ...getNicifiedObjectExtraLines(value),\n ...hideFields.length > 0 ? [`<some fields may have been hidden>`] : [],\n ];\n const resValueLength = entries.length + extraLines.length;\n if (resValueLength === 0) return `${constructorString}{}`;\n if (maxDepth <= 0) return `${constructorString}{ ... }`;\n const resValues = entries.map(([k, v], keyIndex) => {\n const keyNicified = nestedNicify(k, `Object.keys(${path})[${keyIndex}]`, null);\n const keyInObjectLiteral = typeof k === \"string\" ? nicifyPropertyString(k) : `[${keyNicified}]`;\n if (typeof v === \"function\" && v.name === k) {\n return `${keyInObjectLiteral}(...): { ... }`;\n } else {\n return `${keyInObjectLiteral}: ${nestedNicify(v, `${path}[${keyNicified}]`, k)}`;\n }\n });\n resValues.push(...extraLines);\n if (resValues.length !== resValueLength) throw new StackAssertionError(\"nicify of object: resValues.length !== resValueLength\", { value, resValues, resValueLength });\n const shouldIndent = resValues.length > 1 || resValues.some(x => x.includes(\"\\n\"));\n\n if (resValues.length === 0) return `${constructorString}{}`;\n if (shouldIndent) {\n return `${constructorString}{${nl}${resValues.map(x => `${lineIndent}${x},${nl}`).join(\"\")}}`;\n } else {\n return `${constructorString}{ ${resValues.join(\", \")} }`;\n }\n }\n default: {\n return `${typeof value}<${value}>`;\n }\n }\n}\n\nexport function replaceAll(input: string, searchValue: string, replaceValue: string): string {\n if (searchValue === \"\") throw new StackAssertionError(\"replaceAll: searchValue is empty\");\n return input.split(searchValue).join(replaceValue);\n}\nundefined?.test(\"replaceAll\", ({ expect }) => {\n expect(replaceAll(\"hello world\", \"o\", \"x\")).toBe(\"hellx wxrld\");\n expect(replaceAll(\"aaa\", \"a\", \"b\")).toBe(\"bbb\");\n expect(replaceAll(\"\", \"a\", \"b\")).toBe(\"\");\n expect(replaceAll(\"abc\", \"b\", \"\")).toBe(\"ac\");\n expect(replaceAll(\"test.test.test\", \".\", \"_\")).toBe(\"test_test_test\");\n expect(replaceAll(\"a.b*c\", \".\", \"x\")).toBe(\"axb*c\");\n expect(replaceAll(\"a*b*c\", \"*\", \"x\")).toBe(\"axbxc\");\n expect(replaceAll(\"hello hello\", \"hello\", \"hi\")).toBe(\"hi hi\");\n});\n\nfunction nicifyPropertyString(str: string) {\n return JSON.stringify(str);\n}\nundefined?.test(\"nicifyPropertyString\", ({ expect }) => {\n // Test valid identifiers\n expect(nicifyPropertyString(\"validName\")).toBe('\"validName\"');\n expect(nicifyPropertyString(\"_validName\")).toBe('\"_validName\"');\n expect(nicifyPropertyString(\"valid123Name\")).toBe('\"valid123Name\"');\n\n // Test invalid identifiers\n expect(nicifyPropertyString(\"123invalid\")).toBe('\"123invalid\"');\n expect(nicifyPropertyString(\"invalid-name\")).toBe('\"invalid-name\"');\n expect(nicifyPropertyString(\"invalid space\")).toBe('\"invalid space\"');\n expect(nicifyPropertyString(\"$invalid\")).toBe('\"$invalid\"');\n expect(nicifyPropertyString(\"\")).toBe('\"\"');\n\n // Test with special characters\n expect(nicifyPropertyString(\"property!\")).toBe('\"property!\"');\n expect(nicifyPropertyString(\"property.name\")).toBe('\"property.name\"');\n\n // Test with escaped characters\n expect(nicifyPropertyString(\"\\\\\")).toBe('\"\\\\\\\\\"');\n expect(nicifyPropertyString('\"')).toBe('\"\\\\\"\"');\n});\n\nfunction getNicifiableKeys(value: Nicifiable | object) {\n const overridden = (\"getNicifiableKeys\" in value ? value.getNicifiableKeys?.bind(value) : null)?.();\n if (overridden != null) return overridden;\n if (value instanceof Response) {\n return ['status', 'headers'];\n }\n const keys = Object.keys(value).sort();\n return unique(keys);\n}\nundefined?.test(\"getNicifiableKeys\", ({ expect }) => {\n // Test regular object\n expect(getNicifiableKeys({ b: 1, a: 2, c: 3 })).toEqual([\"a\", \"b\", \"c\"]);\n\n // Test empty object\n expect(getNicifiableKeys({})).toEqual([]);\n\n\n expect(getNicifiableKeys(new Response())).toEqual([\"status\", \"headers\"]);\n\n // Test object with custom getNicifiableKeys\n const customObject = {\n a: 1,\n b: 2,\n getNicifiableKeys() {\n return [\"customKey1\", \"customKey2\"];\n }\n };\n expect(getNicifiableKeys(customObject)).toEqual([\"customKey1\", \"customKey2\"]);\n});\n\nfunction getNicifiableEntries(value: Nicifiable | object): [PropertyKey, unknown][] {\n const recordLikes = [Headers];\n function isRecordLike(value: unknown): value is InstanceType<typeof recordLikes[number]> {\n return recordLikes.some(x => value instanceof x);\n }\n\n if (isRecordLike(value)) {\n return [...value.entries()].sort(([a], [b]) => stringCompare(`${a}`, `${b}`));\n }\n const keys = getNicifiableKeys(value);\n return keys.map((k) => [k, value[k as never]] as [PropertyKey, unknown]);\n}\n\nfunction getNicifiedObjectExtraLines(value: Nicifiable | object) {\n return (\"getNicifiedObjectExtraLines\" in value ? value.getNicifiedObjectExtraLines : null)?.() ?? [];\n}\n"],"mappings":"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","names":["a","b","scope","options","extraLines","resValueLength","resValues","shouldIndent","value"]}
1
+ {"version":3,"sources":["../../../src/utils/strings.tsx"],"sourcesContent":["import { findLastIndex, unique } from \"./arrays\";\nimport { StackAssertionError } from \"./errors\";\nimport { filterUndefined } from \"./objects\";\n\nexport type Join<T extends string[], Separator extends string> =\n T extends [] ? \"\"\n : T extends [infer U extends string, ...infer Rest extends string[]]\n ? `${U}${Rest extends [any, ...any[]] ? `${Separator}${Join<Rest, Separator>}` : \"\"}`\n : \"<error-joining-strings>\";\n\nexport function typedJoin<T extends string[], Separator extends string>(strings: T, separator: Separator): Join<T, Separator> {\n return strings.join(separator) as Join<T, Separator>;\n}\n\nexport function typedToLowercase<S extends string>(s: S): Lowercase<S> {\n if (typeof s !== \"string\") throw new StackAssertionError(\"Expected a string for typedToLowercase\", { s });\n return s.toLowerCase() as Lowercase<S>;\n}\nundefined?.test(\"typedToLowercase\", ({ expect }) => {\n expect(typedToLowercase(\"\")).toBe(\"\");\n expect(typedToLowercase(\"HELLO\")).toBe(\"hello\");\n expect(typedToLowercase(\"Hello World\")).toBe(\"hello world\");\n expect(typedToLowercase(\"hello\")).toBe(\"hello\");\n expect(typedToLowercase(\"123\")).toBe(\"123\");\n expect(typedToLowercase(\"MIXED123case\")).toBe(\"mixed123case\");\n expect(typedToLowercase(\"Special@Chars!\")).toBe(\"special@chars!\");\n expect(() => typedToLowercase(123 as any)).toThrow(\"Expected a string for typedToLowercase\");\n});\n\nexport function typedToUppercase<S extends string>(s: S): Uppercase<S> {\n if (typeof s !== \"string\") throw new StackAssertionError(\"Expected a string for typedToUppercase\", { s });\n return s.toUpperCase() as Uppercase<S>;\n}\nundefined?.test(\"typedToUppercase\", ({ expect }) => {\n expect(typedToUppercase(\"\")).toBe(\"\");\n expect(typedToUppercase(\"hello\")).toBe(\"HELLO\");\n expect(typedToUppercase(\"Hello World\")).toBe(\"HELLO WORLD\");\n expect(typedToUppercase(\"HELLO\")).toBe(\"HELLO\");\n expect(typedToUppercase(\"123\")).toBe(\"123\");\n expect(typedToUppercase(\"mixed123Case\")).toBe(\"MIXED123CASE\");\n expect(typedToUppercase(\"special@chars!\")).toBe(\"SPECIAL@CHARS!\");\n expect(() => typedToUppercase(123 as any)).toThrow(\"Expected a string for typedToUppercase\");\n});\n\nexport function typedCapitalize<S extends string>(s: S): Capitalize<S> {\n return s.charAt(0).toUpperCase() + s.slice(1) as Capitalize<S>;\n}\nundefined?.test(\"typedCapitalize\", ({ expect }) => {\n expect(typedCapitalize(\"\")).toBe(\"\");\n expect(typedCapitalize(\"hello\")).toBe(\"Hello\");\n expect(typedCapitalize(\"hello world\")).toBe(\"Hello world\");\n expect(typedCapitalize(\"HELLO\")).toBe(\"HELLO\");\n expect(typedCapitalize(\"123test\")).toBe(\"123test\");\n expect(typedCapitalize(\"already Capitalized\")).toBe(\"Already Capitalized\");\n expect(typedCapitalize(\"h\")).toBe(\"H\");\n});\n\n/**\n * Compares two strings in a way that is not dependent on the current locale.\n */\nexport function stringCompare(a: string, b: string): number {\n if (typeof a !== \"string\" || typeof b !== \"string\") throw new StackAssertionError(`Expected two strings for stringCompare, found ${typeof a} and ${typeof b}`, { a, b });\n const cmp = (a: string, b: string) => a < b ? -1 : a > b ? 1 : 0;\n return cmp(a.toUpperCase(), b.toUpperCase()) || cmp(b, a);\n}\nundefined?.test(\"stringCompare\", ({ expect }) => {\n // Equal strings\n expect(stringCompare(\"a\", \"a\")).toBe(0);\n expect(stringCompare(\"\", \"\")).toBe(0);\n\n // Case comparison - note that this function is NOT case-insensitive\n // It compares uppercase versions first, then original strings\n expect(stringCompare(\"a\", \"A\")).toBe(-1); // lowercase comes after uppercase\n expect(stringCompare(\"A\", \"a\")).toBe(1); // uppercase comes before lowercase\n expect(stringCompare(\"abc\", \"ABC\")).toBe(-1);\n expect(stringCompare(\"ABC\", \"abc\")).toBe(1);\n\n // Different strings\n expect(stringCompare(\"a\", \"b\")).toBe(-1);\n expect(stringCompare(\"b\", \"a\")).toBe(1);\n\n // Strings with different lengths\n expect(stringCompare(\"abc\", \"abcd\")).toBe(-1);\n expect(stringCompare(\"abcd\", \"abc\")).toBe(1);\n\n // Strings with numbers\n expect(stringCompare(\"a1\", \"a2\")).toBe(-1);\n expect(stringCompare(\"a10\", \"a2\")).toBe(-1);\n\n // Strings with special characters\n expect(stringCompare(\"a\", \"a!\")).toBe(-1);\n expect(stringCompare(\"a!\", \"a\")).toBe(1);\n});\n\n/**\n * Returns all whitespace character at the start of the string.\n *\n * Uses the same definition for whitespace as `String.prototype.trim()`.\n */\nexport function getWhitespacePrefix(s: string): string {\n return s.substring(0, s.length - s.trimStart().length);\n}\nundefined?.test(\"getWhitespacePrefix\", ({ expect }) => {\n expect(getWhitespacePrefix(\"\")).toBe(\"\");\n expect(getWhitespacePrefix(\"hello\")).toBe(\"\");\n expect(getWhitespacePrefix(\" hello\")).toBe(\" \");\n expect(getWhitespacePrefix(\" hello\")).toBe(\" \");\n expect(getWhitespacePrefix(\"\\thello\")).toBe(\"\\t\");\n expect(getWhitespacePrefix(\"\\n hello\")).toBe(\"\\n \");\n expect(getWhitespacePrefix(\" \")).toBe(\" \");\n expect(getWhitespacePrefix(\" \\t\\n\\r\")).toBe(\" \\t\\n\\r\");\n});\n\n/**\n * Returns all whitespace character at the end of the string.\n *\n * Uses the same definition for whitespace as `String.prototype.trim()`.\n */\nexport function getWhitespaceSuffix(s: string): string {\n return s.substring(s.trimEnd().length);\n}\nundefined?.test(\"getWhitespaceSuffix\", ({ expect }) => {\n expect(getWhitespaceSuffix(\"\")).toBe(\"\");\n expect(getWhitespaceSuffix(\"hello\")).toBe(\"\");\n expect(getWhitespaceSuffix(\"hello \")).toBe(\" \");\n expect(getWhitespaceSuffix(\"hello \")).toBe(\" \");\n expect(getWhitespaceSuffix(\"hello\\t\")).toBe(\"\\t\");\n expect(getWhitespaceSuffix(\"hello \\n\")).toBe(\" \\n\");\n expect(getWhitespaceSuffix(\" \")).toBe(\" \");\n expect(getWhitespaceSuffix(\" \\t\\n\\r\")).toBe(\" \\t\\n\\r\");\n});\n\n/**\n * Returns a string with all empty or whitespace-only lines at the start removed.\n *\n * Uses the same definition for whitespace as `String.prototype.trim()`.\n */\nexport function trimEmptyLinesStart(s: string): string {\n const lines = s.split(\"\\n\");\n const firstNonEmptyLineIndex = lines.findIndex((line) => line.trim() !== \"\");\n // If all lines are empty or whitespace-only, return an empty string\n if (firstNonEmptyLineIndex === -1) return \"\";\n return lines.slice(firstNonEmptyLineIndex).join(\"\\n\");\n}\nundefined?.test(\"trimEmptyLinesStart\", ({ expect }) => {\n expect(trimEmptyLinesStart(\"\")).toBe(\"\");\n expect(trimEmptyLinesStart(\"hello\")).toBe(\"hello\");\n expect(trimEmptyLinesStart(\"\\nhello\")).toBe(\"hello\");\n expect(trimEmptyLinesStart(\"\\n\\nhello\")).toBe(\"hello\");\n expect(trimEmptyLinesStart(\" \\n\\t\\nhello\")).toBe(\"hello\");\n expect(trimEmptyLinesStart(\"\\n\\nhello\\nworld\")).toBe(\"hello\\nworld\");\n expect(trimEmptyLinesStart(\"hello\\n\\nworld\")).toBe(\"hello\\n\\nworld\");\n expect(trimEmptyLinesStart(\"hello\\nworld\\n\")).toBe(\"hello\\nworld\\n\");\n expect(trimEmptyLinesStart(\"\\n \\n\\nhello\\n \\nworld\")).toBe(\"hello\\n \\nworld\");\n // Edge case: all lines are empty\n expect(trimEmptyLinesStart(\"\\n\\n \\n\\t\")).toBe(\"\");\n});\n\n/**\n * Returns a string with all empty or whitespace-only lines at the end removed.\n *\n * Uses the same definition for whitespace as `String.prototype.trim()`.\n */\nexport function trimEmptyLinesEnd(s: string): string {\n const lines = s.split(\"\\n\");\n const lastNonEmptyLineIndex = findLastIndex(lines, (line) => line.trim() !== \"\");\n return lines.slice(0, lastNonEmptyLineIndex + 1).join(\"\\n\");\n}\nundefined?.test(\"trimEmptyLinesEnd\", ({ expect }) => {\n expect(trimEmptyLinesEnd(\"\")).toBe(\"\");\n expect(trimEmptyLinesEnd(\"hello\")).toBe(\"hello\");\n expect(trimEmptyLinesEnd(\"hello\\n\")).toBe(\"hello\");\n expect(trimEmptyLinesEnd(\"hello\\n\\n\")).toBe(\"hello\");\n expect(trimEmptyLinesEnd(\"hello\\n \\n\\t\")).toBe(\"hello\");\n expect(trimEmptyLinesEnd(\"hello\\nworld\\n\\n\")).toBe(\"hello\\nworld\");\n expect(trimEmptyLinesEnd(\"hello\\n\\nworld\")).toBe(\"hello\\n\\nworld\");\n expect(trimEmptyLinesEnd(\"\\nhello\\nworld\")).toBe(\"\\nhello\\nworld\");\n expect(trimEmptyLinesEnd(\"hello\\n \\nworld\\n\\n \")).toBe(\"hello\\n \\nworld\");\n // Edge case: all lines are empty\n expect(trimEmptyLinesEnd(\"\\n\\n \\n\\t\")).toBe(\"\");\n});\n\n/**\n * Returns a string with all empty or whitespace-only lines trimmed at the start and end.\n *\n * Uses the same definition for whitespace as `String.prototype.trim()`.\n */\nexport function trimLines(s: string): string {\n return trimEmptyLinesEnd(trimEmptyLinesStart(s));\n}\nundefined?.test(\"trimLines\", ({ expect }) => {\n expect(trimLines(\"\")).toBe(\"\");\n expect(trimLines(\" \")).toBe(\"\");\n expect(trimLines(\" \\n \")).toBe(\"\");\n expect(trimLines(\" abc \")).toBe(\" abc \");\n expect(trimLines(\"\\n \\nLine1\\nLine2\\n \\n\")).toBe(\"Line1\\nLine2\");\n expect(trimLines(\"Line1\\n \\nLine2\")).toBe(\"Line1\\n \\nLine2\");\n expect(trimLines(\" \\n \\n\\t\")).toBe(\"\");\n expect(trimLines(\" Hello World\")).toBe(\" Hello World\");\n expect(trimLines(\"\\n\")).toBe(\"\");\n expect(trimLines(\"\\t \\n\\t\\tLine1 \\n \\nLine2\\t\\t\\n\\t \")).toBe(\"\\t\\tLine1 \\n \\nLine2\\t\\t\");\n});\n\n\n/**\n * A template literal tag that returns the same string as the template literal without a tag.\n *\n * Useful for implementing your own template literal tags.\n */\nexport function templateIdentity(strings: TemplateStringsArray | readonly string[], ...values: string[]): string {\n if (values.length !== strings.length - 1) throw new StackAssertionError(\"Invalid number of values; must be one less than strings\", { strings, values });\n\n return strings.reduce((result, str, i) => result + str + (values[i] ?? ''), '');\n}\nundefined?.test(\"templateIdentity\", ({ expect }) => {\n expect(templateIdentity`Hello World`).toBe(\"Hello World\");\n expect(templateIdentity`${\"Hello\"}`).toBe(\"Hello\");\n const greeting = \"Hello\";\n const subject = \"World\";\n expect(templateIdentity`${greeting}, ${subject}!`).toBe(\"Hello, World!\");\n expect(templateIdentity`${\"A\"}${\"B\"}${\"C\"}`).toBe(\"ABC\");\n expect(templateIdentity`Start${\"\"}Middle${\"\"}End`).toBe(\"StartMiddleEnd\");\n expect(templateIdentity``).toBe(\"\");\n expect(templateIdentity`Line1\nLine2`).toBe(\"Line1\\nLine2\");\n expect(templateIdentity([\"a \", \" scientific \", \"gun\"], \"certain\", \"rail\")).toBe(\"a certain scientific railgun\");\n expect(templateIdentity([\"only one part\"])).toBe(\"only one part\");\n expect(() => templateIdentity([\"a \", \"b\", \"c\"], \"only one\")).toThrow(\"Invalid number of values\");\n expect(() => templateIdentity([\"a\", \"b\"], \"x\", \"y\")).toThrow(\"Invalid number of values\");\n});\n\n\nexport function deindent(code: string): string;\nexport function deindent(strings: TemplateStringsArray | readonly string[], ...values: any[]): string;\nexport function deindent(strings: string | readonly string[], ...values: any[]): string {\n if (typeof strings === \"string\") return deindent([strings]);\n return templateIdentity(...deindentTemplate(strings, ...values));\n}\n\nexport function deindentTemplate(strings: TemplateStringsArray | readonly string[], ...values: any[]): [string[], ...string[]] {\n if (values.length !== strings.length - 1) throw new StackAssertionError(\"Invalid number of values; must be one less than strings\", { strings, values });\n\n const trimmedStrings = [...strings];\n trimmedStrings[0] = trimEmptyLinesStart(trimmedStrings[0] + \"+\").slice(0, -1);\n trimmedStrings[trimmedStrings.length - 1] = trimEmptyLinesEnd(\"+\" + trimmedStrings[trimmedStrings.length - 1]).slice(1);\n\n const indentation = trimmedStrings\n .join(\"${SOME_VALUE}\")\n .split(\"\\n\")\n .filter((line) => line.trim() !== \"\")\n .map((line) => getWhitespacePrefix(line).length)\n .reduce((min, current) => Math.min(min, current), Infinity);\n\n const deindentedStrings = trimmedStrings\n .map((string, stringIndex) => {\n return string\n .split(\"\\n\")\n .map((line, lineIndex) => stringIndex !== 0 && lineIndex === 0 ? line : line.substring(indentation))\n .join(\"\\n\");\n });\n\n const indentedValues = values.map((value, i) => {\n const firstLineIndentation = getWhitespacePrefix(deindentedStrings[i].split(\"\\n\").at(-1)!);\n return `${value}`.replaceAll(\"\\n\", `\\n${firstLineIndentation}`);\n });\n\n return [deindentedStrings, ...indentedValues];\n}\nundefined?.test(\"deindent\", ({ expect }) => {\n // Test with string input\n expect(deindent(\" hello\")).toBe(\"hello\");\n expect(deindent(\" hello\\n world\")).toBe(\"hello\\nworld\");\n expect(deindent(\" hello\\n world\")).toBe(\"hello\\n world\");\n expect(deindent(\"\\n hello\\n world\\n\")).toBe(\"hello\\nworld\");\n\n // Test with empty input\n expect(deindent(\"\")).toBe(\"\");\n\n // Test with template literal\n expect(deindent`\n hello\n world\n `).toBe(\"hello\\nworld\");\n\n expect(deindent`\n hello\n world\n `).toBe(\"hello\\n world\");\n\n // Test with values\n const value = \"test\";\n expect(deindent`\n hello ${value}\n world\n `).toBe(`hello ${value}\\nworld`);\n\n // Test with multiline values\n expect(deindent`\n hello\n to ${\"line1\\n line2\"}\n world\n `).toBe(`hello\\n to line1\\n line2\\nworld`);\n\n // Leading whitespace values\n expect(deindent`\n ${\" \"}A\n ${\" \"}B\n ${\" \"}C\n `).toBe(` A\\n B\\n C`);\n\n // Trailing whitespaces (note: there are two whitespaces each after A and after C)\n expect(deindent`\n A \n B ${\" \"}\n C \n `).toBe(`A \\nB \\nC `);\n\n // Test with mixed indentation\n expect(deindent`\n hello\n world\n !\n `).toBe(\"hello\\n world\\n !\");\n\n // Test error cases\n expect(() => deindent([\"a\", \"b\", \"c\"], \"too\", \"many\", \"values\")).toThrow(\"Invalid number of values\");\n});\n\nexport function extractScopes(scope: string, removeDuplicates=true): string[] {\n // TODO what is this for? can we move this into the OAuth code in the backend?\n const trimmedString = scope.trim();\n const scopesArray = trimmedString.split(/\\s+/);\n const filtered = scopesArray.filter(scope => scope.length > 0);\n return removeDuplicates ? [...new Set(filtered)] : filtered;\n}\nundefined?.test(\"extractScopes\", ({ expect }) => {\n // Test with empty string\n expect(extractScopes(\"\")).toEqual([]);\n\n // Test with single scope\n expect(extractScopes(\"read\")).toEqual([\"read\"]);\n\n // Test with multiple scopes\n expect(extractScopes(\"read write\")).toEqual([\"read\", \"write\"]);\n\n // Test with extra whitespace\n expect(extractScopes(\" read write \")).toEqual([\"read\", \"write\"]);\n\n // Test with newlines and tabs\n expect(extractScopes(\"read\\nwrite\\tdelete\")).toEqual([\"read\", \"write\", \"delete\"]);\n\n // Test with duplicates (default behavior)\n expect(extractScopes(\"read write read\")).toEqual([\"read\", \"write\"]);\n\n // Test with duplicates (explicitly set to remove)\n expect(extractScopes(\"read write read\", true)).toEqual([\"read\", \"write\"]);\n\n // Test with duplicates (explicitly set to keep)\n expect(extractScopes(\"read write read\", false)).toEqual([\"read\", \"write\", \"read\"]);\n});\n\nexport function mergeScopeStrings(...scopes: string[]): string {\n // TODO what is this for? can we move this into the OAuth code in the backend?\n const allScope = scopes.map((s) => extractScopes(s)).flat().join(\" \");\n return extractScopes(allScope).join(\" \");\n}\nundefined?.test(\"mergeScopeStrings\", ({ expect }) => {\n // Test with empty input\n expect(mergeScopeStrings()).toBe(\"\");\n\n // Test with single scope string\n expect(mergeScopeStrings(\"read write\")).toBe(\"read write\");\n\n // Test with multiple scope strings\n expect(mergeScopeStrings(\"read\", \"write\")).toBe(\"read write\");\n\n // Test with overlapping scopes\n expect(mergeScopeStrings(\"read write\", \"write delete\")).toBe(\"read write delete\");\n\n // Test with extra whitespace\n expect(mergeScopeStrings(\" read write \", \" delete \")).toBe(\"read write delete\");\n\n // Test with duplicates across strings\n expect(mergeScopeStrings(\"read write\", \"write delete\", \"read\")).toBe(\"read write delete\");\n\n // Test with empty strings\n expect(mergeScopeStrings(\"read write\", \"\", \"delete\")).toBe(\"read write delete\");\n});\n\nexport function escapeTemplateLiteral(s: string): string {\n return s.replaceAll(\"`\", \"\\\\`\").replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll(\"$\", \"\\\\$\");\n}\nundefined?.test(\"escapeTemplateLiteral\", ({ expect }) => {\n // Test with empty string\n expect(escapeTemplateLiteral(\"\")).toBe(\"\");\n\n // Test with normal string (no special characters)\n expect(escapeTemplateLiteral(\"hello world\")).toBe(\"hello world\");\n\n // Test with backtick\n const input1 = \"hello `world`\";\n const output1 = escapeTemplateLiteral(input1);\n // Verify backticks are escaped\n expect(output1.includes(\"\\\\`\")).toBe(true);\n expect(output1).not.toBe(input1);\n\n // Test with backslash\n const input2 = \"hello \\\\world\";\n const output2 = escapeTemplateLiteral(input2);\n // Verify backslashes are escaped\n expect(output2.includes(\"\\\\\\\\\")).toBe(true);\n expect(output2).not.toBe(input2);\n\n // Test with dollar sign\n const input3 = \"hello $world\";\n const output3 = escapeTemplateLiteral(input3);\n // Verify dollar signs are escaped\n expect(output3.includes(\"\\\\$\")).toBe(true);\n expect(output3).not.toBe(input3);\n\n // Test with multiple special characters\n const input4 = \"`hello` $world\\\\\";\n const output4 = escapeTemplateLiteral(input4);\n // Verify all special characters are escaped\n expect(output4.includes(\"\\\\`\")).toBe(true);\n expect(output4.includes(\"\\\\$\")).toBe(true);\n expect(output4.includes(\"\\\\\\\\\")).toBe(true);\n expect(output4).not.toBe(input4);\n\n // Test with already escaped characters\n const input5 = \"\\\\`hello\\\\`\";\n const output5 = escapeTemplateLiteral(input5);\n // Verify already escaped characters are properly escaped\n expect(output5).not.toBe(input5);\n});\n\n/**\n * Some classes have different constructor names in different environments (eg. `Headers` is sometimes called `_Headers`,\n * so we create an object of overrides to handle these cases.\n */\nconst nicifiableClassNameOverrides = new Map(Object.entries({\n Headers,\n} as Record<string, unknown>).map(([k, v]) => [v, k]));\nexport type Nicifiable = {\n getNicifiableKeys?(): PropertyKey[],\n getNicifiedObjectExtraLines?(): string[],\n};\nexport type NicifyOptions = {\n maxDepth: number,\n currentIndent: string,\n lineIndent: string,\n multiline: boolean,\n refs: Map<unknown, string>,\n path: string,\n parent: null | {\n options: NicifyOptions,\n value: unknown,\n },\n keyInParent: PropertyKey | null,\n hideFields: PropertyKey[],\n overrides: (...args: Parameters<typeof nicify>) => string | null,\n};\nexport function nicify(\n value: unknown,\n options: Partial<NicifyOptions> = {},\n): string {\n const fullOptions: NicifyOptions = {\n maxDepth: 5,\n currentIndent: \"\",\n lineIndent: \" \",\n multiline: true,\n refs: new Map(),\n path: \"value\",\n parent: null,\n overrides: () => null,\n keyInParent: null,\n hideFields: [],\n ...filterUndefined(options),\n };\n const {\n maxDepth,\n currentIndent,\n lineIndent,\n multiline,\n refs,\n path,\n overrides,\n hideFields,\n } = fullOptions;\n const nl = `\\n${currentIndent}`;\n\n const overrideResult = overrides(value, options);\n if (overrideResult !== null) return overrideResult;\n\n if ([\"function\", \"object\", \"symbol\"].includes(typeof value) && value !== null) {\n if (refs.has(value)) {\n return `Ref<${refs.get(value)}>`;\n }\n refs.set(value, path);\n }\n\n const newOptions: NicifyOptions = {\n maxDepth: maxDepth - 1,\n currentIndent,\n lineIndent,\n multiline,\n refs,\n path: path + \"->[unknown property]\",\n overrides,\n parent: { value, options: fullOptions },\n keyInParent: null,\n hideFields: [],\n };\n const nestedNicify = (newValue: unknown, newPath: string, keyInParent: PropertyKey | null, options: Partial<NicifyOptions> = {}) => {\n return nicify(newValue, {\n ...newOptions,\n path: newPath,\n currentIndent: currentIndent + lineIndent,\n keyInParent,\n ...options,\n });\n };\n\n switch (typeof value) {\n case \"boolean\": case \"number\": {\n return JSON.stringify(value);\n }\n case \"string\": {\n const isDeindentable = (v: string) => deindent(v) === v && v.includes(\"\\n\");\n const wrapInDeindent = (v: string) => deindent`\n deindent\\`\n ${currentIndent + lineIndent}${escapeTemplateLiteral(v).replaceAll(\"\\n\", nl + lineIndent)}\n ${currentIndent}\\`\n `;\n if (isDeindentable(value)) {\n return wrapInDeindent(value);\n } else if (value.endsWith(\"\\n\") && isDeindentable(value.slice(0, -1))) {\n return wrapInDeindent(value.slice(0, -1)) + ' + \"\\\\n\"';\n } else {\n return JSON.stringify(value);\n }\n }\n case \"undefined\": {\n return \"undefined\";\n }\n case \"symbol\": {\n return value.toString();\n }\n case \"bigint\": {\n return `${value}n`;\n }\n case \"function\": {\n if (value.name) return `function ${value.name}(...) { ... }`;\n return `(...) => { ... }`;\n }\n case \"object\": {\n if (value === null) return \"null\";\n if (Array.isArray(value)) {\n const extraLines = getNicifiedObjectExtraLines(value);\n const resValueLength = value.length + extraLines.length;\n if (maxDepth <= 0 && resValueLength === 0) return \"[...]\";\n const resValues = value.map((v, i) => nestedNicify(v, `${path}[${i}]`, i));\n resValues.push(...extraLines);\n if (resValues.length !== resValueLength) throw new StackAssertionError(\"nicify of object: resValues.length !== resValueLength\", { value, resValues, resValueLength });\n const shouldIndent = resValues.length > 4 || resValues.some(x => (resValues.length > 1 && x.length > 4) || x.includes(\"\\n\"));\n if (shouldIndent) {\n return `[${nl}${resValues.map(x => `${lineIndent}${x},${nl}`).join(\"\")}]`;\n } else {\n return `[${resValues.join(\", \")}]`;\n }\n }\n if (value instanceof URL) {\n return `URL(${nestedNicify(value.toString(), `${path}.toString()`, null)})`;\n }\n if (ArrayBuffer.isView(value)) {\n return `${value.constructor.name}([${value.toString()}])`;\n }\n if (value instanceof Error) {\n let stack = value.stack ?? \"\";\n const toString = value.toString();\n if (!stack.startsWith(toString)) stack = `${toString}\\n${stack}`; // some browsers don't include the error message in the stack, some do\n stack = stack.trimEnd();\n stack = stack.replace(/\\n\\s+/g, `\\n${lineIndent}${lineIndent}`);\n stack = stack.replace(\"\\n\", `\\n${lineIndent}Stack:\\n`);\n if (Object.keys(value).length > 0) {\n stack += `\\n${lineIndent}Extra properties: ${nestedNicify(Object.fromEntries(Object.entries(value)), path, null)}`;\n }\n if (value.cause) {\n stack += `\\n${lineIndent}Cause:\\n${lineIndent}${lineIndent}${nestedNicify(value.cause, path, null, { currentIndent: currentIndent + lineIndent + lineIndent })}`;\n }\n stack = stack.replaceAll(\"\\n\", `\\n${currentIndent}`);\n return stack;\n }\n\n const constructorName = [null, Object.prototype].includes(Object.getPrototypeOf(value)) ? null : (nicifiableClassNameOverrides.get(value.constructor) ?? value.constructor.name);\n const constructorString = constructorName ? `${constructorName} ` : \"\";\n\n const entries = getNicifiableEntries(value).filter(([k]) => !hideFields.includes(k));\n const extraLines = [\n ...getNicifiedObjectExtraLines(value),\n ...hideFields.length > 0 ? [`<some fields may have been hidden>`] : [],\n ];\n const resValueLength = entries.length + extraLines.length;\n if (resValueLength === 0) return `${constructorString}{}`;\n if (maxDepth <= 0) return `${constructorString}{ ... }`;\n const resValues = entries.map(([k, v], keyIndex) => {\n const keyNicified = nestedNicify(k, `Object.keys(${path})[${keyIndex}]`, null);\n const keyInObjectLiteral = typeof k === \"string\" ? nicifyPropertyString(k) : `[${keyNicified}]`;\n if (typeof v === \"function\" && v.name === k) {\n return `${keyInObjectLiteral}(...): { ... }`;\n } else {\n return `${keyInObjectLiteral}: ${nestedNicify(v, `${path}[${keyNicified}]`, k)}`;\n }\n });\n resValues.push(...extraLines);\n if (resValues.length !== resValueLength) throw new StackAssertionError(\"nicify of object: resValues.length !== resValueLength\", { value, resValues, resValueLength });\n const shouldIndent = resValues.length > 1 || resValues.some(x => x.includes(\"\\n\"));\n\n if (resValues.length === 0) return `${constructorString}{}`;\n if (shouldIndent) {\n return `${constructorString}{${nl}${resValues.map(x => `${lineIndent}${x},${nl}`).join(\"\")}}`;\n } else {\n return `${constructorString}{ ${resValues.join(\", \")} }`;\n }\n }\n default: {\n return `${typeof value}<${value}>`;\n }\n }\n}\n\nexport function replaceAll(input: string, searchValue: string, replaceValue: string): string {\n if (searchValue === \"\") throw new StackAssertionError(\"replaceAll: searchValue is empty\");\n return input.split(searchValue).join(replaceValue);\n}\nundefined?.test(\"replaceAll\", ({ expect }) => {\n expect(replaceAll(\"hello world\", \"o\", \"x\")).toBe(\"hellx wxrld\");\n expect(replaceAll(\"aaa\", \"a\", \"b\")).toBe(\"bbb\");\n expect(replaceAll(\"\", \"a\", \"b\")).toBe(\"\");\n expect(replaceAll(\"abc\", \"b\", \"\")).toBe(\"ac\");\n expect(replaceAll(\"test.test.test\", \".\", \"_\")).toBe(\"test_test_test\");\n expect(replaceAll(\"a.b*c\", \".\", \"x\")).toBe(\"axb*c\");\n expect(replaceAll(\"a*b*c\", \"*\", \"x\")).toBe(\"axbxc\");\n expect(replaceAll(\"hello hello\", \"hello\", \"hi\")).toBe(\"hi hi\");\n});\n\nfunction nicifyPropertyString(str: string) {\n return JSON.stringify(str);\n}\nundefined?.test(\"nicifyPropertyString\", ({ expect }) => {\n // Test valid identifiers\n expect(nicifyPropertyString(\"validName\")).toBe('\"validName\"');\n expect(nicifyPropertyString(\"_validName\")).toBe('\"_validName\"');\n expect(nicifyPropertyString(\"valid123Name\")).toBe('\"valid123Name\"');\n\n // Test invalid identifiers\n expect(nicifyPropertyString(\"123invalid\")).toBe('\"123invalid\"');\n expect(nicifyPropertyString(\"invalid-name\")).toBe('\"invalid-name\"');\n expect(nicifyPropertyString(\"invalid space\")).toBe('\"invalid space\"');\n expect(nicifyPropertyString(\"$invalid\")).toBe('\"$invalid\"');\n expect(nicifyPropertyString(\"\")).toBe('\"\"');\n\n // Test with special characters\n expect(nicifyPropertyString(\"property!\")).toBe('\"property!\"');\n expect(nicifyPropertyString(\"property.name\")).toBe('\"property.name\"');\n\n // Test with escaped characters\n expect(nicifyPropertyString(\"\\\\\")).toBe('\"\\\\\\\\\"');\n expect(nicifyPropertyString('\"')).toBe('\"\\\\\"\"');\n});\n\nfunction getNicifiableKeys(value: Nicifiable | object) {\n const overridden = (\"getNicifiableKeys\" in value ? value.getNicifiableKeys?.bind(value) : null)?.();\n if (overridden != null) return overridden;\n if (value instanceof Response) {\n return ['status', 'headers'];\n }\n const keys = Object.keys(value).sort();\n return unique(keys);\n}\nundefined?.test(\"getNicifiableKeys\", ({ expect }) => {\n // Test regular object\n expect(getNicifiableKeys({ b: 1, a: 2, c: 3 })).toEqual([\"a\", \"b\", \"c\"]);\n\n // Test empty object\n expect(getNicifiableKeys({})).toEqual([]);\n\n\n expect(getNicifiableKeys(new Response())).toEqual([\"status\", \"headers\"]);\n\n // Test object with custom getNicifiableKeys\n const customObject = {\n a: 1,\n b: 2,\n getNicifiableKeys() {\n return [\"customKey1\", \"customKey2\"];\n }\n };\n expect(getNicifiableKeys(customObject)).toEqual([\"customKey1\", \"customKey2\"]);\n});\n\nfunction getNicifiableEntries(value: Nicifiable | object): [PropertyKey, unknown][] {\n const recordLikes = [Headers];\n function isRecordLike(value: unknown): value is InstanceType<typeof recordLikes[number]> {\n return recordLikes.some(x => value instanceof x);\n }\n\n if (isRecordLike(value)) {\n return [...value.entries()].sort(([a], [b]) => stringCompare(`${a}`, `${b}`));\n }\n const keys = getNicifiableKeys(value);\n return keys.map((k) => [k, value[k as never]] as [PropertyKey, unknown]);\n}\n\nfunction getNicifiedObjectExtraLines(value: Nicifiable | object) {\n return (\"getNicifiedObjectExtraLines\" in value ? value.getNicifiedObjectExtraLines : null)?.() ?? [];\n}\n"],"mappings":"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","names":["a","b","scope","options","extraLines","resValueLength","resValues","shouldIndent","value"]}