Created
March 1, 2024 20:50
-
-
Save boneskull/dd11a4d73024909299e26c95c85edc70 to your computer and use it in GitHub Desktop.
create memfs volume from filesystem
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
/* eslint-disable n/shebang */ | |
// @ts-check | |
/** | |
* Prints a `memfs` volume JSON from the filesystem given glob patterns and/or | |
* directories | |
* | |
* Directories are handled recursively | |
* | |
* Note: The memfs volume will be "squashed" to `cwd`, even if a glob pattern or | |
* directory is not an ancestor of `cwd`. | |
* | |
* @packageDocumentation | |
* @see {@link https://npm.im/memfs} | |
*/ | |
import { glob } from 'glob' | |
import { memfs } from 'memfs' | |
import { readFile } from 'node:fs/promises' | |
import path from 'node:path' | |
import { fileURLToPath } from 'node:url' | |
import { parseArgs } from 'node:util' | |
const MEMFS_ROOT = '/' | |
function showHelp() { | |
console.log(` | |
fs-to-volume [options..] [directory..] | |
Creates memfs volume JSON from the filesystem | |
Options: | |
--glob, -g - Glob patterns (can be used multiple times) | |
--help - Show this help message | |
--root - memfs root directory (default: '/') | |
`) | |
} | |
/** | |
* Creates a `memfs` `Volume` from the filesystem | |
* | |
* All paths will be computed relative to the current working directory. | |
* | |
* @param {string[]} dirs - Directories to include (recursively). If unspecified | |
* or empty, `cwd` is used | |
* @param {string[]} globPatterns - Glob patterns to include | |
* @param {string} root - Memfs root | |
* @returns {Promise<ReturnType<typeof memfs>['vol']>} | |
*/ | |
async function createVolumeFromFs( | |
dirs = [], | |
globPatterns = [], | |
root = MEMFS_ROOT | |
) { | |
if (!dirs.length) { | |
dirs.push('.') | |
} | |
// recursify dirs | |
const dirPatterns = dirs.map((pattern) => path.join(pattern, '**')) | |
const patterns = [...new Set([...dirPatterns, ...globPatterns])] | |
const files = await glob(patterns, { | |
// we don't actually need filetypes, but we want the PathScurry objects | |
withFileTypes: true, | |
// don't need dirs because memfs creates dir structure from relative | |
// filepaths | |
nodir: true, | |
root, | |
}) | |
/** @type {import('memfs').DirectoryJSON} */ | |
const json = {} | |
// instead of building a JSON object, we could actually use mkdir/writeFile, | |
// but that's slow | |
await Promise.all( | |
files.map(async (file) => { | |
// yes, this should work with binaries | |
const content = await readFile(file.fullpath()) | |
json[file.relativePosix()] = content | |
}) | |
) | |
const { vol } = memfs(json, root) | |
return vol | |
} | |
async function main() { | |
const { | |
positionals, | |
values: { help, glob: globPatterns = [], root = MEMFS_ROOT }, | |
} = parseArgs({ | |
allowPositionals: true, | |
options: { | |
glob: { | |
short: 'g', | |
type: 'string', | |
multiple: true, | |
default: [], | |
}, | |
root: { type: 'string', default: MEMFS_ROOT }, | |
help: { type: 'boolean' }, | |
}, | |
}) | |
if (help) { | |
showHelp() | |
return | |
} | |
const vol = await createVolumeFromFs(positionals, globPatterns, root) | |
console.log(JSON.stringify(vol.toJSON(), null, 2)) | |
} | |
// equiv of `require.main === module` | |
if (process.argv[1] === fileURLToPath(import.meta.url)) { | |
main().catch((err) => { | |
console.error(err) | |
process.exitCode = 1 | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment