sc4
Version:
A command line utility for automating SimCity 4 modding tasks & modifying savegames
88 lines (87 loc) • 2.62 kB
JavaScript
// # glob.browser.ts
// This module contains an implementation of the Node.js glob module, but then
// based on the Browser's file system api instead of using Node's fs module -
// which isn't available in the browser obviously.
import { Minimatch } from 'minimatch';
// # Glob
export class Glob {
pattern;
cwd;
constructor(pattern, opts) {
const patterns = Array.isArray(pattern) ? [...pattern] : [pattern];
this.cwd = opts.cwd;
const mmOptions = {
nocase: opts.nocase,
};
this.pattern = patterns.map((pattern) => {
return new Minimatch(pattern, mmOptions);
});
}
// ## *[Symbol.asyncIterator]()
async *[Symbol.asyncIterator]() {
yield* this.stream();
}
// ## stream()
// Loops over all the files as a stream. This is the base for all of our
// async functions.
stream() {
const glob = this;
const info = new FileInfo(this.cwd, '/');
return new ReadableStream({
async start(controller) {
const tasks = [];
await readdir(info, (info) => {
if (!glob.match(info.path))
return;
const { handle, kind } = info;
if (kind === 'file') {
const task = handle
.getFile()
.then((src) => {
controller.enqueue(new File([src], info.path));
});
tasks.push(task);
}
});
await Promise.all(tasks);
controller.close();
},
});
}
// ## async walk()
async walk() {
const files = [];
for await (let file of this) {
files.push(file);
}
return files;
}
// ## match()
match(path) {
return this.pattern.some((mm) => mm.match(path));
}
}
// # readdir()
async function readdir(info, cb) {
let tasks = [];
for await (let handle of info.handle.values()) {
let { name, kind } = handle;
let path = `${info.path}${name}${kind === 'directory' ? '/' : ''}`;
let child = new FileInfo(handle, path);
if (kind === 'directory') {
tasks.push(readdir(child, cb));
}
cb(child);
}
await Promise.all(tasks);
}
class FileInfo {
handle;
kind;
path;
constructor(handle, path) {
this.handle = handle;
this.kind = handle.kind;
this.path = path;
}
}