diff --git a/src/clean.ts b/src/clean.ts index f3acde4..7b78c13 100644 --- a/src/clean.ts +++ b/src/clean.ts @@ -1,34 +1,28 @@ -import { Context } from "@code-engine/types"; import { ono } from "ono"; -import { resolve } from "path"; import * as trash from "trash"; -import { NormalizedConfig } from "./normalize-config"; +import { FSPromises } from "./normalize-config"; /** * Cleans the destination directory by deleting all of its contents. */ -export function clean(config: NormalizedConfig) { - return async (context: Context): Promise => { - // Resolve the output path, relative to the config path and/or the CWD - let dir = resolve(context.cwd, config.path); - let exists = await directoryExists(dir, config); +export async function clean(dir: string, fs: FSPromises) { + let exists = await directoryExists(dir, fs); - if (exists) { - // Move the output directory to the OS trash. - // This is safer than permanently deleting it, - // and allows users to roll-back to previous output if they want. - await trash(dir, { glob: false }); - } - }; + if (exists) { + // Move the output directory to the OS trash. + // This is safer than permanently deleting it, + // and allows users to roll-back to previous output if they want. + await trash(dir, { glob: false }); + } } /** * Determines whether the specified directory exists. * An error is thrown if the path exists and is not a directory. */ -async function directoryExists(dir: string, config: NormalizedConfig): Promise { +async function directoryExists(dir: string, fs: FSPromises): Promise { try { - let stats = await config.fs.promises.stat(dir); + let stats = await fs.promises.stat(dir); if (stats.isDirectory()) { // The directory exists diff --git a/src/index.ts b/src/index.ts index 429d6e0..b4f0728 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,22 +1,4 @@ -import { Plugin } from "@code-engine/types"; -import { clean } from "./clean"; -import { FileSystemConfig } from "./config"; -import { normalizeConfig } from "./normalize-config"; -import { processFile } from "./process-file"; - -/** - * A CodeEngine plugin that writes files to the filesystem. - */ -function filesystem(conf?: FileSystemConfig): Plugin { - let config = normalizeConfig(conf); - - return { - name: "Filesystem Destination", - filter: config.filter, - processFile: processFile(config), - clean: clean(config), - }; -} +import { filesystem } from "./plugin"; // Named exports export * from "./config"; diff --git a/src/plugin.ts b/src/plugin.ts new file mode 100644 index 0000000..04d3262 --- /dev/null +++ b/src/plugin.ts @@ -0,0 +1,39 @@ +import { File, Plugin, Run } from "@code-engine/types"; +import { resolve } from "path"; +import { clean } from "./clean"; +import { FileSystemConfig } from "./config"; +import { normalizeConfig } from "./normalize-config"; +import { writeFile } from "./write-file"; + +/** + * A CodeEngine plugin that writes files to the filesystem. + */ +export function filesystem(conf?: FileSystemConfig): Plugin { + let config = normalizeConfig(conf); + let dir: string; + + return { + name: "Filesystem Destination", + + filter: config.filter, + + initialize() { + // Resolve the output directory, relative to the CodeEngine CWD + dir = resolve(this.engine.cwd, config.path); + }, + + /** + * Writes a file to the filesystem, creating parent directories if needed. + */ + async processFile(file: File, run: Run) { + await writeFile(dir, file, config.fs); + }, + + /** + * Cleans the destination directory by deleting all of its contents. + */ + async clean() { + await clean(dir, config.fs); + }, + }; +} diff --git a/src/process-file.ts b/src/write-file.ts similarity index 51% rename from src/process-file.ts rename to src/write-file.ts index e58052d..194c3a2 100644 --- a/src/process-file.ts +++ b/src/write-file.ts @@ -1,43 +1,32 @@ -import { Context, File, FileProcessor } from "@code-engine/types"; +import { File } from "@code-engine/types"; import { dirname, resolve } from "path"; -import { FSPromises, NormalizedConfig } from "./normalize-config"; +import { FSPromises } from "./normalize-config"; /** - * Writes a file to the filesystem. + * Writes the given contents to the specified file path, creating the parent directories if needed. * * This method is called in parallel by CodeEngine based on the `concurrency` setting. * All filesystem IO in Node.js is done via the LibUV thread pool, which defaults to 4 threads. * This means that the number of concurrent file writes is the MINIMUM of CodeEngine's `concurrency` * setting and LibUV's thread pool size. */ -export function processFile(config: NormalizedConfig): FileProcessor { - return async (file: File, context: Context): Promise => { - // Resolve the output path, relative to the config path and/or the CWD - let path = resolve(context.cwd, config.path, file.path); - - await writeFile(path, file.contents, config.fs); - return file; - }; -} +export async function writeFile(baseDir: string, file: File, fs: FSPromises, retry = true): Promise { + let absolutePath = resolve(baseDir, file.path); -/** - * Writes the given contents to the specified file path, creating the parent directories if needed. - */ -async function writeFile(path: string, contents: Buffer, fs: FSPromises, retry = true): Promise { try { // Try to write the file - await fs.promises.writeFile(path, contents, { flag: "w" }); + await fs.promises.writeFile(absolutePath, file.contents, { flag: "w" }); } catch (e) { let error = e as NodeJS.ErrnoException; if (error && retry && error.code === "ENOENT") { // The directory path doesn't exist, so create it - let dir = dirname(path); + let dir = dirname(absolutePath); await fs.promises.mkdir(dir, { recursive: true }); // Now try again to write the file - await writeFile(path, contents, fs, false); + await fs.promises.writeFile(absolutePath, file.contents, { flag: "w" }); } else { throw error;