@stackframe/stack-shared 2.8.32 → 2.8.35
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.
- package/CHANGELOG.md +18 -0
- package/dist/config/schema.d.mts +184 -231
- package/dist/config/schema.d.ts +184 -231
- package/dist/config/schema.js +39 -31
- package/dist/config/schema.js.map +1 -1
- package/dist/esm/config/schema.js +39 -31
- package/dist/esm/config/schema.js.map +1 -1
- package/dist/esm/helpers/production-mode.js +2 -1
- package/dist/esm/helpers/production-mode.js.map +1 -1
- package/dist/esm/interface/admin-interface.js +28 -8
- package/dist/esm/interface/admin-interface.js.map +1 -1
- package/dist/esm/interface/client-interface.js +29 -12
- package/dist/esm/interface/client-interface.js.map +1 -1
- package/dist/esm/interface/crud/users.js +1 -1
- package/dist/esm/interface/crud/users.js.map +1 -1
- package/dist/esm/interface/server-interface.js +22 -10
- package/dist/esm/interface/server-interface.js.map +1 -1
- package/dist/esm/known-errors.js +10 -0
- package/dist/esm/known-errors.js.map +1 -1
- package/dist/esm/schema-fields.js +52 -9
- package/dist/esm/schema-fields.js.map +1 -1
- package/dist/esm/utils/currencies.js +0 -38
- package/dist/esm/utils/currencies.js.map +1 -1
- package/dist/esm/utils/currency-constants.js +42 -0
- package/dist/esm/utils/currency-constants.js.map +1 -0
- package/dist/esm/utils/dates.js +30 -0
- package/dist/esm/utils/dates.js.map +1 -1
- package/dist/esm/utils/jwt.js +42 -37
- package/dist/esm/utils/jwt.js.map +1 -1
- package/dist/esm/utils/strings.js +3 -0
- package/dist/esm/utils/strings.js.map +1 -1
- package/dist/esm/utils/types.js.map +1 -1
- package/dist/esm/utils/urls.js +54 -0
- package/dist/esm/utils/urls.js.map +1 -1
- package/dist/helpers/password.d.mts +1 -1
- package/dist/helpers/password.d.ts +1 -1
- package/dist/helpers/production-mode.js +2 -1
- package/dist/helpers/production-mode.js.map +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/interface/admin-interface.d.mts +15 -7
- package/dist/interface/admin-interface.d.ts +15 -7
- package/dist/interface/admin-interface.js +28 -8
- package/dist/interface/admin-interface.js.map +1 -1
- package/dist/interface/client-interface.d.mts +17 -16
- package/dist/interface/client-interface.d.ts +17 -16
- package/dist/interface/client-interface.js +29 -12
- package/dist/interface/client-interface.js.map +1 -1
- package/dist/interface/crud/current-user.d.mts +1 -1
- package/dist/interface/crud/current-user.d.ts +1 -1
- package/dist/interface/crud/project-api-keys.d.mts +4 -4
- package/dist/interface/crud/project-api-keys.d.ts +4 -4
- package/dist/interface/crud/team-member-profiles.d.mts +2 -2
- package/dist/interface/crud/team-member-profiles.d.ts +2 -2
- package/dist/interface/crud/users.d.mts +4 -4
- package/dist/interface/crud/users.d.ts +4 -4
- package/dist/interface/crud/users.js +1 -1
- package/dist/interface/crud/users.js.map +1 -1
- package/dist/interface/server-interface.d.mts +14 -4
- package/dist/interface/server-interface.d.ts +14 -4
- package/dist/interface/server-interface.js +22 -10
- package/dist/interface/server-interface.js.map +1 -1
- package/dist/known-errors.d.mts +6 -3
- package/dist/known-errors.d.ts +6 -3
- package/dist/known-errors.js +10 -0
- package/dist/known-errors.js.map +1 -1
- package/dist/schema-fields.d.mts +28 -8
- package/dist/schema-fields.d.ts +28 -8
- package/dist/schema-fields.js +56 -11
- package/dist/schema-fields.js.map +1 -1
- package/dist/utils/currencies.d.mts +3 -36
- package/dist/utils/currencies.d.ts +3 -36
- package/dist/utils/currencies.js +0 -39
- package/dist/utils/currencies.js.map +1 -1
- package/dist/utils/currency-constants.d.mts +37 -0
- package/dist/utils/currency-constants.d.ts +37 -0
- package/dist/utils/currency-constants.js +67 -0
- package/dist/utils/currency-constants.js.map +1 -0
- package/dist/utils/dates.d.mts +3 -1
- package/dist/utils/dates.d.ts +3 -1
- package/dist/utils/dates.js +32 -0
- package/dist/utils/dates.js.map +1 -1
- package/dist/utils/jwt.d.mts +11 -11
- package/dist/utils/jwt.d.ts +11 -11
- package/dist/utils/jwt.js +44 -42
- package/dist/utils/jwt.js.map +1 -1
- package/dist/utils/strings.js +3 -0
- package/dist/utils/strings.js.map +1 -1
- package/dist/utils/types.d.mts +16 -5
- package/dist/utils/types.d.ts +16 -5
- package/dist/utils/types.js.map +1 -1
- package/dist/utils/urls.d.mts +3 -1
- package/dist/utils/urls.d.ts +3 -1
- package/dist/utils/urls.js +56 -0
- package/dist/utils/urls.js.map +1 -1
- package/package.json +1 -1
|
@@ -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 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"]}
|
|
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 ArrayBuffer) {\n return `ArrayBuffer [${new Uint8Array(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"]}
|
package/dist/utils/types.d.mts
CHANGED
|
@@ -6,14 +6,15 @@ type IsNullish<T> = [T] extends [null | undefined] ? true : false;
|
|
|
6
6
|
type IsUnion<T, U = T> = IsNever<T> extends true ? false : IsAny<T> extends true ? false : T extends U ? ([U] extends [T] ? false : true) : never;
|
|
7
7
|
type NullishCoalesce<T, U> = T extends null | undefined ? U : T;
|
|
8
8
|
type LastUnionElement<U> = UnionToIntersection<U extends any ? (x: U) => 0 : never> extends (x: infer L) => 0 ? L & U : never;
|
|
9
|
+
type primitive = string | number | boolean | bigint | symbol | null | undefined;
|
|
9
10
|
/**
|
|
10
11
|
* Makes a type prettier by recursively expanding all object types. For example, `Omit<{ a: 1 }, "a">` becomes just `{}`.
|
|
11
12
|
*/
|
|
12
|
-
type Expand<T> = T extends (...args: infer A) => infer R ? ((
|
|
13
|
+
type Expand<T> = T extends (...args: infer A) => infer R ? ((...args: A) => R) extends T ? (...args: Expand<A>) => Expand<R> : ((...args: Expand<A>) => Expand<R>) & {
|
|
13
14
|
[K in keyof T]: Expand<T[K]>;
|
|
14
|
-
}
|
|
15
|
-
[K in keyof
|
|
16
|
-
} : T
|
|
15
|
+
} : T extends object ? T extends primitive ? T : T extends infer O ? {
|
|
16
|
+
[K in keyof O]: Expand<O[K]>;
|
|
17
|
+
} : never : T;
|
|
17
18
|
/**
|
|
18
19
|
* Removes all optional undefined/never keys from an object.
|
|
19
20
|
*/
|
|
@@ -33,6 +34,16 @@ type OptionalKeys<T> = {
|
|
|
33
34
|
type RequiredKeys<T> = {
|
|
34
35
|
[K in keyof T]: {} extends Pick<T, K> ? never : K;
|
|
35
36
|
}[keyof T];
|
|
37
|
+
/**
|
|
38
|
+
* Returns a type whose keys are the intersection of the keys of T and U, deeply.
|
|
39
|
+
*/
|
|
40
|
+
type KeyIntersect<T, U> = {
|
|
41
|
+
[K in keyof T & keyof U]?: T[K] & U[K];
|
|
42
|
+
} | {
|
|
43
|
+
[K in RequiredKeys<T> & keyof U]: T[K] & U[K];
|
|
44
|
+
} | {
|
|
45
|
+
[K in RequiredKeys<U> & keyof T]: U[K] & T[K];
|
|
46
|
+
};
|
|
36
47
|
/**
|
|
37
48
|
* Returns ALL keys of all union elements.
|
|
38
49
|
*/
|
|
@@ -92,4 +103,4 @@ declare function typeAssertExtends<T, S>(): ([
|
|
|
92
103
|
] extends [S] ? (() => undefined) : TypeAssertionError<`Type assertion failed. Expected ${TypeToString<T>} to extend ${TypeToString<S>}`>);
|
|
93
104
|
declare function typeAssertIs<T, U>(): (IsAny<T> extends true ? (IsAny<U> extends true ? (() => undefined) : TypeAssertionError<`Type assertion failed. Expected ${TypeToString<T>} to be ${TypeToString<U>}`>) : IsAny<U> extends true ? TypeAssertionError<`Type assertion failed. Expected ${TypeToString<T>} to be ${TypeToString<U>}`> : [T] extends [U] ? ([U] extends [T] ? (() => undefined) : TypeAssertionError<`Type assertion failed. Expected ${TypeToString<T>} to be ${TypeToString<U>}`>) : TypeAssertionError<`Type assertion failed. Expected ${TypeToString<T>} to be ${TypeToString<U>}`>);
|
|
94
105
|
|
|
95
|
-
export { type AllUnionKeys, type AntiIntersect, type CollapseObjectUnion, type DeepRemoveOptionalUndefined, type Expand, type IfAndOnlyIf, type IntersectAll, type IsAny, type IsNever, type IsNullish, type IsUnion, type LastUnionElement, type NullishCoalesce, type OptionalKeys, type PrettifyType, type PseudoAntiIntersect, type RequiredKeys, type SubtractType, type TypeToString, type UnionToIntersection, type UnionToTuple, typeAssert, typeAssertExtends, typeAssertIs };
|
|
106
|
+
export { type AllUnionKeys, type AntiIntersect, type CollapseObjectUnion, type DeepRemoveOptionalUndefined, type Expand, type IfAndOnlyIf, type IntersectAll, type IsAny, type IsNever, type IsNullish, type IsUnion, type KeyIntersect, type LastUnionElement, type NullishCoalesce, type OptionalKeys, type PrettifyType, type PseudoAntiIntersect, type RequiredKeys, type SubtractType, type TypeToString, type UnionToIntersection, type UnionToTuple, typeAssert, typeAssertExtends, typeAssertIs };
|
package/dist/utils/types.d.ts
CHANGED
|
@@ -6,14 +6,15 @@ type IsNullish<T> = [T] extends [null | undefined] ? true : false;
|
|
|
6
6
|
type IsUnion<T, U = T> = IsNever<T> extends true ? false : IsAny<T> extends true ? false : T extends U ? ([U] extends [T] ? false : true) : never;
|
|
7
7
|
type NullishCoalesce<T, U> = T extends null | undefined ? U : T;
|
|
8
8
|
type LastUnionElement<U> = UnionToIntersection<U extends any ? (x: U) => 0 : never> extends (x: infer L) => 0 ? L & U : never;
|
|
9
|
+
type primitive = string | number | boolean | bigint | symbol | null | undefined;
|
|
9
10
|
/**
|
|
10
11
|
* Makes a type prettier by recursively expanding all object types. For example, `Omit<{ a: 1 }, "a">` becomes just `{}`.
|
|
11
12
|
*/
|
|
12
|
-
type Expand<T> = T extends (...args: infer A) => infer R ? ((
|
|
13
|
+
type Expand<T> = T extends (...args: infer A) => infer R ? ((...args: A) => R) extends T ? (...args: Expand<A>) => Expand<R> : ((...args: Expand<A>) => Expand<R>) & {
|
|
13
14
|
[K in keyof T]: Expand<T[K]>;
|
|
14
|
-
}
|
|
15
|
-
[K in keyof
|
|
16
|
-
} : T
|
|
15
|
+
} : T extends object ? T extends primitive ? T : T extends infer O ? {
|
|
16
|
+
[K in keyof O]: Expand<O[K]>;
|
|
17
|
+
} : never : T;
|
|
17
18
|
/**
|
|
18
19
|
* Removes all optional undefined/never keys from an object.
|
|
19
20
|
*/
|
|
@@ -33,6 +34,16 @@ type OptionalKeys<T> = {
|
|
|
33
34
|
type RequiredKeys<T> = {
|
|
34
35
|
[K in keyof T]: {} extends Pick<T, K> ? never : K;
|
|
35
36
|
}[keyof T];
|
|
37
|
+
/**
|
|
38
|
+
* Returns a type whose keys are the intersection of the keys of T and U, deeply.
|
|
39
|
+
*/
|
|
40
|
+
type KeyIntersect<T, U> = {
|
|
41
|
+
[K in keyof T & keyof U]?: T[K] & U[K];
|
|
42
|
+
} | {
|
|
43
|
+
[K in RequiredKeys<T> & keyof U]: T[K] & U[K];
|
|
44
|
+
} | {
|
|
45
|
+
[K in RequiredKeys<U> & keyof T]: U[K] & T[K];
|
|
46
|
+
};
|
|
36
47
|
/**
|
|
37
48
|
* Returns ALL keys of all union elements.
|
|
38
49
|
*/
|
|
@@ -92,4 +103,4 @@ declare function typeAssertExtends<T, S>(): ([
|
|
|
92
103
|
] extends [S] ? (() => undefined) : TypeAssertionError<`Type assertion failed. Expected ${TypeToString<T>} to extend ${TypeToString<S>}`>);
|
|
93
104
|
declare function typeAssertIs<T, U>(): (IsAny<T> extends true ? (IsAny<U> extends true ? (() => undefined) : TypeAssertionError<`Type assertion failed. Expected ${TypeToString<T>} to be ${TypeToString<U>}`>) : IsAny<U> extends true ? TypeAssertionError<`Type assertion failed. Expected ${TypeToString<T>} to be ${TypeToString<U>}`> : [T] extends [U] ? ([U] extends [T] ? (() => undefined) : TypeAssertionError<`Type assertion failed. Expected ${TypeToString<T>} to be ${TypeToString<U>}`>) : TypeAssertionError<`Type assertion failed. Expected ${TypeToString<T>} to be ${TypeToString<U>}`>);
|
|
94
105
|
|
|
95
|
-
export { type AllUnionKeys, type AntiIntersect, type CollapseObjectUnion, type DeepRemoveOptionalUndefined, type Expand, type IfAndOnlyIf, type IntersectAll, type IsAny, type IsNever, type IsNullish, type IsUnion, type LastUnionElement, type NullishCoalesce, type OptionalKeys, type PrettifyType, type PseudoAntiIntersect, type RequiredKeys, type SubtractType, type TypeToString, type UnionToIntersection, type UnionToTuple, typeAssert, typeAssertExtends, typeAssertIs };
|
|
106
|
+
export { type AllUnionKeys, type AntiIntersect, type CollapseObjectUnion, type DeepRemoveOptionalUndefined, type Expand, type IfAndOnlyIf, type IntersectAll, type IsAny, type IsNever, type IsNullish, type IsUnion, type KeyIntersect, type LastUnionElement, type NullishCoalesce, type OptionalKeys, type PrettifyType, type PseudoAntiIntersect, type RequiredKeys, type SubtractType, type TypeToString, type UnionToIntersection, type UnionToTuple, typeAssert, typeAssertExtends, typeAssertIs };
|
package/dist/utils/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/types.tsx"],"sourcesContent":["import { DeepPartial } from \"./objects\";\nimport { Join } from \"./strings\";\n\nexport type IsAny<T> = 0 extends (1 & T) ? true : false;\nexport type IsNever<T> = [T] extends [never] ? true : false;\nexport type IsNullish<T> = [T] extends [null | undefined] ? true : false;\nexport type IsUnion<T, U = T> =\n IsNever<T> extends true ? false\n : IsAny<T> extends true ? false\n : T extends U // distributive conditional https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types\n ? /* if the *whole* original type (`U`) still fits inside the current variant, then `T` wasn’t a union */ ([U] extends [T] ? false : true)\n : never;\n\nexport type NullishCoalesce<T, U> = T extends null | undefined ? U : T;\n\nexport type LastUnionElement<U> = UnionToIntersection<U extends any ? (x: U) => 0 : never> extends (x: infer L) => 0 ? L & U : never;\n\n/**\n * Makes a type prettier by recursively expanding all object types. For example, `Omit<{ a: 1 }, \"a\">` becomes just `{}`.\n */\nexport type Expand<T> = T extends (...args: infer A) => infer R\n ? (\n ((...args: A) => R) extends T\n ? (...args: Expand<A>) => Expand<R>\n : ((...args: Expand<A>) => Expand<R>) & { [K in keyof T]: Expand<T[K]> }\n )\n : (\n T extends object\n ? { [K in keyof T]: Expand<T[K]> }\n : T\n );\n\n\n/**\n * Removes all optional undefined/never keys from an object.\n */\nexport type DeepRemoveOptionalUndefined<T> = T extends object ? { [K in keyof T]: DeepRemoveOptionalUndefined<T[K]> } : T;\n\n// why this works: https://stackoverflow.com/a/50375286\nexport type UnionToIntersection<U> =\n (U extends any ? (x: U) => void : never) extends ((x: infer I) => void) ? I : never\n\ntype _UnionToTupleInner<U, R extends any[], Last> = UnionToTuple<Exclude<U, Last>, [...R, Last]>\nexport type UnionToTuple<U, R extends any[] = []> = [U] extends [never] ? R : _UnionToTupleInner<U, R, LastUnionElement<U>>;\n\nexport type CollapseObjectUnion<T extends object> = {\n [K in AllUnionKeys<T>]?: T extends Record<K, infer V> ? V : never;\n};\ntypeAssertIs<CollapseObjectUnion<{ a: string } | { b: number }>, { a?: string, b?: number }>()();\ntypeAssertIs<CollapseObjectUnion<{ a: string } | { a: number }>, { a?: string | number }>()();\n\nexport type IntersectAll<T extends any[]> = UnionToIntersection<T[number]>;\n\nexport type OptionalKeys<T> = {\n [K in keyof T]: {} extends Pick<T, K> ? K : never;\n}[keyof T];\nexport type RequiredKeys<T> = {\n [K in keyof T]: {} extends Pick<T, K> ? never : K;\n}[keyof T];\n\n/**\n * Returns ALL keys of all union elements.\n */\nexport type AllUnionKeys<T extends object> = T extends T ? keyof T : never;\ntypeAssertIs<AllUnionKeys<{ a: string } | { b: number }>, \"a\" | \"b\">()();\n\nexport type SubtractType<T, U> = T extends object ? { [K in keyof T]: K extends keyof U ? SubtractType<T[K], U[K]> : T[K] } : (T extends U ? never : T); // note: this only works due to the distributive property of conditional types https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types\n\n\ntype _AntiIntersectInner<T, U> = T extends object ? (\n & Omit<U, keyof T>\n & { [K in keyof Pick<U, { [K in keyof T & keyof U]: U[K] extends T[K] ? (T[K] extends U[K] ? never : K) : never }[keyof T & keyof U]>]: PseudoAntiIntersect<T[K], U[K]> }\n & { [K in keyof Pick<U, keyof T & keyof U>]?: PseudoAntiIntersect<T[K], U[K]> }\n) : U;\n/**\n * Returns a type R such that T & R = U.\n */\nexport type AntiIntersect<T, U> = U extends T ? _AntiIntersectInner<T, U> : \"Cannot anti-intersect a type with a type that is not a subtype of it\"; // NOTE: This type is mostly untested — not sure how well it works on the edge cases\nexport type PseudoAntiIntersect<T, U> = _AntiIntersectInner<T, T & U>;\n\n/**\n * A variation of TypeScript's conditionals with slightly different semantics. It is the perfect type for cases where:\n *\n * - If all possible values are contained in `Extends`, then it will be mapped to `Then`.\n * - If all possible values are not contained in `Extends`, then it will be mapped to `Otherwise`.\n * - If some possible values are contained in `Extends` and some are not, then it will be mapped to `Then | Otherwise`.\n *\n * This is different from TypeScript's built-in conditional types (`Value extends Extends ? Then : Otherwise`), which\n * returns `Otherwise` for the third case (causing unsoundness in many real-world cases).\n */\nexport type IfAndOnlyIf<Value, Extends, Then, Otherwise> =\n | (Value extends Extends ? never : Otherwise)\n | (Value & Extends extends never ? never : Then);\n\n\n/**\n * Can be used to prettify a type in the IDE; for example, some complicated intersected types can be flattened into a single type.\n */\nexport type PrettifyType<T> = T extends object ? { [K in keyof T]: T[K] } & {} : T;\n\ntype _ToStringAndJoin<T extends any[], Separator extends string> =\n T extends [infer U, ...infer Rest extends any[]]\n ? `${TypeToString<U>}${Rest extends [any, ...any[]] ? `${Separator}${_ToStringAndJoin<Rest, Separator>}` : \"\"}`\n : \"<error-joining-tuple-elements>\";\ntype _TypeToStringInner<T> =\n IsAny<T> extends true ? \"any\"\n : IsNever<T> extends true ? \"never\"\n : IsUnion<T> extends true ? _ToStringAndJoin<UnionToTuple<T>, \" | \">\n : [T] extends [number] ? (number extends T ? \"number\" : `${T}`)\n : [T] extends [boolean] ? `${T}`\n : [T] extends [undefined] ? \"undefined\"\n : [T] extends [null] ? \"null\"\n : [T] extends [string] ? (string extends T ? \"string\" : `'${T}'`)\n : [T] extends [[]] ? \"[]\"\n : [T] extends [[any, ...any[]]] ? `[${_ToStringAndJoin<T, \", \">}]`\n : [T] extends [(infer E)[]] ? `${TypeToString<E>}[]`\n : [T] extends [Function] ? \"function\"\n : [T] extends [symbol] ? `symbol(${T['description']})`\n : [T] extends [object] ? `{ ${Join<UnionToTuple<{ [K in keyof T]: `${TypeToString<K>}: ${TypeToString<T[K]>}` }[keyof T]>, \", \">} }`\n : \"<unknown-type>\"\nexport type TypeToString<T> = _TypeToStringInner<T> extends `${infer S}` ? S : never;\n\n/**\n * Can be used to create assertions on types. For example, if passed any T other than `true`, the following will\n * show a type error:\n *\n * ```ts\n * typeAssert<T>()(); // the second pair of braces is important!\n * ```\n */\nexport function typeAssert<T>(): (\n IsAny<T> extends true ? TypeAssertionError<`Type assertion failed. Expected true, but got any.`>\n : IsNever<T> extends true ? TypeAssertionError<`Type assertion failed. Expected true, but got never.`>\n : T extends true ? (() => undefined)\n : TypeAssertionError<`Type assertion failed. Expected true, but got: ${TypeToString<T>}`>\n) {\n return (() => undefined) as any;\n}\ntype TypeAssertionError<T> =\n & [T]\n & /* this promise makes sure that if we accidentally forget the second pair of braces, eslint will complain (if we have no-floating-promises enabled) */ Promise<any>;\n\n\ntypeAssertExtends<ReturnType<typeof typeAssert<true>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssert<false>>, TypeAssertionError<`Type assertion failed. Expected true, but got: false`>>()();\ntypeAssertExtends<ReturnType<typeof typeAssert<never>>, TypeAssertionError<`Type assertion failed. Expected true, but got never.`>>()();\ntypeAssertExtends<ReturnType<typeof typeAssert<any>>, TypeAssertionError<`Type assertion failed. Expected true, but got any.`>>()();\n\n/**\n * Functionally equivalent to `typeAssert<T extends S ? true : false>()()`, but with better error messages.\n */\nexport function typeAssertExtends<T, S>(): (\n [T] extends [S] ? (() => undefined) : TypeAssertionError<`Type assertion failed. Expected ${TypeToString<T>} to extend ${TypeToString<S>}`>\n) {\n return (() => undefined) as any;\n}\n\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<never, true>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<any, true>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<false, false>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<\"abc\", string>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<{a: 1, b: 123}, {a: number}>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<never, never>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<true, any>>, () => undefined>()();\n\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<{a: number}, {a: 1}>>, [\"Type assertion failed. Expected { 'a': number } to extend { 'a': 1 }\"]>()();\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<any, never>>, [\"Type assertion failed. Expected any to extend never\"]>()();\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<false, true>>, [\"Type assertion failed. Expected false to extend true\"]>()();\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<false, never>>, [\"Type assertion failed. Expected false to extend never\"]>()();\n\n\nexport function typeAssertIs<T, U>(): (\n IsAny<T> extends true ? (IsAny<U> extends true ? (() => undefined) : TypeAssertionError<`Type assertion failed. Expected ${TypeToString<T>} to be ${TypeToString<U>}`>)\n : IsAny<U> extends true ? TypeAssertionError<`Type assertion failed. Expected ${TypeToString<T>} to be ${TypeToString<U>}`>\n : [T] extends [U] ? ([U] extends [T] ? (() => undefined) : TypeAssertionError<`Type assertion failed. Expected ${TypeToString<T>} to be ${TypeToString<U>}`>)\n : TypeAssertionError<`Type assertion failed. Expected ${TypeToString<T>} to be ${TypeToString<U>}`>\n) {\n return (() => undefined) as any;\n}\n\ntypeAssertExtends<ReturnType<typeof typeAssertIs<\"123\", \"123\">>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<{a: 1}, {a: 1}>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<DeepPartial<{a: 1}>, {a?: 1}>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<any, any>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<never, never>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<1, any>>, [\"Type assertion failed. Expected 1 to be any\"]>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<any, 1>>, [\"Type assertion failed. Expected any to be 1\"]>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<false, true>>, [\"Type assertion failed. Expected false to be true\"]>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<{a: number}, {a: 1}>>, [\"Type assertion failed. Expected { 'a': number } to be { 'a': 1 }\"]>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<any, never>>, [\"Type assertion failed. Expected any to be never\"]>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<false, true>>, [\"Type assertion failed. Expected false to be true\"]>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<false, never>>, [\"Type assertion failed. Expected false to be never\"]>()();\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgDA,aAA6F,EAAE;AAC/F,aAA0F,EAAE;AAe5F,aAAqE,EAAE;AAkEhE,SAAS,aAKd;AACA,SAAQ,MAAM;AAChB;AAMA,kBAAwE,EAAE;AAC1E,kBAAoI,EAAE;AACtI,kBAAoI,EAAE;AACtI,kBAAgI,EAAE;AAK3H,SAAS,oBAEd;AACA,SAAQ,MAAM;AAChB;AAEA,kBAAsF,EAAE;AACxF,kBAAoF,EAAE;AACtF,kBAAuF,EAAE;AACzF,kBAAwF,EAAE;AAC1F,kBAAsG,EAAE;AACxG,kBAAuF,EAAE;AACzF,kBAAoF,EAAE;AAEtF,kBAAuJ,EAAE;AACzJ,kBAA6H,EAAE;AAC/H,kBAA+H,EAAE;AACjI,kBAAiI,EAAE;AAG5H,SAAS,eAKd;AACA,SAAQ,MAAM;AAChB;AAEA,kBAAkF,EAAE;AACpF,kBAAoF,EAAE;AACtF,kBAAkG,EAAE;AACpG,kBAA8E,EAAE;AAChF,kBAAkF,EAAE;AACpF,kBAA4G,EAAE;AAC9G,kBAA4G,EAAE;AAC9G,kBAAsH,EAAE;AACxH,kBAA8I,EAAE;AAChJ,kBAAoH,EAAE;AACtH,kBAAsH,EAAE;AACxH,kBAAwH,EAAE;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/types.tsx"],"sourcesContent":["import { DeepPartial } from \"./objects\";\nimport { Join } from \"./strings\";\n\nexport type IsAny<T> = 0 extends (1 & T) ? true : false;\nexport type IsNever<T> = [T] extends [never] ? true : false;\nexport type IsNullish<T> = [T] extends [null | undefined] ? true : false;\nexport type IsUnion<T, U = T> =\n IsNever<T> extends true ? false\n : IsAny<T> extends true ? false\n : T extends U // distributive conditional https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types\n ? /* if the *whole* original type (`U`) still fits inside the current variant, then `T` wasn’t a union */ ([U] extends [T] ? false : true)\n : never;\n\nexport type NullishCoalesce<T, U> = T extends null | undefined ? U : T;\n\nexport type LastUnionElement<U> = UnionToIntersection<U extends any ? (x: U) => 0 : never> extends (x: infer L) => 0 ? L & U : never;\n\ntype primitive = string | number | boolean | bigint | symbol | null | undefined;\n\n/**\n * Makes a type prettier by recursively expanding all object types. For example, `Omit<{ a: 1 }, \"a\">` becomes just `{}`.\n */\nexport type Expand<T> = T extends (...args: infer A) => infer R\n ? ((...args: A) => R) extends T\n ? (...args: Expand<A>) => Expand<R>\n : ((...args: Expand<A>) => Expand<R>) & { [K in keyof T]: Expand<T[K]> }\n : T extends object\n ? T extends primitive\n ? T\n : T extends infer O\n ? { [K in keyof O]: Expand<O[K]> }\n : never\n : T;\n\n\n/**\n * Removes all optional undefined/never keys from an object.\n */\nexport type DeepRemoveOptionalUndefined<T> = T extends object ? { [K in keyof T]: DeepRemoveOptionalUndefined<T[K]> } : T;\n\n// why this works: https://stackoverflow.com/a/50375286\nexport type UnionToIntersection<U> =\n (U extends any ? (x: U) => void : never) extends ((x: infer I) => void) ? I : never\n\ntype _UnionToTupleInner<U, R extends any[], Last> = UnionToTuple<Exclude<U, Last>, [...R, Last]>\nexport type UnionToTuple<U, R extends any[] = []> = [U] extends [never] ? R : _UnionToTupleInner<U, R, LastUnionElement<U>>;\n\nexport type CollapseObjectUnion<T extends object> = {\n [K in AllUnionKeys<T>]?: T extends Record<K, infer V> ? V : never;\n};\ntypeAssertIs<CollapseObjectUnion<{ a: string } | { b: number }>, { a?: string, b?: number }>()();\ntypeAssertIs<CollapseObjectUnion<{ a: string } | { a: number }>, { a?: string | number }>()();\n\nexport type IntersectAll<T extends any[]> = UnionToIntersection<T[number]>;\n\nexport type OptionalKeys<T> = {\n [K in keyof T]: {} extends Pick<T, K> ? K : never;\n}[keyof T];\nexport type RequiredKeys<T> = {\n [K in keyof T]: {} extends Pick<T, K> ? never : K;\n}[keyof T];\n\n/**\n * Returns a type whose keys are the intersection of the keys of T and U, deeply.\n */\nexport type KeyIntersect<T, U> =\n | { [K in keyof T & keyof U]?: T[K] & U[K] }\n | { [K in RequiredKeys<T> & keyof U]: T[K] & U[K] }\n | { [K in RequiredKeys<U> & keyof T]: U[K] & T[K] }\n\n/**\n * Returns ALL keys of all union elements.\n */\nexport type AllUnionKeys<T extends object> = T extends T ? keyof T : never;\ntypeAssertIs<AllUnionKeys<{ a: string } | { b: number }>, \"a\" | \"b\">()();\n\nexport type SubtractType<T, U> = T extends object ? { [K in keyof T]: K extends keyof U ? SubtractType<T[K], U[K]> : T[K] } : (T extends U ? never : T); // note: this only works due to the distributive property of conditional types https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types\n\n\ntype _AntiIntersectInner<T, U> = T extends object ? (\n & Omit<U, keyof T>\n & { [K in keyof Pick<U, { [K in keyof T & keyof U]: U[K] extends T[K] ? (T[K] extends U[K] ? never : K) : never }[keyof T & keyof U]>]: PseudoAntiIntersect<T[K], U[K]> }\n & { [K in keyof Pick<U, keyof T & keyof U>]?: PseudoAntiIntersect<T[K], U[K]> }\n) : U;\n/**\n * Returns a type R such that T & R = U.\n */\nexport type AntiIntersect<T, U> = U extends T ? _AntiIntersectInner<T, U> : \"Cannot anti-intersect a type with a type that is not a subtype of it\"; // NOTE: This type is mostly untested — not sure how well it works on the edge cases\nexport type PseudoAntiIntersect<T, U> = _AntiIntersectInner<T, T & U>;\n\n/**\n * A variation of TypeScript's conditionals with slightly different semantics. It is the perfect type for cases where:\n *\n * - If all possible values are contained in `Extends`, then it will be mapped to `Then`.\n * - If all possible values are not contained in `Extends`, then it will be mapped to `Otherwise`.\n * - If some possible values are contained in `Extends` and some are not, then it will be mapped to `Then | Otherwise`.\n *\n * This is different from TypeScript's built-in conditional types (`Value extends Extends ? Then : Otherwise`), which\n * returns `Otherwise` for the third case (causing unsoundness in many real-world cases).\n */\nexport type IfAndOnlyIf<Value, Extends, Then, Otherwise> =\n | (Value extends Extends ? never : Otherwise)\n | (Value & Extends extends never ? never : Then);\n\n\n/**\n * Can be used to prettify a type in the IDE; for example, some complicated intersected types can be flattened into a single type.\n */\nexport type PrettifyType<T> = T extends object ? { [K in keyof T]: T[K] } & {} : T;\n\ntype _ToStringAndJoin<T extends any[], Separator extends string> =\n T extends [infer U, ...infer Rest extends any[]]\n ? `${TypeToString<U>}${Rest extends [any, ...any[]] ? `${Separator}${_ToStringAndJoin<Rest, Separator>}` : \"\"}`\n : \"<error-joining-tuple-elements>\";\ntype _TypeToStringInner<T> =\n IsAny<T> extends true ? \"any\"\n : IsNever<T> extends true ? \"never\"\n : IsUnion<T> extends true ? _ToStringAndJoin<UnionToTuple<T>, \" | \">\n : [T] extends [number] ? (number extends T ? \"number\" : `${T}`)\n : [T] extends [boolean] ? `${T}`\n : [T] extends [undefined] ? \"undefined\"\n : [T] extends [null] ? \"null\"\n : [T] extends [string] ? (string extends T ? \"string\" : `'${T}'`)\n : [T] extends [[]] ? \"[]\"\n : [T] extends [[any, ...any[]]] ? `[${_ToStringAndJoin<T, \", \">}]`\n : [T] extends [(infer E)[]] ? `${TypeToString<E>}[]`\n : [T] extends [Function] ? \"function\"\n : [T] extends [symbol] ? `symbol(${T['description']})`\n : [T] extends [object] ? `{ ${Join<UnionToTuple<{ [K in keyof T]: `${TypeToString<K>}: ${TypeToString<T[K]>}` }[keyof T]>, \", \">} }`\n : \"<unknown-type>\"\nexport type TypeToString<T> = _TypeToStringInner<T> extends `${infer S}` ? S : never;\n\n/**\n * Can be used to create assertions on types. For example, if passed any T other than `true`, the following will\n * show a type error:\n *\n * ```ts\n * typeAssert<T>()(); // the second pair of braces is important!\n * ```\n */\nexport function typeAssert<T>(): (\n IsAny<T> extends true ? TypeAssertionError<`Type assertion failed. Expected true, but got any.`>\n : IsNever<T> extends true ? TypeAssertionError<`Type assertion failed. Expected true, but got never.`>\n : T extends true ? (() => undefined)\n : TypeAssertionError<`Type assertion failed. Expected true, but got: ${TypeToString<T>}`>\n) {\n return (() => undefined) as any;\n}\ntype TypeAssertionError<T> =\n & [T]\n & /* this promise makes sure that if we accidentally forget the second pair of braces, eslint will complain (if we have no-floating-promises enabled) */ Promise<any>;\n\n\ntypeAssertExtends<ReturnType<typeof typeAssert<true>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssert<false>>, TypeAssertionError<`Type assertion failed. Expected true, but got: false`>>()();\ntypeAssertExtends<ReturnType<typeof typeAssert<never>>, TypeAssertionError<`Type assertion failed. Expected true, but got never.`>>()();\ntypeAssertExtends<ReturnType<typeof typeAssert<any>>, TypeAssertionError<`Type assertion failed. Expected true, but got any.`>>()();\n\n/**\n * Functionally equivalent to `typeAssert<T extends S ? true : false>()()`, but with better error messages.\n */\nexport function typeAssertExtends<T, S>(): (\n [T] extends [S] ? (() => undefined) : TypeAssertionError<`Type assertion failed. Expected ${TypeToString<T>} to extend ${TypeToString<S>}`>\n) {\n return (() => undefined) as any;\n}\n\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<never, true>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<any, true>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<false, false>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<\"abc\", string>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<{a: 1, b: 123}, {a: number}>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<never, never>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<true, any>>, () => undefined>()();\n\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<{a: number}, {a: 1}>>, [\"Type assertion failed. Expected { 'a': number } to extend { 'a': 1 }\"]>()();\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<any, never>>, [\"Type assertion failed. Expected any to extend never\"]>()();\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<false, true>>, [\"Type assertion failed. Expected false to extend true\"]>()();\ntypeAssertExtends<ReturnType<typeof typeAssertExtends<false, never>>, [\"Type assertion failed. Expected false to extend never\"]>()();\n\n\nexport function typeAssertIs<T, U>(): (\n IsAny<T> extends true ? (IsAny<U> extends true ? (() => undefined) : TypeAssertionError<`Type assertion failed. Expected ${TypeToString<T>} to be ${TypeToString<U>}`>)\n : IsAny<U> extends true ? TypeAssertionError<`Type assertion failed. Expected ${TypeToString<T>} to be ${TypeToString<U>}`>\n : [T] extends [U] ? ([U] extends [T] ? (() => undefined) : TypeAssertionError<`Type assertion failed. Expected ${TypeToString<T>} to be ${TypeToString<U>}`>)\n : TypeAssertionError<`Type assertion failed. Expected ${TypeToString<T>} to be ${TypeToString<U>}`>\n) {\n return (() => undefined) as any;\n}\n\ntypeAssertExtends<ReturnType<typeof typeAssertIs<\"123\", \"123\">>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<{a: 1}, {a: 1}>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<DeepPartial<{a: 1}>, {a?: 1}>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<any, any>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<never, never>>, () => undefined>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<1, any>>, [\"Type assertion failed. Expected 1 to be any\"]>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<any, 1>>, [\"Type assertion failed. Expected any to be 1\"]>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<false, true>>, [\"Type assertion failed. Expected false to be true\"]>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<{a: number}, {a: 1}>>, [\"Type assertion failed. Expected { 'a': number } to be { 'a': 1 }\"]>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<any, never>>, [\"Type assertion failed. Expected any to be never\"]>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<false, true>>, [\"Type assertion failed. Expected false to be true\"]>()();\ntypeAssertExtends<ReturnType<typeof typeAssertIs<false, never>>, [\"Type assertion failed. Expected false to be never\"]>()();\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkDA,aAA6F,EAAE;AAC/F,aAA0F,EAAE;AAuB5F,aAAqE,EAAE;AAkEhE,SAAS,aAKd;AACA,SAAQ,MAAM;AAChB;AAMA,kBAAwE,EAAE;AAC1E,kBAAoI,EAAE;AACtI,kBAAoI,EAAE;AACtI,kBAAgI,EAAE;AAK3H,SAAS,oBAEd;AACA,SAAQ,MAAM;AAChB;AAEA,kBAAsF,EAAE;AACxF,kBAAoF,EAAE;AACtF,kBAAuF,EAAE;AACzF,kBAAwF,EAAE;AAC1F,kBAAsG,EAAE;AACxG,kBAAuF,EAAE;AACzF,kBAAoF,EAAE;AAEtF,kBAAuJ,EAAE;AACzJ,kBAA6H,EAAE;AAC/H,kBAA+H,EAAE;AACjI,kBAAiI,EAAE;AAG5H,SAAS,eAKd;AACA,SAAQ,MAAM;AAChB;AAEA,kBAAkF,EAAE;AACpF,kBAAoF,EAAE;AACtF,kBAAkG,EAAE;AACpG,kBAA8E,EAAE;AAChF,kBAAkF,EAAE;AACpF,kBAA4G,EAAE;AAC9G,kBAA4G,EAAE;AAC9G,kBAAsH,EAAE;AACxH,kBAA8I,EAAE;AAChJ,kBAAoH,EAAE;AACtH,kBAAsH,EAAE;AACxH,kBAAwH,EAAE;","names":[]}
|
package/dist/utils/urls.d.mts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
declare function createUrlIfValid(...args: ConstructorParameters<typeof URL>): URL | null;
|
|
2
2
|
declare function isValidUrl(url: string): boolean;
|
|
3
3
|
declare function isValidHostname(hostname: string): boolean;
|
|
4
|
+
declare function isValidHostnameWithWildcards(hostname: string): boolean;
|
|
5
|
+
declare function matchHostnamePattern(pattern: string, hostname: string): boolean;
|
|
4
6
|
declare function isLocalhost(urlOrString: string | URL): boolean;
|
|
5
7
|
declare function isRelative(url: string): boolean;
|
|
6
8
|
declare function getRelativePart(url: URL): string;
|
|
@@ -17,4 +19,4 @@ declare function url(strings: TemplateStringsArray | readonly string[], ...value
|
|
|
17
19
|
*/
|
|
18
20
|
declare function urlString(strings: TemplateStringsArray | readonly string[], ...values: (string | number | boolean)[]): string;
|
|
19
21
|
|
|
20
|
-
export { createUrlIfValid, getRelativePart, isLocalhost, isRelative, isValidHostname, isValidUrl, url, urlString };
|
|
22
|
+
export { createUrlIfValid, getRelativePart, isLocalhost, isRelative, isValidHostname, isValidHostnameWithWildcards, isValidUrl, matchHostnamePattern, url, urlString };
|
package/dist/utils/urls.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
declare function createUrlIfValid(...args: ConstructorParameters<typeof URL>): URL | null;
|
|
2
2
|
declare function isValidUrl(url: string): boolean;
|
|
3
3
|
declare function isValidHostname(hostname: string): boolean;
|
|
4
|
+
declare function isValidHostnameWithWildcards(hostname: string): boolean;
|
|
5
|
+
declare function matchHostnamePattern(pattern: string, hostname: string): boolean;
|
|
4
6
|
declare function isLocalhost(urlOrString: string | URL): boolean;
|
|
5
7
|
declare function isRelative(url: string): boolean;
|
|
6
8
|
declare function getRelativePart(url: URL): string;
|
|
@@ -17,4 +19,4 @@ declare function url(strings: TemplateStringsArray | readonly string[], ...value
|
|
|
17
19
|
*/
|
|
18
20
|
declare function urlString(strings: TemplateStringsArray | readonly string[], ...values: (string | number | boolean)[]): string;
|
|
19
21
|
|
|
20
|
-
export { createUrlIfValid, getRelativePart, isLocalhost, isRelative, isValidHostname, isValidUrl, url, urlString };
|
|
22
|
+
export { createUrlIfValid, getRelativePart, isLocalhost, isRelative, isValidHostname, isValidHostnameWithWildcards, isValidUrl, matchHostnamePattern, url, urlString };
|
package/dist/utils/urls.js
CHANGED
|
@@ -25,7 +25,9 @@ __export(urls_exports, {
|
|
|
25
25
|
isLocalhost: () => isLocalhost,
|
|
26
26
|
isRelative: () => isRelative,
|
|
27
27
|
isValidHostname: () => isValidHostname,
|
|
28
|
+
isValidHostnameWithWildcards: () => isValidHostnameWithWildcards,
|
|
28
29
|
isValidUrl: () => isValidUrl,
|
|
30
|
+
matchHostnamePattern: () => matchHostnamePattern,
|
|
29
31
|
url: () => url,
|
|
30
32
|
urlString: () => urlString
|
|
31
33
|
});
|
|
@@ -43,10 +45,62 @@ function isValidUrl(url2) {
|
|
|
43
45
|
return !!createUrlIfValid(url2);
|
|
44
46
|
}
|
|
45
47
|
function isValidHostname(hostname) {
|
|
48
|
+
if (!hostname || hostname.startsWith(".") || hostname.endsWith(".") || hostname.includes("..")) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
46
51
|
const url2 = createUrlIfValid(`https://${hostname}`);
|
|
47
52
|
if (!url2) return false;
|
|
48
53
|
return url2.hostname === hostname;
|
|
49
54
|
}
|
|
55
|
+
function isValidHostnameWithWildcards(hostname) {
|
|
56
|
+
if (!hostname) return false;
|
|
57
|
+
const hasWildcard = hostname.includes("*");
|
|
58
|
+
if (!hasWildcard) {
|
|
59
|
+
return isValidHostname(hostname);
|
|
60
|
+
}
|
|
61
|
+
if (hostname.startsWith(".") || hostname.endsWith(".")) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
if (hostname.includes("..")) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
const testHostname = hostname.replace(/\*+/g, "wildcard");
|
|
68
|
+
if (!/^[a-zA-Z0-9.-]+$/.test(testHostname)) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
const segments = hostname.split(/\*+/);
|
|
72
|
+
for (let i = 0; i < segments.length; i++) {
|
|
73
|
+
const segment = segments[i];
|
|
74
|
+
if (segment === "") continue;
|
|
75
|
+
if (i === 0 && segment.startsWith(".")) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
if (i === segments.length - 1 && segment.endsWith(".")) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
if (segment.includes("..")) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
function matchHostnamePattern(pattern, hostname) {
|
|
88
|
+
if (!pattern.includes("*")) {
|
|
89
|
+
return pattern === hostname;
|
|
90
|
+
}
|
|
91
|
+
let regexPattern = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
92
|
+
const doubleWildcardPlaceholder = "\0DOUBLE_WILDCARD\0";
|
|
93
|
+
regexPattern = regexPattern.replace(/\*\*/g, doubleWildcardPlaceholder);
|
|
94
|
+
regexPattern = regexPattern.replace(/\*/g, "[^.]*");
|
|
95
|
+
regexPattern = regexPattern.replace(new RegExp(doubleWildcardPlaceholder, "g"), ".*");
|
|
96
|
+
regexPattern = "^" + regexPattern + "$";
|
|
97
|
+
try {
|
|
98
|
+
const regex = new RegExp(regexPattern);
|
|
99
|
+
return regex.test(hostname);
|
|
100
|
+
} catch {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
50
104
|
function isLocalhost(urlOrString) {
|
|
51
105
|
const url2 = createUrlIfValid(urlOrString);
|
|
52
106
|
if (!url2) return false;
|
|
@@ -78,7 +132,9 @@ function urlString(strings, ...values) {
|
|
|
78
132
|
isLocalhost,
|
|
79
133
|
isRelative,
|
|
80
134
|
isValidHostname,
|
|
135
|
+
isValidHostnameWithWildcards,
|
|
81
136
|
isValidUrl,
|
|
137
|
+
matchHostnamePattern,
|
|
82
138
|
url,
|
|
83
139
|
urlString
|
|
84
140
|
});
|
package/dist/utils/urls.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/urls.tsx"],"sourcesContent":["import { generateSecureRandomString } from \"./crypto\";\nimport { templateIdentity } from \"./strings\";\n\nexport function createUrlIfValid(...args: ConstructorParameters<typeof URL>) {\n try {\n return new URL(...args);\n } catch (e) {\n return null;\n }\n}\nundefined?.test(\"createUrlIfValid\", ({ expect }) => {\n // Test with valid URLs\n expect(createUrlIfValid(\"https://example.com\")).toBeInstanceOf(URL);\n expect(createUrlIfValid(\"https://example.com/path?query=value#hash\")).toBeInstanceOf(URL);\n expect(createUrlIfValid(\"/path\", \"https://example.com\")).toBeInstanceOf(URL);\n\n // Test with invalid URLs\n expect(createUrlIfValid(\"\")).toBeNull();\n expect(createUrlIfValid(\"not a url\")).toBeNull();\n expect(createUrlIfValid(\"http://\")).toBeNull();\n});\n\nexport function isValidUrl(url: string) {\n return !!createUrlIfValid(url);\n}\nundefined?.test(\"isValidUrl\", ({ expect }) => {\n // Test with valid URLs\n expect(isValidUrl(\"https://example.com\")).toBe(true);\n expect(isValidUrl(\"http://localhost:3000\")).toBe(true);\n expect(isValidUrl(\"ftp://example.com\")).toBe(true);\n\n // Test with invalid URLs\n expect(isValidUrl(\"\")).toBe(false);\n expect(isValidUrl(\"not a url\")).toBe(false);\n expect(isValidUrl(\"http://\")).toBe(false);\n});\n\nexport function isValidHostname(hostname: string) {\n const url = createUrlIfValid(`https://${hostname}`);\n if (!url) return false;\n return url.hostname === hostname;\n}\nundefined?.test(\"isValidHostname\", ({ expect }) => {\n // Test with valid hostnames\n expect(isValidHostname(\"example.com\")).toBe(true);\n expect(isValidHostname(\"localhost\")).toBe(true);\n expect(isValidHostname(\"sub.domain.example.com\")).toBe(true);\n expect(isValidHostname(\"127.0.0.1\")).toBe(true);\n\n // Test with invalid hostnames\n expect(isValidHostname(\"\")).toBe(false);\n expect(isValidHostname(\"example.com/path\")).toBe(false);\n expect(isValidHostname(\"https://example.com\")).toBe(false);\n expect(isValidHostname(\"example com\")).toBe(false);\n});\n\nexport function isLocalhost(urlOrString: string | URL) {\n const url = createUrlIfValid(urlOrString);\n if (!url) return false;\n if (url.hostname === \"localhost\" || url.hostname.endsWith(\".localhost\")) return true;\n if (url.hostname.match(/^127\\.\\d+\\.\\d+\\.\\d+$/)) return true;\n return false;\n}\nundefined?.test(\"isLocalhost\", ({ expect }) => {\n // Test with localhost URLs\n expect(isLocalhost(\"http://localhost\")).toBe(true);\n expect(isLocalhost(\"https://localhost:8080\")).toBe(true);\n expect(isLocalhost(\"http://sub.localhost\")).toBe(true);\n expect(isLocalhost(\"http://127.0.0.1\")).toBe(true);\n expect(isLocalhost(\"http://127.1.2.3\")).toBe(true);\n\n // Test with non-localhost URLs\n expect(isLocalhost(\"https://example.com\")).toBe(false);\n expect(isLocalhost(\"http://192.168.1.1\")).toBe(false);\n expect(isLocalhost(\"http://10.0.0.1\")).toBe(false);\n\n // Test with URL objects\n expect(isLocalhost(new URL(\"http://localhost\"))).toBe(true);\n expect(isLocalhost(new URL(\"https://example.com\"))).toBe(false);\n\n // Test with invalid URLs\n expect(isLocalhost(\"not a url\")).toBe(false);\n expect(isLocalhost(\"\")).toBe(false);\n});\n\nexport function isRelative(url: string) {\n const randomDomain = `${generateSecureRandomString()}.stack-auth.example.com`;\n const u = createUrlIfValid(url, `https://${randomDomain}`);\n if (!u) return false;\n if (u.host !== randomDomain) return false;\n if (u.protocol !== \"https:\") return false;\n return true;\n}\nundefined?.test(\"isRelative\", ({ expect }) => {\n // We can't easily mock generateSecureRandomString in this context\n // but we can still test the function's behavior\n\n // Test with relative URLs\n expect(isRelative(\"/\")).toBe(true);\n expect(isRelative(\"/path\")).toBe(true);\n expect(isRelative(\"/path?query=value#hash\")).toBe(true);\n\n // Test with absolute URLs\n expect(isRelative(\"https://example.com\")).toBe(false);\n expect(isRelative(\"http://example.com\")).toBe(false);\n expect(isRelative(\"//example.com\")).toBe(false);\n\n // Note: The implementation treats empty strings and invalid URLs as relative\n // This is because they can be resolved against a base URL\n expect(isRelative(\"\")).toBe(true);\n expect(isRelative(\"not a url\")).toBe(true);\n});\n\nexport function getRelativePart(url: URL) {\n return url.pathname + url.search + url.hash;\n}\nundefined?.test(\"getRelativePart\", ({ expect }) => {\n // Test with various URLs\n expect(getRelativePart(new URL(\"https://example.com\"))).toBe(\"/\");\n expect(getRelativePart(new URL(\"https://example.com/path\"))).toBe(\"/path\");\n expect(getRelativePart(new URL(\"https://example.com/path?query=value\"))).toBe(\"/path?query=value\");\n expect(getRelativePart(new URL(\"https://example.com/path#hash\"))).toBe(\"/path#hash\");\n expect(getRelativePart(new URL(\"https://example.com/path?query=value#hash\"))).toBe(\"/path?query=value#hash\");\n\n // Test with different domains but same paths\n const url1 = new URL(\"https://example.com/path?query=value#hash\");\n const url2 = new URL(\"https://different.com/path?query=value#hash\");\n expect(getRelativePart(url1)).toBe(getRelativePart(url2));\n});\n\n/**\n * A template literal tag that returns a URL.\n *\n * Any values passed are encoded.\n */\nexport function url(strings: TemplateStringsArray | readonly string[], ...values: (string|number|boolean)[]): URL {\n return new URL(urlString(strings, ...values));\n}\nundefined?.test(\"url\", ({ expect }) => {\n // Test with no interpolation\n expect(url`https://example.com`).toBeInstanceOf(URL);\n expect(url`https://example.com`.href).toBe(\"https://example.com/\");\n\n // Test with string interpolation\n expect(url`https://example.com/${\"path\"}`).toBeInstanceOf(URL);\n expect(url`https://example.com/${\"path\"}`.pathname).toBe(\"/path\");\n\n // Test with number interpolation\n expect(url`https://example.com/${42}`).toBeInstanceOf(URL);\n expect(url`https://example.com/${42}`.pathname).toBe(\"/42\");\n\n // Test with boolean interpolation\n expect(url`https://example.com/${true}`).toBeInstanceOf(URL);\n expect(url`https://example.com/${true}`.pathname).toBe(\"/true\");\n\n // Test with special characters in interpolation\n expect(url`https://example.com/${\"path with spaces\"}`).toBeInstanceOf(URL);\n expect(url`https://example.com/${\"path with spaces\"}`.pathname).toBe(\"/path%20with%20spaces\");\n\n // Test with multiple interpolations\n expect(url`https://example.com/${\"path\"}?query=${\"value\"}`).toBeInstanceOf(URL);\n expect(url`https://example.com/${\"path\"}?query=${\"value\"}`.pathname).toBe(\"/path\");\n expect(url`https://example.com/${\"path\"}?query=${\"value\"}`.search).toBe(\"?query=value\");\n});\n\n\n/**\n * A template literal tag that returns a URL string.\n *\n * Any values passed are encoded.\n */\nexport function urlString(strings: TemplateStringsArray | readonly string[], ...values: (string|number|boolean)[]): string {\n return templateIdentity(strings, ...values.map(encodeURIComponent));\n}\nundefined?.test(\"urlString\", ({ expect }) => {\n // Test with no interpolation\n expect(urlString`https://example.com`).toBe(\"https://example.com\");\n\n // Test with string interpolation\n expect(urlString`https://example.com/${\"path\"}`).toBe(\"https://example.com/path\");\n\n // Test with number interpolation\n expect(urlString`https://example.com/${42}`).toBe(\"https://example.com/42\");\n\n // Test with boolean interpolation\n expect(urlString`https://example.com/${true}`).toBe(\"https://example.com/true\");\n\n // Test with special characters in interpolation\n expect(urlString`https://example.com/${\"path with spaces\"}`).toBe(\"https://example.com/path%20with%20spaces\");\n expect(urlString`https://example.com/${\"?&=\"}`).toBe(\"https://example.com/%3F%26%3D\");\n\n // Test with multiple interpolations\n expect(urlString`https://example.com/${\"path\"}?query=${\"value\"}`).toBe(\"https://example.com/path?query=value\");\n expect(urlString`https://example.com/${\"path\"}?query=${\"value with spaces\"}`).toBe(\"https://example.com/path?query=value%20with%20spaces\");\n});\n\n\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAA2C;AAC3C,qBAAiC;AAE1B,SAAS,oBAAoB,MAAyC;AAC3E,MAAI;AACF,WAAO,IAAI,IAAI,GAAG,IAAI;AAAA,EACxB,SAAS,GAAG;AACV,WAAO;AAAA,EACT;AACF;AAaO,SAAS,WAAWA,MAAa;AACtC,SAAO,CAAC,CAAC,iBAAiBA,IAAG;AAC/B;AAaO,SAAS,gBAAgB,UAAkB;AAChD,QAAMA,OAAM,iBAAiB,WAAW,QAAQ,EAAE;AAClD,MAAI,CAACA,KAAK,QAAO;AACjB,SAAOA,KAAI,aAAa;AAC1B;AAeO,SAAS,YAAY,aAA2B;AACrD,QAAMA,OAAM,iBAAiB,WAAW;AACxC,MAAI,CAACA,KAAK,QAAO;AACjB,MAAIA,KAAI,aAAa,eAAeA,KAAI,SAAS,SAAS,YAAY,EAAG,QAAO;AAChF,MAAIA,KAAI,SAAS,MAAM,sBAAsB,EAAG,QAAO;AACvD,SAAO;AACT;AAuBO,SAAS,WAAWA,MAAa;AACtC,QAAM,eAAe,OAAG,0CAA2B,CAAC;AACpD,QAAM,IAAI,iBAAiBA,MAAK,WAAW,YAAY,EAAE;AACzD,MAAI,CAAC,EAAG,QAAO;AACf,MAAI,EAAE,SAAS,aAAc,QAAO;AACpC,MAAI,EAAE,aAAa,SAAU,QAAO;AACpC,SAAO;AACT;AAqBO,SAAS,gBAAgBA,MAAU;AACxC,SAAOA,KAAI,WAAWA,KAAI,SAASA,KAAI;AACzC;AAoBO,SAAS,IAAI,YAAsD,QAAwC;AAChH,SAAO,IAAI,IAAI,UAAU,SAAS,GAAG,MAAM,CAAC;AAC9C;AAkCO,SAAS,UAAU,YAAsD,QAA2C;AACzH,aAAO,iCAAiB,SAAS,GAAG,OAAO,IAAI,kBAAkB,CAAC;AACpE;","names":["url"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/urls.tsx"],"sourcesContent":["import { generateSecureRandomString } from \"./crypto\";\nimport { templateIdentity } from \"./strings\";\n\nexport function createUrlIfValid(...args: ConstructorParameters<typeof URL>) {\n try {\n return new URL(...args);\n } catch (e) {\n return null;\n }\n}\nundefined?.test(\"createUrlIfValid\", ({ expect }) => {\n // Test with valid URLs\n expect(createUrlIfValid(\"https://example.com\")).toBeInstanceOf(URL);\n expect(createUrlIfValid(\"https://example.com/path?query=value#hash\")).toBeInstanceOf(URL);\n expect(createUrlIfValid(\"/path\", \"https://example.com\")).toBeInstanceOf(URL);\n\n // Test with invalid URLs\n expect(createUrlIfValid(\"\")).toBeNull();\n expect(createUrlIfValid(\"not a url\")).toBeNull();\n expect(createUrlIfValid(\"http://\")).toBeNull();\n});\n\nexport function isValidUrl(url: string) {\n return !!createUrlIfValid(url);\n}\nundefined?.test(\"isValidUrl\", ({ expect }) => {\n // Test with valid URLs\n expect(isValidUrl(\"https://example.com\")).toBe(true);\n expect(isValidUrl(\"http://localhost:3000\")).toBe(true);\n expect(isValidUrl(\"ftp://example.com\")).toBe(true);\n\n // Test with invalid URLs\n expect(isValidUrl(\"\")).toBe(false);\n expect(isValidUrl(\"not a url\")).toBe(false);\n expect(isValidUrl(\"http://\")).toBe(false);\n});\n\nexport function isValidHostname(hostname: string) {\n // Basic validation\n if (!hostname || hostname.startsWith('.') || hostname.endsWith('.') || hostname.includes('..')) {\n return false;\n }\n\n const url = createUrlIfValid(`https://${hostname}`);\n if (!url) return false;\n return url.hostname === hostname;\n}\nundefined?.test(\"isValidHostname\", ({ expect }) => {\n // Test with valid hostnames\n expect(isValidHostname(\"example.com\")).toBe(true);\n expect(isValidHostname(\"localhost\")).toBe(true);\n expect(isValidHostname(\"sub.domain.example.com\")).toBe(true);\n expect(isValidHostname(\"127.0.0.1\")).toBe(true);\n\n // Test with invalid hostnames\n expect(isValidHostname(\"\")).toBe(false);\n expect(isValidHostname(\"example.com/path\")).toBe(false);\n expect(isValidHostname(\"https://example.com\")).toBe(false);\n expect(isValidHostname(\"example com\")).toBe(false);\n});\n\nexport function isValidHostnameWithWildcards(hostname: string) {\n // Empty hostnames are invalid\n if (!hostname) return false;\n\n // Check if it contains wildcards\n const hasWildcard = hostname.includes('*');\n\n if (!hasWildcard) {\n // If no wildcards, validate as a normal hostname\n return isValidHostname(hostname);\n }\n\n // Basic validation checks that apply even with wildcards\n // - Hostname cannot start or end with a dot\n if (hostname.startsWith('.') || hostname.endsWith('.')) {\n return false;\n }\n\n // - No consecutive dots\n if (hostname.includes('..')) {\n return false;\n }\n\n // For wildcard validation, check that non-wildcard parts contain valid characters\n // Replace wildcards with a valid placeholder to check the rest\n const testHostname = hostname.replace(/\\*+/g, 'wildcard');\n\n // Check if the resulting string would be a valid hostname\n if (!/^[a-zA-Z0-9.-]+$/.test(testHostname)) {\n return false;\n }\n\n // Additional check: ensure the pattern makes sense\n // Check each segment between wildcards\n const segments = hostname.split(/\\*+/);\n for (let i = 0; i < segments.length; i++) {\n const segment = segments[i];\n if (segment === '') continue; // Empty segments are OK (consecutive wildcards)\n\n // First segment can't start with dot\n if (i === 0 && segment.startsWith('.')) {\n return false;\n }\n\n // Last segment can't end with dot\n if (i === segments.length - 1 && segment.endsWith('.')) {\n return false;\n }\n\n // No segment should have consecutive dots\n if (segment.includes('..')) {\n return false;\n }\n }\n\n return true;\n}\nundefined?.test(\"isValidHostnameWithWildcards\", ({ expect }) => {\n // Test with valid regular hostnames\n expect(isValidHostnameWithWildcards(\"example.com\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"localhost\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"sub.domain.example.com\")).toBe(true);\n\n // Test with valid wildcard hostnames\n expect(isValidHostnameWithWildcards(\"*.example.com\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"a-*.example.com\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"*.*.org\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"**.example.com\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"sub.**.com\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"*-api.*.com\")).toBe(true);\n\n // Test with invalid hostnames\n expect(isValidHostnameWithWildcards(\"\")).toBe(false);\n expect(isValidHostnameWithWildcards(\"example.com/path\")).toBe(false);\n expect(isValidHostnameWithWildcards(\"https://example.com\")).toBe(false);\n expect(isValidHostnameWithWildcards(\"example com\")).toBe(false);\n expect(isValidHostnameWithWildcards(\".example.com\")).toBe(false);\n expect(isValidHostnameWithWildcards(\"example.com.\")).toBe(false);\n expect(isValidHostnameWithWildcards(\"example..com\")).toBe(false);\n expect(isValidHostnameWithWildcards(\"*.example..com\")).toBe(false);\n});\n\nexport function matchHostnamePattern(pattern: string, hostname: string): boolean {\n // If no wildcards, it's an exact match\n if (!pattern.includes('*')) {\n return pattern === hostname;\n }\n\n // Convert the pattern to a regex\n // First, escape all regex special characters except *\n let regexPattern = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n // Use a placeholder for ** to handle it separately from single *\n const doubleWildcardPlaceholder = '\\x00DOUBLE_WILDCARD\\x00';\n regexPattern = regexPattern.replace(/\\*\\*/g, doubleWildcardPlaceholder);\n\n // Replace single * with a pattern that matches anything except dots\n regexPattern = regexPattern.replace(/\\*/g, '[^.]*');\n\n // Replace the double wildcard placeholder with a pattern that matches anything including dots\n regexPattern = regexPattern.replace(new RegExp(doubleWildcardPlaceholder, 'g'), '.*');\n\n // Anchor the pattern to match the entire hostname\n regexPattern = '^' + regexPattern + '$';\n\n try {\n const regex = new RegExp(regexPattern);\n return regex.test(hostname);\n } catch {\n return false;\n }\n}\nundefined?.test(\"matchHostnamePattern\", ({ expect }) => {\n // Test exact matches\n expect(matchHostnamePattern(\"example.com\", \"example.com\")).toBe(true);\n expect(matchHostnamePattern(\"example.com\", \"other.com\")).toBe(false);\n\n // Test single wildcard matches\n expect(matchHostnamePattern(\"*.example.com\", \"api.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"*.example.com\", \"www.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"*.example.com\", \"example.com\")).toBe(false);\n expect(matchHostnamePattern(\"*.example.com\", \"api.v2.example.com\")).toBe(false);\n\n // Test double wildcard matches\n expect(matchHostnamePattern(\"**.example.com\", \"api.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"**.example.com\", \"api.v2.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"**.example.com\", \"a.b.c.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"**.example.com\", \"example.com\")).toBe(false);\n\n // Test complex patterns\n expect(matchHostnamePattern(\"api-*.example.com\", \"api-v1.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"api-*.example.com\", \"api-v2.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"api-*.example.com\", \"api.example.com\")).toBe(false);\n expect(matchHostnamePattern(\"*.*.org\", \"mail.example.org\")).toBe(true);\n expect(matchHostnamePattern(\"*.*.org\", \"example.org\")).toBe(false);\n});\n\nexport function isLocalhost(urlOrString: string | URL) {\n const url = createUrlIfValid(urlOrString);\n if (!url) return false;\n if (url.hostname === \"localhost\" || url.hostname.endsWith(\".localhost\")) return true;\n if (url.hostname.match(/^127\\.\\d+\\.\\d+\\.\\d+$/)) return true;\n return false;\n}\nundefined?.test(\"isLocalhost\", ({ expect }) => {\n // Test with localhost URLs\n expect(isLocalhost(\"http://localhost\")).toBe(true);\n expect(isLocalhost(\"https://localhost:8080\")).toBe(true);\n expect(isLocalhost(\"http://sub.localhost\")).toBe(true);\n expect(isLocalhost(\"http://127.0.0.1\")).toBe(true);\n expect(isLocalhost(\"http://127.1.2.3\")).toBe(true);\n\n // Test with non-localhost URLs\n expect(isLocalhost(\"https://example.com\")).toBe(false);\n expect(isLocalhost(\"http://192.168.1.1\")).toBe(false);\n expect(isLocalhost(\"http://10.0.0.1\")).toBe(false);\n\n // Test with URL objects\n expect(isLocalhost(new URL(\"http://localhost\"))).toBe(true);\n expect(isLocalhost(new URL(\"https://example.com\"))).toBe(false);\n\n // Test with invalid URLs\n expect(isLocalhost(\"not a url\")).toBe(false);\n expect(isLocalhost(\"\")).toBe(false);\n});\n\nexport function isRelative(url: string) {\n const randomDomain = `${generateSecureRandomString()}.stack-auth.example.com`;\n const u = createUrlIfValid(url, `https://${randomDomain}`);\n if (!u) return false;\n if (u.host !== randomDomain) return false;\n if (u.protocol !== \"https:\") return false;\n return true;\n}\nundefined?.test(\"isRelative\", ({ expect }) => {\n // We can't easily mock generateSecureRandomString in this context\n // but we can still test the function's behavior\n\n // Test with relative URLs\n expect(isRelative(\"/\")).toBe(true);\n expect(isRelative(\"/path\")).toBe(true);\n expect(isRelative(\"/path?query=value#hash\")).toBe(true);\n\n // Test with absolute URLs\n expect(isRelative(\"https://example.com\")).toBe(false);\n expect(isRelative(\"http://example.com\")).toBe(false);\n expect(isRelative(\"//example.com\")).toBe(false);\n\n // Note: The implementation treats empty strings and invalid URLs as relative\n // This is because they can be resolved against a base URL\n expect(isRelative(\"\")).toBe(true);\n expect(isRelative(\"not a url\")).toBe(true);\n});\n\nexport function getRelativePart(url: URL) {\n return url.pathname + url.search + url.hash;\n}\nundefined?.test(\"getRelativePart\", ({ expect }) => {\n // Test with various URLs\n expect(getRelativePart(new URL(\"https://example.com\"))).toBe(\"/\");\n expect(getRelativePart(new URL(\"https://example.com/path\"))).toBe(\"/path\");\n expect(getRelativePart(new URL(\"https://example.com/path?query=value\"))).toBe(\"/path?query=value\");\n expect(getRelativePart(new URL(\"https://example.com/path#hash\"))).toBe(\"/path#hash\");\n expect(getRelativePart(new URL(\"https://example.com/path?query=value#hash\"))).toBe(\"/path?query=value#hash\");\n\n // Test with different domains but same paths\n const url1 = new URL(\"https://example.com/path?query=value#hash\");\n const url2 = new URL(\"https://different.com/path?query=value#hash\");\n expect(getRelativePart(url1)).toBe(getRelativePart(url2));\n});\n\n/**\n * A template literal tag that returns a URL.\n *\n * Any values passed are encoded.\n */\nexport function url(strings: TemplateStringsArray | readonly string[], ...values: (string|number|boolean)[]): URL {\n return new URL(urlString(strings, ...values));\n}\nundefined?.test(\"url\", ({ expect }) => {\n // Test with no interpolation\n expect(url`https://example.com`).toBeInstanceOf(URL);\n expect(url`https://example.com`.href).toBe(\"https://example.com/\");\n\n // Test with string interpolation\n expect(url`https://example.com/${\"path\"}`).toBeInstanceOf(URL);\n expect(url`https://example.com/${\"path\"}`.pathname).toBe(\"/path\");\n\n // Test with number interpolation\n expect(url`https://example.com/${42}`).toBeInstanceOf(URL);\n expect(url`https://example.com/${42}`.pathname).toBe(\"/42\");\n\n // Test with boolean interpolation\n expect(url`https://example.com/${true}`).toBeInstanceOf(URL);\n expect(url`https://example.com/${true}`.pathname).toBe(\"/true\");\n\n // Test with special characters in interpolation\n expect(url`https://example.com/${\"path with spaces\"}`).toBeInstanceOf(URL);\n expect(url`https://example.com/${\"path with spaces\"}`.pathname).toBe(\"/path%20with%20spaces\");\n\n // Test with multiple interpolations\n expect(url`https://example.com/${\"path\"}?query=${\"value\"}`).toBeInstanceOf(URL);\n expect(url`https://example.com/${\"path\"}?query=${\"value\"}`.pathname).toBe(\"/path\");\n expect(url`https://example.com/${\"path\"}?query=${\"value\"}`.search).toBe(\"?query=value\");\n});\n\n\n/**\n * A template literal tag that returns a URL string.\n *\n * Any values passed are encoded.\n */\nexport function urlString(strings: TemplateStringsArray | readonly string[], ...values: (string|number|boolean)[]): string {\n return templateIdentity(strings, ...values.map(encodeURIComponent));\n}\nundefined?.test(\"urlString\", ({ expect }) => {\n // Test with no interpolation\n expect(urlString`https://example.com`).toBe(\"https://example.com\");\n\n // Test with string interpolation\n expect(urlString`https://example.com/${\"path\"}`).toBe(\"https://example.com/path\");\n\n // Test with number interpolation\n expect(urlString`https://example.com/${42}`).toBe(\"https://example.com/42\");\n\n // Test with boolean interpolation\n expect(urlString`https://example.com/${true}`).toBe(\"https://example.com/true\");\n\n // Test with special characters in interpolation\n expect(urlString`https://example.com/${\"path with spaces\"}`).toBe(\"https://example.com/path%20with%20spaces\");\n expect(urlString`https://example.com/${\"?&=\"}`).toBe(\"https://example.com/%3F%26%3D\");\n\n // Test with multiple interpolations\n expect(urlString`https://example.com/${\"path\"}?query=${\"value\"}`).toBe(\"https://example.com/path?query=value\");\n expect(urlString`https://example.com/${\"path\"}?query=${\"value with spaces\"}`).toBe(\"https://example.com/path?query=value%20with%20spaces\");\n});\n\n\n"],"mappings":"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","names":["url"]}
|