|
| 1 | +import { GenericFunction } from './types'; |
| 2 | + |
| 3 | +/** |
| 4 | + * Polyfill for the optional chain operator, `?.`, given previous conversion of the expression into an array of values, |
| 5 | + * descriptors, and functions, for situations in which at least one part of the expression is async. |
| 6 | + * |
| 7 | + * Adapted from Sucrase (https://github.com/alangpierce/sucrase) See |
| 8 | + * https://github.com/alangpierce/sucrase/blob/265887868966917f3b924ce38dfad01fbab1329f/src/transformers/OptionalChainingNullishTransformer.ts#L15 |
| 9 | + * |
| 10 | + * @param ops Array result of expression conversion |
| 11 | + * @returns The value of the expression |
| 12 | + */ |
| 13 | +// eslint-disable-next-line @sentry-internal/sdk/no-async-await |
| 14 | +export async function _asyncOptionalChain(ops: unknown[]): Promise<unknown> { |
| 15 | + let lastAccessLHS: unknown = undefined; |
| 16 | + let value = ops[0]; |
| 17 | + let i = 1; |
| 18 | + while (i < ops.length) { |
| 19 | + const op = ops[i] as string; |
| 20 | + const fn = ops[i + 1] as (intermediateValue: unknown) => Promise<unknown>; |
| 21 | + i += 2; |
| 22 | + // by checking for loose equality to `null`, we catch both `null` and `undefined` |
| 23 | + if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { |
| 24 | + // really we're meaning to return `undefined` as an actual value here, but it saves bytes not to write it |
| 25 | + return; |
| 26 | + } |
| 27 | + if (op === 'access' || op === 'optionalAccess') { |
| 28 | + lastAccessLHS = value; |
| 29 | + value = await fn(value); |
| 30 | + } else if (op === 'call' || op === 'optionalCall') { |
| 31 | + value = await fn((...args: unknown[]) => (value as GenericFunction).call(lastAccessLHS, ...args)); |
| 32 | + lastAccessLHS = undefined; |
| 33 | + } |
| 34 | + } |
| 35 | + return value; |
| 36 | +} |
| 37 | + |
| 38 | +// Sucrase version: |
| 39 | +// async function _asyncOptionalChain(ops) { |
| 40 | +// let lastAccessLHS = undefined; |
| 41 | +// let value = ops[0]; |
| 42 | +// let i = 1; |
| 43 | +// while (i < ops.length) { |
| 44 | +// const op = ops[i]; |
| 45 | +// const fn = ops[i + 1]; |
| 46 | +// i += 2; |
| 47 | +// if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { |
| 48 | +// return undefined; |
| 49 | +// } |
| 50 | +// if (op === 'access' || op === 'optionalAccess') { |
| 51 | +// lastAccessLHS = value; |
| 52 | +// value = await fn(value); |
| 53 | +// } else if (op === 'call' || op === 'optionalCall') { |
| 54 | +// value = await fn((...args) => value.call(lastAccessLHS, ...args)); |
| 55 | +// lastAccessLHS = undefined; |
| 56 | +// } |
| 57 | +// } |
| 58 | +// return value; |
| 59 | +// } |
0 commit comments