snapshot-fs
Version:
Create a filesystem snapshot for use with memfs
1 lines • 8.9 kB
Source Map (JSON)
{"version":3,"file":"read.js","sourceRoot":"","sources":["../src/read.ts"],"names":[],"mappings":"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","sourcesContent":["import { type DirectoryJSON, memfs } from 'memfs';\nimport {\n fromBinarySnapshot,\n fromJsonSnapshot,\n type JsonUint8Array,\n type SnapshotNode,\n toBinarySnapshot,\n} from 'memfs/lib/snapshot/index.js';\n\nimport { type CreateSnapshotOptions, type FsApi } from './snapshot.js';\nimport { type CborUint8Array } from './types.js';\n\n/**\n * Options for {@link readSnapshot}\n */\nexport type ReadSnapshotOptions = CreateSnapshotOptions;\n\n/**\n * Get the type of snapshot data for a given snapshot kind\n * @template K Snapshot kind\n */\nexport type SnapshotForKind<K extends SnapshotKind> = K extends typeof CBOR_KIND\n ? CborUint8Array<SnapshotNode>\n : K extends typeof CJSON_KIND\n ? JsonUint8Array<SnapshotNode>\n : K extends typeof JSON_KIND\n ? string | Uint8Array\n : never;\n\n/**\n * Three (3) types of \"snapshots\" are supported:\n * - `cbor`: A CBOR-encoded snapshot\n * - `cjson`: A \"compact\" JSON-encoded snapshot\n * - `json`: A DirectoryJSON snapshot-ish data structure (lossy)\n */\nexport type SnapshotKind =\n | typeof CBOR_KIND\n | typeof CJSON_KIND\n | typeof JSON_KIND;\n\n/**\n * CBOR snapshot kind\n */\nexport const CBOR_KIND = 'cbor';\n\n/**\n * Compact JSON snapshot kind\n */\nexport const CJSON_KIND = 'cjson';\n\n/**\n * {@link DirectoryJSON} snapshot kind\n */\nexport const JSON_KIND = 'json';\n\n/**\n * Reads a CBOR-encoded snapshot and populates a virtual file system.\n *\n * @param data - The CBOR-encoded data representing the snapshot.\n * @param options - Options for reading the snapshot.\n * @param options.fs - The file system to populate. Defaults to an in-memory file system.\n * @param options.separator - The path separator to use.\n * @param options.source - The root path of the source.\n * @returns A promise that resolves to the populated file system API.\n */\nexport async function readCBORSnapshot(\n data: CborUint8Array<SnapshotNode>,\n { fs = memfs().vol, separator, source: root }: ReadSnapshotOptions = {},\n): Promise<FsApi> {\n await fromBinarySnapshot(data, {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n fs: fs.promises as any,\n path: root,\n separator,\n });\n return fs;\n}\n\n/**\n * Reads a CJSON snapshot and populates a filesystem with its contents.\n *\n * @param data - The JSON data representing the snapshot.\n * @param options - Options for reading the snapshot.\n * @param options.fs - The filesystem to populate. Defaults to an in-memory filesystem.\n * @param options.separator - The path separator to use.\n * @param options.source - The root path for the filesystem.\n * @returns A promise that resolves to the populated filesystem API.\n */\nexport async function readCJSONSnapshot(\n data: JsonUint8Array<SnapshotNode>,\n { fs = memfs().vol, separator, source: root }: ReadSnapshotOptions = {},\n): Promise<FsApi> {\n await fromJsonSnapshot(data, {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n fs: fs.promises as any,\n path: root,\n separator,\n });\n return fs;\n}\n\n/**\n * Reads a directory JSON snapshot and populates a filesystem with its contents.\n *\n * @param data - The JSON data representing the directory structure. Can be a string or Uint8Array.\n * @param options - Options for reading the snapshot.\n * @param options.fs - The filesystem to populate. If not provided, a new in-memory filesystem will be created.\n * @param options.separator - The path separator to use.\n * @param options.source - The root path for the source filesystem.\n *\n * @returns A promise that resolves to the populated filesystem.\n *\n * @throws Will throw an error if the JSON data is invalid.\n */\nexport async function readDirectoryJSONSnapshot(\n data: string | Uint8Array,\n { fs, separator, source: root }: ReadSnapshotOptions = {},\n): Promise<FsApi> {\n const dirJson = (\n typeof data === 'string'\n ? JSON.parse(data)\n : JSON.parse(new TextDecoder().decode(data))\n ) as DirectoryJSON;\n const { vol } = memfs();\n vol.fromJSON(dirJson);\n // if the user wanted a new filesystem, we're done.\n if (!fs) {\n return vol;\n }\n // otherwise we need to create a snapshot from the temp filesystem,\n // then write it out to the real filesystem (which may be real or virtual).\n // unfortunately there is no such `fs.fromJSON()` method :D\n try {\n // CBOR is faster and smaller than CJSON\n const snapshot = await toBinarySnapshot({ fs: vol.promises, separator });\n await fromBinarySnapshot(snapshot, {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n fs: fs.promises as any,\n path: root,\n separator,\n });\n } finally {\n vol.reset();\n }\n return fs;\n}\n\n/**\n * Reads a snapshot into a new virtual filesystem or existing filesystem\n *\n * @param data Raw snapshot data in `DirectoryJSON`, CSJON or CBOR format\n * @param options Options\n * @returns The value of `options.fs` populated with the snapshot contents, or a new `memfs` `Volume`.\n */\nexport async function readSnapshot<\n K extends SnapshotKind,\n T extends SnapshotForKind<K>,\n>(kind: K, data: T, options?: ReadSnapshotOptions): Promise<FsApi> {\n await Promise.resolve();\n switch (kind) {\n case CBOR_KIND: {\n try {\n return await readCBORSnapshot(\n data as CborUint8Array<SnapshotNode>,\n options,\n );\n } catch (err) {\n throw new Error(\n `Failed to read snapshot as ${kind}: ${(err as Error).message}`,\n );\n }\n }\n case CJSON_KIND: {\n try {\n return await readCJSONSnapshot(\n data as JsonUint8Array<SnapshotNode>,\n options,\n );\n } catch (err) {\n throw new Error(\n `Failed to read snapshot as ${kind}: ${(err as Error).message}`,\n );\n }\n }\n case JSON_KIND: {\n try {\n return await readDirectoryJSONSnapshot(data as Uint8Array, options);\n } catch (err) {\n throw new Error(\n `Failed to read snapshot as ${kind}: ${(err as Error).message}`,\n );\n }\n }\n default:\n throw new TypeError(`Unknown snapshot kind: ${kind}`);\n }\n}\n"]}