@softwareventures/maintain-project
Version:
Automatically create and maintain TypeScript projects with standard settings for Software Ventures Limited
91 lines • 3.28 kB
JavaScript
import { promises as fs } from "fs";
import { resolve } from "path";
import { chain } from "@softwareventures/chain";
import { mapFn } from "@softwareventures/iterable";
import { hasProperty } from "unknown";
import { liftPromises, liftResults, mapValue } from "../collections/maps.js";
import { failure, mapAsyncResultFn, mapResultFn, success } from "../result/result.js";
export async function commit(path, stage) {
return open(path, stage).then(mapAsyncResultFn(write));
}
async function open(path, stage) {
const { root, overwrite = false } = stage;
return openDirectory({ path, node: root, overwrite }).then(mapResultFn(openRoot => ({
type: "open-fs-stage",
path,
openRoot
})));
}
async function openDirectory(options) {
const { overwrite } = options;
try {
await fs.mkdir(options.path);
}
catch (reason) {
if (!hasProperty(reason, "code") || reason.code !== "EEXIST") {
throw reason;
}
else if (await fs.stat(options.path).then(stat => !stat.isDirectory())) {
return failure([{ type: "not-a-directory", path: options.path }]);
}
else if (!overwrite) {
return failure([{ type: "file-exists", path: options.path }]);
}
}
const openEntries = mapValue(options.node.entries, async (node, relativePath) => {
const path = resolve(options.path, relativePath);
switch (node.type) {
case "directory":
return openDirectory({ path, node, overwrite });
case "file":
return openFile({ path, node, overwrite });
}
});
return liftPromises(openEntries)
.then(liftResults)
.then(mapResultFn(entries => ({ type: "open-directory", entries })));
}
async function openFile(options) {
const flags = options.overwrite ? "r+" : "wx+";
return fs
.open(options.path, flags)
.catch(async (reason) => {
if (hasProperty(reason, "code") && reason.code === "ENOENT" && options.overwrite) {
return fs.open(options.path, "wx+");
}
else {
throw reason;
}
})
.then(fileHandle => success({ type: "open-file", fileHandle, data: options.node.data }), reason => {
if (hasProperty(reason, "code") && reason.code === "EEXIST") {
return failure([{ type: "file-exists", path: options.path }]);
}
else {
throw reason;
}
});
}
async function write(stage) {
return writeDirectory(stage.openRoot);
}
async function writeDirectory(directory) {
return chain(directory.entries.values())
.map(mapFn(async (node) => {
switch (node.type) {
case "open-directory":
return writeDirectory(node);
case "open-file":
return writeFile(node);
}
}))
.map(async (results) => Promise.all(results))
.map(async (promise) => promise.then(() => undefined)).value;
}
async function writeFile(file) {
return fs
.writeFile(file.fileHandle, file.data)
.then(async () => file.fileHandle.truncate(file.data.byteLength))
.then(async () => file.fileHandle.close());
}
//# sourceMappingURL=commit.js.map