summaryrefslogtreecommitdiff
path: root/ext/node/polyfills/_fs/_fs_writeFile.ts
diff options
context:
space:
mode:
Diffstat (limited to 'ext/node/polyfills/_fs/_fs_writeFile.ts')
-rw-r--r--ext/node/polyfills/_fs/_fs_writeFile.ts193
1 files changed, 193 insertions, 0 deletions
diff --git a/ext/node/polyfills/_fs/_fs_writeFile.ts b/ext/node/polyfills/_fs/_fs_writeFile.ts
new file mode 100644
index 000000000..3cad5f947
--- /dev/null
+++ b/ext/node/polyfills/_fs/_fs_writeFile.ts
@@ -0,0 +1,193 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+import { Encodings } from "internal:deno_node/polyfills/_utils.ts";
+import { fromFileUrl } from "internal:deno_node/polyfills/path.ts";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import {
+ CallbackWithError,
+ checkEncoding,
+ getEncoding,
+ getOpenOptions,
+ isFileOptions,
+ WriteFileOptions,
+} from "internal:deno_node/polyfills/_fs/_fs_common.ts";
+import { isWindows } from "internal:deno_node/polyfills/_util/os.ts";
+import {
+ AbortError,
+ denoErrorToNodeError,
+} from "internal:deno_node/polyfills/internal/errors.ts";
+import {
+ showStringCoercionDeprecation,
+ validateStringAfterArrayBufferView,
+} from "internal:deno_node/polyfills/internal/fs/utils.mjs";
+import { promisify } from "internal:deno_node/polyfills/internal/util.mjs";
+
+interface Writer {
+ write(p: Uint8Array): Promise<number>;
+}
+
+export function writeFile(
+ pathOrRid: string | number | URL,
+ // deno-lint-ignore ban-types
+ data: string | Uint8Array | Object,
+ optOrCallback: Encodings | CallbackWithError | WriteFileOptions | undefined,
+ callback?: CallbackWithError,
+) {
+ const callbackFn: CallbackWithError | undefined =
+ optOrCallback instanceof Function ? optOrCallback : callback;
+ const options: Encodings | WriteFileOptions | undefined =
+ optOrCallback instanceof Function ? undefined : optOrCallback;
+
+ if (!callbackFn) {
+ throw new TypeError("Callback must be a function.");
+ }
+
+ pathOrRid = pathOrRid instanceof URL ? fromFileUrl(pathOrRid) : pathOrRid;
+
+ const flag: string | undefined = isFileOptions(options)
+ ? options.flag
+ : undefined;
+
+ const mode: number | undefined = isFileOptions(options)
+ ? options.mode
+ : undefined;
+
+ const encoding = checkEncoding(getEncoding(options)) || "utf8";
+ const openOptions = getOpenOptions(flag || "w");
+
+ if (!ArrayBuffer.isView(data)) {
+ validateStringAfterArrayBufferView(data, "data");
+ if (typeof data !== "string") {
+ showStringCoercionDeprecation();
+ }
+ data = Buffer.from(String(data), encoding);
+ }
+
+ const isRid = typeof pathOrRid === "number";
+ let file;
+
+ let error: Error | null = null;
+ (async () => {
+ try {
+ file = isRid
+ ? new Deno.FsFile(pathOrRid as number)
+ : await Deno.open(pathOrRid as string, openOptions);
+
+ // ignore mode because it's not supported on windows
+ // TODO(@bartlomieju): remove `!isWindows` when `Deno.chmod` is supported
+ if (!isRid && mode && !isWindows) {
+ await Deno.chmod(pathOrRid as string, mode);
+ }
+
+ const signal: AbortSignal | undefined = isFileOptions(options)
+ ? options.signal
+ : undefined;
+ await writeAll(file, data as Uint8Array, { signal });
+ } catch (e) {
+ error = e instanceof Error
+ ? denoErrorToNodeError(e, { syscall: "write" })
+ : new Error("[non-error thrown]");
+ } finally {
+ // Make sure to close resource
+ if (!isRid && file) file.close();
+ callbackFn(error);
+ }
+ })();
+}
+
+export const writeFilePromise = promisify(writeFile) as (
+ pathOrRid: string | number | URL,
+ // deno-lint-ignore ban-types
+ data: string | Uint8Array | Object,
+ options?: Encodings | WriteFileOptions,
+) => Promise<void>;
+
+export function writeFileSync(
+ pathOrRid: string | number | URL,
+ // deno-lint-ignore ban-types
+ data: string | Uint8Array | Object,
+ options?: Encodings | WriteFileOptions,
+) {
+ pathOrRid = pathOrRid instanceof URL ? fromFileUrl(pathOrRid) : pathOrRid;
+
+ const flag: string | undefined = isFileOptions(options)
+ ? options.flag
+ : undefined;
+
+ const mode: number | undefined = isFileOptions(options)
+ ? options.mode
+ : undefined;
+
+ const encoding = checkEncoding(getEncoding(options)) || "utf8";
+ const openOptions = getOpenOptions(flag || "w");
+
+ if (!ArrayBuffer.isView(data)) {
+ validateStringAfterArrayBufferView(data, "data");
+ if (typeof data !== "string") {
+ showStringCoercionDeprecation();
+ }
+ data = Buffer.from(String(data), encoding);
+ }
+
+ const isRid = typeof pathOrRid === "number";
+ let file;
+
+ let error: Error | null = null;
+ try {
+ file = isRid
+ ? new Deno.FsFile(pathOrRid as number)
+ : Deno.openSync(pathOrRid as string, openOptions);
+
+ // ignore mode because it's not supported on windows
+ // TODO(@bartlomieju): remove `!isWindows` when `Deno.chmod` is supported
+ if (!isRid && mode && !isWindows) {
+ Deno.chmodSync(pathOrRid as string, mode);
+ }
+
+ // TODO(crowlKats): duplicate from runtime/js/13_buffer.js
+ let nwritten = 0;
+ while (nwritten < (data as Uint8Array).length) {
+ nwritten += file.writeSync((data as Uint8Array).subarray(nwritten));
+ }
+ } catch (e) {
+ error = e instanceof Error
+ ? denoErrorToNodeError(e, { syscall: "write" })
+ : new Error("[non-error thrown]");
+ } finally {
+ // Make sure to close resource
+ if (!isRid && file) file.close();
+ }
+
+ if (error) throw error;
+}
+
+interface WriteAllOptions {
+ offset?: number;
+ length?: number;
+ signal?: AbortSignal;
+}
+async function writeAll(
+ w: Writer,
+ arr: Uint8Array,
+ options: WriteAllOptions = {},
+) {
+ const { offset = 0, length = arr.byteLength, signal } = options;
+ checkAborted(signal);
+
+ const written = await w.write(arr.subarray(offset, offset + length));
+
+ if (written === length) {
+ return;
+ }
+
+ await writeAll(w, arr, {
+ offset: offset + written,
+ length: length - written,
+ signal,
+ });
+}
+
+function checkAborted(signal?: AbortSignal) {
+ if (signal?.aborted) {
+ throw new AbortError();
+ }
+}