@tldraw/utils
Version:
tldraw infinite canvas SDK (private utilities).
8 lines (7 loc) • 9.23 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../src/lib/control.ts"],
"sourcesContent": ["import { omitFromStackTrace } from './function'\n\n/**\n * Represents a successful result containing a value.\n *\n * Interface for the success case of a Result type, containing the computed value.\n * Used in conjunction with ErrorResult to create a discriminated union for error handling.\n *\n * @example\n * ```ts\n * const success: OkResult<string> = { ok: true, value: 'Hello World' }\n * if (success.ok) {\n * console.log(success.value) // 'Hello World'\n * }\n * ```\n * @public\n */\nexport interface OkResult<T> {\n\treadonly ok: true\n\treadonly value: T\n}\n/**\n * Represents a failed result containing an error.\n *\n * Interface for the error case of a Result type, containing the error information.\n * Used in conjunction with OkResult to create a discriminated union for error handling.\n *\n * @example\n * ```ts\n * const failure: ErrorResult<string> = { ok: false, error: 'Something went wrong' }\n * if (!failure.ok) {\n * console.error(failure.error) // 'Something went wrong'\n * }\n * ```\n * @public\n */\nexport interface ErrorResult<E> {\n\treadonly ok: false\n\treadonly error: E\n}\n/**\n * A discriminated union type for handling success and error cases.\n *\n * Represents either a successful result with a value or a failed result with an error.\n * This pattern provides type-safe error handling without throwing exceptions. The 'ok' property\n * serves as the discriminant for type narrowing.\n *\n * @example\n * ```ts\n * function divide(a: number, b: number): Result<number, string> {\n * if (b === 0) {\n * return Result.err('Division by zero')\n * }\n * return Result.ok(a / b)\n * }\n *\n * const result = divide(10, 2)\n * if (result.ok) {\n * console.log(`Result: ${result.value}`) // Result: 5\n * } else {\n * console.error(`Error: ${result.error}`)\n * }\n * ```\n * @public\n */\nexport type Result<T, E> = OkResult<T> | ErrorResult<E>\n\n/**\n * Utility object for creating Result instances.\n *\n * Provides factory methods for creating OkResult and ErrorResult instances.\n * This is the preferred way to construct Result values for consistent structure.\n *\n * @example\n * ```ts\n * // Create success result\n * const success = Result.ok(42)\n * // success: OkResult<number> = { ok: true, value: 42 }\n *\n * // Create error result\n * const failure = Result.err('Invalid input')\n * // failure: ErrorResult<string> = { ok: false, error: 'Invalid input' }\n * ```\n * @public\n */\nexport const Result = {\n\t/**\n\t * Create a successful result containing a value.\n\t *\n\t * @param value - The success value to wrap\n\t * @returns An OkResult containing the value\n\t */\n\tok<T>(value: T): OkResult<T> {\n\t\treturn { ok: true, value }\n\t},\n\t/**\n\t * Create a failed result containing an error.\n\t *\n\t * @param error - The error value to wrap\n\t * @returns An ErrorResult containing the error\n\t */\n\terr<E>(error: E): ErrorResult<E> {\n\t\treturn { ok: false, error }\n\t},\n}\n\n/**\n * Throws an error for unhandled switch cases in exhaustive switch statements.\n *\n * Utility function to ensure exhaustive handling of discriminated unions in switch\n * statements. When called, it indicates a programming error where a case was not handled.\n * The TypeScript 'never' type ensures this function is only reachable if all cases aren't covered.\n *\n * @param value - The unhandled value (typed as 'never' for exhaustiveness checking)\n * @param property - Optional property name to extract from the value for better error messages\n * @returns Never returns (always throws)\n *\n * @example\n * ```ts\n * type Shape = 'circle' | 'square' | 'triangle'\n *\n * function getArea(shape: Shape): number {\n * switch (shape) {\n * case 'circle': return Math.PI * 5 * 5\n * case 'square': return 10 * 10\n * case 'triangle': return 0.5 * 10 * 8\n * default: return exhaustiveSwitchError(shape)\n * }\n * }\n * ```\n * @internal\n */\nexport function exhaustiveSwitchError(value: never, property?: string): never {\n\tconst debugValue =\n\t\tproperty && value && typeof value === 'object' && property in value ? value[property] : value\n\tthrow new Error(`Unknown switch case ${debugValue}`)\n}\n\n/**\n * Assert that a value is truthy, throwing an error if it's not.\n *\n * TypeScript assertion function that throws an error if the provided value is falsy.\n * After this function executes successfully, TypeScript narrows the type to exclude falsy values.\n * Stack trace is omitted from the error for cleaner debugging.\n *\n * @param value - The value to assert as truthy\n * @param message - Optional custom error message\n *\n * @example\n * ```ts\n * const user = getUser() // User | null\n * assert(user, 'User must be logged in')\n * // TypeScript now knows user is non-null\n * console.log(user.name) // Safe to access properties\n * ```\n * @internal\n */\nexport const assert: (value: unknown, message?: string) => asserts value = omitFromStackTrace(\n\t(value, message) => {\n\t\tif (!value) {\n\t\t\tthrow new Error(message || 'Assertion Error')\n\t\t}\n\t}\n)\n\n/**\n * Assert that a value is not null or undefined.\n *\n * Throws an error if the value is null or undefined, otherwise returns the value\n * with a refined type that excludes null and undefined. Stack trace is omitted for cleaner debugging.\n *\n * @param value - The value to check for null/undefined\n * @param message - Optional custom error message\n * @returns The value with null and undefined excluded from the type\n *\n * @example\n * ```ts\n * const element = document.getElementById('my-id') // HTMLElement | null\n * const safeElement = assertExists(element, 'Element not found')\n * // TypeScript now knows safeElement is HTMLElement (not null)\n * safeElement.addEventListener('click', handler) // Safe to call methods\n * ```\n * @internal\n */\nexport const assertExists = omitFromStackTrace(<T>(value: T, message?: string): NonNullable<T> => {\n\t// note that value == null is equivalent to value === null || value === undefined\n\tif (value == null) {\n\t\tthrow new Error(message ?? 'value must be defined')\n\t}\n\treturn value as NonNullable<T>\n})\n\n/**\n * Create a Promise with externally accessible resolve and reject functions.\n *\n * Creates a Promise along with its resolve and reject functions exposed as\n * properties on the returned object. This allows external code to control when the\n * Promise resolves or rejects, useful for coordination between async operations.\n *\n * @returns A Promise object with additional resolve and reject methods\n *\n * @example\n * ```ts\n * const deferred = promiseWithResolve<string>()\n *\n * // Set up the promise consumer\n * deferred.then(value => console.log(`Resolved: ${value}`))\n * deferred.catch(error => console.error(`Rejected: ${error}`))\n *\n * // Later, resolve from external code\n * setTimeout(() => {\n * deferred.resolve('Hello World')\n * }, 1000)\n * ```\n * @internal\n */\nexport function promiseWithResolve<T>(): Promise<T> & {\n\tresolve(value: T): void\n\treject(reason?: any): void\n} {\n\tlet resolve: (value: T) => void\n\tlet reject: (reason?: any) => void\n\tconst promise = new Promise<T>((res, rej) => {\n\t\tresolve = res\n\t\treject = rej\n\t})\n\treturn Object.assign(promise, {\n\t\tresolve: resolve!,\n\t\treject: reject!,\n\t})\n}\n\n/**\n * Create a Promise that resolves after a specified delay.\n *\n * Utility function for introducing delays in async code. Returns a Promise\n * that resolves with undefined after the specified number of milliseconds. Useful for\n * implementing timeouts, rate limiting, or adding delays in testing scenarios.\n *\n * @param ms - The delay in milliseconds\n * @returns A Promise that resolves after the specified delay\n *\n * @example\n * ```ts\n * async function delayedOperation() {\n * console.log('Starting...')\n * await sleep(1000) // Wait 1 second\n * console.log('Done!')\n * }\n *\n * // Can also be used with .then()\n * sleep(500).then(() => {\n * console.log('Half second has passed')\n * })\n * ```\n * @internal\n */\nexport function sleep(ms: number): Promise<void> {\n\t// eslint-disable-next-line no-restricted-globals\n\treturn new Promise((resolve) => setTimeout(resolve, ms))\n}\n"],
"mappings": "AAAA,SAAS,0BAA0B;AAqF5B,MAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOrB,GAAM,OAAuB;AAC5B,WAAO,EAAE,IAAI,MAAM,MAAM;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAO,OAA0B;AAChC,WAAO,EAAE,IAAI,OAAO,MAAM;AAAA,EAC3B;AACD;AA4BO,SAAS,sBAAsB,OAAc,UAA0B;AAC7E,QAAM,aACL,YAAY,SAAS,OAAO,UAAU,YAAY,YAAY,QAAQ,MAAM,QAAQ,IAAI;AACzF,QAAM,IAAI,MAAM,uBAAuB,UAAU,EAAE;AACpD;AAqBO,MAAM,SAA8D;AAAA,EAC1E,CAAC,OAAO,YAAY;AACnB,QAAI,CAAC,OAAO;AACX,YAAM,IAAI,MAAM,WAAW,iBAAiB;AAAA,IAC7C;AAAA,EACD;AACD;AAqBO,MAAM,eAAe,mBAAmB,CAAI,OAAU,YAAqC;AAEjG,MAAI,SAAS,MAAM;AAClB,UAAM,IAAI,MAAM,WAAW,uBAAuB;AAAA,EACnD;AACA,SAAO;AACR,CAAC;AA0BM,SAAS,qBAGd;AACD,MAAI;AACJ,MAAI;AACJ,QAAM,UAAU,IAAI,QAAW,CAAC,KAAK,QAAQ;AAC5C,cAAU;AACV,aAAS;AAAA,EACV,CAAC;AACD,SAAO,OAAO,OAAO,SAAS;AAAA,IAC7B;AAAA,IACA;AAAA,EACD,CAAC;AACF;AA2BO,SAAS,MAAM,IAA2B;AAEhD,SAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AACxD;",
"names": []
}