diff options
Diffstat (limited to 'std/node/_fs/_fs_appendFile.ts')
-rw-r--r-- | std/node/_fs/_fs_appendFile.ts | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/std/node/_fs/_fs_appendFile.ts b/std/node/_fs/_fs_appendFile.ts new file mode 100644 index 000000000..962f44884 --- /dev/null +++ b/std/node/_fs/_fs_appendFile.ts @@ -0,0 +1,193 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { FileOptions, isFileOptions } from "./_fs_common.ts"; +import { notImplemented } from "../_utils.ts"; + +/** + * TODO: Also accept 'data' parameter as a Node polyfill Buffer type once this + * is implemented. See https://github.com/denoland/deno/issues/3403 + */ +export async function appendFile( + pathOrRid: string | number, + data: string, + optionsOrCallback: string | FileOptions | Function, + callback?: Function +): Promise<void> { + const callbackFn: Function | undefined = + optionsOrCallback instanceof Function ? optionsOrCallback : callback; + const options: string | FileOptions | undefined = + optionsOrCallback instanceof Function ? undefined : optionsOrCallback; + if (!callbackFn) { + throw new Error("No callback function supplied"); + } + + validateEncoding(options); + + let rid = -1; + try { + if (typeof pathOrRid === "number") { + rid = pathOrRid; + } else { + const mode: number | undefined = isFileOptions(options) + ? options.mode + : undefined; + const flag: string | undefined = isFileOptions(options) + ? options.flag + : undefined; + + if (mode) { + //TODO rework once https://github.com/denoland/deno/issues/4017 completes + notImplemented("Deno does not yet support setting mode on create"); + } + + const file = await Deno.open(pathOrRid, getOpenOptions(flag)); + rid = file.rid; + } + + const buffer: Uint8Array = new TextEncoder().encode(data); + + await Deno.write(rid, buffer); + callbackFn(); + } catch (err) { + callbackFn(err); + } finally { + if (typeof pathOrRid === "string" && rid != -1) { + //Only close if a path was supplied and a rid allocated + Deno.close(rid); + } + } +} + +/** + * TODO: Also accept 'data' parameter as a Node polyfill Buffer type once this + * is implemented. See https://github.com/denoland/deno/issues/3403 + */ +export function appendFileSync( + pathOrRid: string | number, + data: string, + options?: string | FileOptions +): void { + let rid = -1; + + validateEncoding(options); + + try { + if (typeof pathOrRid === "number") { + rid = pathOrRid; + } else { + const mode: number | undefined = isFileOptions(options) + ? options.mode + : undefined; + const flag: string | undefined = isFileOptions(options) + ? options.flag + : undefined; + + if (mode) { + // TODO rework once https://github.com/denoland/deno/issues/4017 completes + notImplemented("Deno does not yet support setting mode on create"); + } + + const file = Deno.openSync(pathOrRid, getOpenOptions(flag)); + rid = file.rid; + } + + const buffer: Uint8Array = new TextEncoder().encode(data); + + Deno.writeSync(rid, buffer); + } finally { + if (typeof pathOrRid === "string" && rid != -1) { + //Only close if a 'string' path was supplied and a rid allocated + Deno.close(rid); + } + } +} + +function validateEncoding( + encodingOption: string | FileOptions | undefined +): void { + if (!encodingOption) return; + + if (typeof encodingOption === "string") { + if (encodingOption !== "utf8") { + throw new Error("Only 'utf8' encoding is currently supported"); + } + } else if (encodingOption.encoding && encodingOption.encoding !== "utf8") { + throw new Error("Only 'utf8' encoding is currently supported"); + } +} + +function getOpenOptions(flag: string | undefined): Deno.OpenOptions { + if (!flag) { + return { create: true, append: true }; + } + + let openOptions: Deno.OpenOptions; + switch (flag) { + case "a": { + // 'a': Open file for appending. The file is created if it does not exist. + openOptions = { create: true, append: true }; + break; + } + case "ax": { + // 'ax': Like 'a' but fails if the path exists. + openOptions = { createNew: true, write: true, append: true }; + break; + } + case "a+": { + // 'a+': Open file for reading and appending. The file is created if it does not exist. + openOptions = { read: true, create: true, append: true }; + break; + } + case "ax+": { + // 'ax+': Like 'a+' but fails if the path exists. + openOptions = { read: true, createNew: true, append: true }; + break; + } + case "r": { + // 'r': Open file for reading. An exception occurs if the file does not exist. + openOptions = { read: true }; + break; + } + case "r+": { + // 'r+': Open file for reading and writing. An exception occurs if the file does not exist. + openOptions = { read: true, write: true }; + break; + } + case "w": { + // 'w': Open file for writing. The file is created (if it does not exist) or truncated (if it exists). + openOptions = { create: true, write: true, truncate: true }; + break; + } + case "wx": { + // 'wx': Like 'w' but fails if the path exists. + openOptions = { createNew: true, write: true }; + break; + } + case "w+": { + // 'w+': Open file for reading and writing. The file is created (if it does not exist) or truncated (if it exists). + openOptions = { create: true, write: true, truncate: true, read: true }; + break; + } + case "wx+": { + // 'wx+': Like 'w+' but fails if the path exists. + openOptions = { createNew: true, write: true, read: true }; + break; + } + case "as": { + // 'as': Open file for appending in synchronous mode. The file is created if it does not exist. + openOptions = { create: true, append: true }; + } + case "as+": { + // 'as+': Open file for reading and appending in synchronous mode. The file is created if it does not exist. + openOptions = { create: true, read: true, append: true }; + } + case "rs+": { + // 'rs+': Open file for reading and writing in synchronous mode. Instructs the operating system to bypass the local file system cache. + openOptions = { create: true, read: true, write: true }; + } + default: { + throw new Error(`Unrecognized file system flag: ${flag}`); + } + } + + return openOptions; +} |