@zenfs/core
Version:
A filesystem, anywhere
89 lines (72 loc) • 2.38 kB
JavaScript
import { readdirSync, statSync, writeFileSync } from 'node:fs';
import { matchesGlob, relative, join, resolve } from 'node:path/posix';
import { parseArgs, styleText } from 'node:util';
const { values: options, positionals } = parseArgs({
options: {
help: { short: 'h', type: 'boolean', default: false },
ignore: { short: 'i', type: 'string', multiple: true, default: [] },
output: { short: 'o', type: 'string', default: 'index.json' },
quiet: { short: 'q', type: 'boolean', default: false },
verbose: { type: 'boolean', default: false },
},
allowPositionals: true,
});
const root = positionals.at(-1) || '.';
if (options.help) {
console.log(`make-index <path> [...options]
path: The path to create a listing for
options:
--help, -h Outputs this help message
--quiet, -q The command will not generate any output, including error messages.
--verbose Output verbose messages
--output, -o <path> Path to the output file. Defaults to listing.
--ignore, -i <pattern> Ignores files which match the glob <pattern>. Can be passed multiple times.
`);
process.exit();
}
if (options.quiet && options.verbose) {
console.log('Can not use both --verbose and --quiet.');
process.exit();
}
function fixSlash(path) {
return path.replaceAll('\\', '/');
}
const resolvedRoot = root || '.';
const entries = new Map();
function computeEntries(path) {
try {
if (options.ignore.some(pattern => matchesGlob(path, pattern))) {
if (!options.quiet) console.log(`${styleText('yellow', 'skip')} ${path}`);
return;
}
const stats = statSync(path);
if (stats.isFile()) {
entries.set('/' + relative(resolvedRoot, path), stats);
if (options.verbose) {
console.log(`${styleText('green', 'file')} ${path}`);
}
return;
}
for (const file of readdirSync(path)) {
computeEntries(join(path, file));
}
entries.set('/' + relative(resolvedRoot, path), stats);
if (options.verbose) {
console.log(`${styleText('greenBright', ' dir')} ${path}`);
}
} catch (e) {
if (!options.quiet) {
console.log(`${styleText('red', 'fail')} ${path}: ${e.message}`);
}
}
}
computeEntries(resolvedRoot);
if (!options.quiet) {
console.log('Generated listing for ' + fixSlash(resolve(root)));
}
const index = {
version: 1,
entries: Object.fromEntries(entries),
};
writeFileSync(options.output, JSON.stringify(index));