summaryrefslogtreecommitdiff
path: root/ext/node/polyfills/_fs/_fs_open.ts
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2023-02-14 17:38:45 +0100
committerGitHub <noreply@github.com>2023-02-14 17:38:45 +0100
commitd47147fb6ad229b1c039aff9d0959b6e281f4df5 (patch)
tree6e9e790f2b9bc71b5f0c9c7e64b95cae31579d58 /ext/node/polyfills/_fs/_fs_open.ts
parent1d00bbe47e2ca14e2d2151518e02b2324461a065 (diff)
feat(ext/node): embed std/node into the snapshot (#17724)
This commit moves "deno_std/node" in "ext/node" crate. The code is transpiled and snapshotted during the build process. During the first pass a minimal amount of work was done to create the snapshot, a lot of code in "ext/node" depends on presence of "Deno" global. This code will be gradually fixed in the follow up PRs to migrate it to import relevant APIs from "internal:" modules. Currently the code from snapshot is not used in any way, and all Node/npm compatibility still uses code from "https://deno.land/std/node" (or from the location specified by "DENO_NODE_COMPAT_URL"). This will also be handled in a follow up PRs. --------- Co-authored-by: crowlkats <crowlkats@toaxl.com> Co-authored-by: Divy Srivastava <dj.srivastava23@gmail.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
Diffstat (limited to 'ext/node/polyfills/_fs/_fs_open.ts')
-rw-r--r--ext/node/polyfills/_fs/_fs_open.ts198
1 files changed, 198 insertions, 0 deletions
diff --git a/ext/node/polyfills/_fs/_fs_open.ts b/ext/node/polyfills/_fs/_fs_open.ts
new file mode 100644
index 000000000..e703da56f
--- /dev/null
+++ b/ext/node/polyfills/_fs/_fs_open.ts
@@ -0,0 +1,198 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+import {
+ O_APPEND,
+ O_CREAT,
+ O_EXCL,
+ O_RDWR,
+ O_TRUNC,
+ O_WRONLY,
+} from "internal:deno_node/polyfills/_fs/_fs_constants.ts";
+import { getOpenOptions } from "internal:deno_node/polyfills/_fs/_fs_common.ts";
+import { promisify } from "internal:deno_node/polyfills/internal/util.mjs";
+import { parseFileMode } from "internal:deno_node/polyfills/internal/validators.mjs";
+import { ERR_INVALID_ARG_TYPE } from "internal:deno_node/polyfills/internal/errors.ts";
+import { getValidatedPath } from "internal:deno_node/polyfills/internal/fs/utils.mjs";
+import type { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+
+function existsSync(filePath: string | URL): boolean {
+ try {
+ Deno.lstatSync(filePath);
+ return true;
+ } catch (error) {
+ if (error instanceof Deno.errors.NotFound) {
+ return false;
+ }
+ throw error;
+ }
+}
+
+const FLAGS_AX = O_APPEND | O_CREAT | O_WRONLY | O_EXCL;
+const FLAGS_AX_PLUS = O_APPEND | O_CREAT | O_RDWR | O_EXCL;
+const FLAGS_WX = O_TRUNC | O_CREAT | O_WRONLY | O_EXCL;
+const FLAGS_WX_PLUS = O_TRUNC | O_CREAT | O_RDWR | O_EXCL;
+
+export type openFlags =
+ | "a"
+ | "ax"
+ | "a+"
+ | "ax+"
+ | "as"
+ | "as+"
+ | "r"
+ | "r+"
+ | "rs+"
+ | "w"
+ | "wx"
+ | "w+"
+ | "wx+"
+ | number;
+
+type openCallback = (err: Error | null, fd: number) => void;
+
+function convertFlagAndModeToOptions(
+ flag?: openFlags,
+ mode?: number,
+): Deno.OpenOptions | undefined {
+ if (!flag && !mode) return undefined;
+ if (!flag && mode) return { mode };
+ return { ...getOpenOptions(flag), mode };
+}
+
+export function open(path: string | Buffer | URL, callback: openCallback): void;
+export function open(
+ path: string | Buffer | URL,
+ flags: openFlags,
+ callback: openCallback,
+): void;
+export function open(
+ path: string | Buffer | URL,
+ flags: openFlags,
+ mode: number,
+ callback: openCallback,
+): void;
+export function open(
+ path: string | Buffer | URL,
+ flags: openCallback | openFlags,
+ mode?: openCallback | number,
+ callback?: openCallback,
+) {
+ if (flags === undefined) {
+ throw new ERR_INVALID_ARG_TYPE(
+ "flags or callback",
+ ["string", "function"],
+ flags,
+ );
+ }
+ path = getValidatedPath(path);
+ if (arguments.length < 3) {
+ // deno-lint-ignore no-explicit-any
+ callback = flags as any;
+ flags = "r";
+ mode = 0o666;
+ } else if (typeof mode === "function") {
+ callback = mode;
+ mode = 0o666;
+ } else {
+ mode = parseFileMode(mode, "mode", 0o666);
+ }
+
+ if (typeof callback !== "function") {
+ throw new ERR_INVALID_ARG_TYPE(
+ "callback",
+ "function",
+ callback,
+ );
+ }
+
+ if (flags === undefined) {
+ flags = "r";
+ }
+
+ if (
+ existenceCheckRequired(flags as openFlags) &&
+ existsSync(path as string)
+ ) {
+ const err = new Error(`EEXIST: file already exists, open '${path}'`);
+ (callback as (err: Error) => void)(err);
+ } else {
+ if (flags === "as" || flags === "as+") {
+ let err: Error | null = null, res: number;
+ try {
+ res = openSync(path, flags, mode);
+ } catch (error) {
+ err = error instanceof Error ? error : new Error("[non-error thrown]");
+ }
+ if (err) {
+ (callback as (err: Error) => void)(err);
+ } else {
+ callback(null, res!);
+ }
+ return;
+ }
+ Deno.open(
+ path as string,
+ convertFlagAndModeToOptions(flags as openFlags, mode),
+ ).then(
+ (file) => callback!(null, file.rid),
+ (err) => (callback as (err: Error) => void)(err),
+ );
+ }
+}
+
+export const openPromise = promisify(open) as (
+ & ((path: string | Buffer | URL) => Promise<number>)
+ & ((path: string | Buffer | URL, flags: openFlags) => Promise<number>)
+ & ((path: string | Buffer | URL, mode?: number) => Promise<number>)
+ & ((
+ path: string | Buffer | URL,
+ flags?: openFlags,
+ mode?: number,
+ ) => Promise<number>)
+);
+
+export function openSync(path: string | Buffer | URL): number;
+export function openSync(
+ path: string | Buffer | URL,
+ flags?: openFlags,
+): number;
+export function openSync(path: string | Buffer | URL, mode?: number): number;
+export function openSync(
+ path: string | Buffer | URL,
+ flags?: openFlags,
+ mode?: number,
+): number;
+export function openSync(
+ path: string | Buffer | URL,
+ flags?: openFlags,
+ maybeMode?: number,
+) {
+ const mode = parseFileMode(maybeMode, "mode", 0o666);
+ path = getValidatedPath(path);
+
+ if (flags === undefined) {
+ flags = "r";
+ }
+
+ if (
+ existenceCheckRequired(flags) &&
+ existsSync(path as string)
+ ) {
+ throw new Error(`EEXIST: file already exists, open '${path}'`);
+ }
+
+ return Deno.openSync(path as string, convertFlagAndModeToOptions(flags, mode))
+ .rid;
+}
+
+function existenceCheckRequired(flags: openFlags | number) {
+ return (
+ (typeof flags === "string" &&
+ ["ax", "ax+", "wx", "wx+"].includes(flags)) ||
+ (typeof flags === "number" && (
+ ((flags & FLAGS_AX) === FLAGS_AX) ||
+ ((flags & FLAGS_AX_PLUS) === FLAGS_AX_PLUS) ||
+ ((flags & FLAGS_WX) === FLAGS_WX) ||
+ ((flags & FLAGS_WX_PLUS) === FLAGS_WX_PLUS)
+ ))
+ );
+}