|
| 1 | +/* |
| 2 | + * Copyright (c) 2023, salesforce.com, inc. |
| 3 | + * All rights reserved. |
| 4 | + * Licensed under the BSD 3-Clause license. |
| 5 | + * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause |
| 6 | + */ |
| 7 | +import type * as nodeFs from 'node:fs'; |
| 8 | +import type { IFs as MemFs } from 'memfs'; |
| 9 | + |
| 10 | +// Get the types for both node:fs and memfs |
| 11 | +type NodeFs = typeof nodeFs; |
| 12 | + |
| 13 | +// Find keys that exist in both types |
| 14 | +type CommonKeys<T, U> = keyof T & keyof U; |
| 15 | + |
| 16 | +// Create intersection type - be more specific for compatible methods |
| 17 | +type IntersectionType<T, U> = { |
| 18 | + // eslint-disable-next-line @typescript-eslint/no-explicit-any |
| 19 | + [K in CommonKeys<T, U>]: T[K] extends (...args: any[]) => any |
| 20 | + ? T[K] extends U[K] |
| 21 | + ? T[K] // If signatures are compatible, use the more specific type |
| 22 | + : U[K] extends T[K] |
| 23 | + ? U[K] // If memfs signature is more specific, use that |
| 24 | + : // eslint-disable-next-line @typescript-eslint/no-explicit-any |
| 25 | + any // Only use any for genuinely incompatible signatures |
| 26 | + : T[K] extends U[K] |
| 27 | + ? T[K] |
| 28 | + : U[K] extends T[K] |
| 29 | + ? U[K] |
| 30 | + : T[K]; // Default to node:fs for non-functions |
| 31 | +}; |
| 32 | + |
| 33 | +// Base intersection type |
| 34 | +type BaseVirtualFs = IntersectionType<NodeFs, MemFs>; |
| 35 | + |
| 36 | +// VirtualFs with specific overrides for methods we know the behavior of |
| 37 | +export type VirtualFs = Omit< |
| 38 | + BaseVirtualFs, |
| 39 | + 'writeFileSync' | 'readFileSync' | 'statSync' | 'promises' | 'mkdtempSync' | 'createWriteStream' | 'mkdirSync' |
| 40 | +> & { |
| 41 | + // Override promises object with specific types for methods we override |
| 42 | + promises: Omit<BaseVirtualFs['promises'], 'writeFile' | 'readFile'> & { |
| 43 | + writeFile: ( |
| 44 | + file: string, |
| 45 | + data: string | Buffer, |
| 46 | + options?: BufferEncoding | { encoding?: BufferEncoding; mode?: string | number } |
| 47 | + ) => Promise<void>; |
| 48 | + readFile: { |
| 49 | + (path: string): Promise<Buffer>; |
| 50 | + (path: string, encoding: BufferEncoding): Promise<string>; |
| 51 | + }; |
| 52 | + }; |
| 53 | + |
| 54 | + // Override sync methods with specific types |
| 55 | + readFileSync: { |
| 56 | + (path: string): Buffer; |
| 57 | + (path: string, encoding: BufferEncoding): string; |
| 58 | + }; |
| 59 | + writeFileSync: (file: string, data: string | Buffer, encoding?: BufferEncoding) => void; |
| 60 | + /** there are some differences between node:fs and memfs for statSync around bigint stats. Be careful if using those */ |
| 61 | + statSync: typeof nodeFs.statSync; |
| 62 | + mkdtempSync: typeof nodeFs.mkdtempSync; |
| 63 | + createWriteStream: typeof nodeFs.createWriteStream; |
| 64 | + mkdirSync: typeof nodeFs.mkdirSync; |
| 65 | +}; |
0 commit comments