| 23 | } |
| 24 | |
| 25 | function unpack( |
| 26 | arr: unknown[], |
| 27 | hydrated: unknown[], |
| 28 | idx: number, |
| 29 | custom: CustomParser | undefined, |
| 30 | ): unknown { |
| 31 | switch (idx) { |
| 32 | case UNDEFINED: |
| 33 | return undefined; |
| 34 | case NULL: |
| 35 | return null; |
| 36 | case NAN: |
| 37 | return NaN; |
| 38 | case INFINITY_POS: |
| 39 | return Infinity; |
| 40 | case INFINITY_NEG: |
| 41 | return -Infinity; |
| 42 | case ZERO_NEG: |
| 43 | return -0; |
| 44 | } |
| 45 | |
| 46 | if (idx in hydrated) return hydrated[idx]; |
| 47 | |
| 48 | const current = arr[idx]; |
| 49 | if (typeof current === "number") { |
| 50 | return hydrated[idx] = current; |
| 51 | } else if ( |
| 52 | typeof current === "string" || typeof current === "boolean" || |
| 53 | current === null |
| 54 | ) { |
| 55 | return hydrated[idx] = current; |
| 56 | } else if (Array.isArray(current)) { |
| 57 | if (current.length > 0 && typeof current[0] === "string") { |
| 58 | const name = current[0]; |
| 59 | if (custom !== undefined && name in custom) { |
| 60 | const fn = custom[name]; |
| 61 | const ref = current[1]; |
| 62 | const value = unpack(arr, hydrated, ref, custom); |
| 63 | return hydrated[idx] = fn(value); |
| 64 | } |
| 65 | switch (name) { |
| 66 | case "BigInt": |
| 67 | return hydrated[idx] = BigInt(current[1]); |
| 68 | case "URL": |
| 69 | return hydrated[idx] = new URL(current[1]); |
| 70 | case "Date": |
| 71 | return hydrated[idx] = new Date(current[1]); |
| 72 | case "RegExp": |
| 73 | return hydrated[idx] = new RegExp(current[1], current[2]); |
| 74 | case "Set": { |
| 75 | const set = new Set(); |
| 76 | for (let i = 0; i < current[1].length; i++) { |
| 77 | const ref = current[1][i]; |
| 78 | set.add(unpack(arr, hydrated, ref, custom)); |
| 79 | } |
| 80 | return hydrated[idx] = set; |
| 81 | } |
| 82 | case "Map": { |