diff options
Diffstat (limited to 'cli/js')
-rw-r--r-- | cli/js/deno.ts | 1 | ||||
-rw-r--r-- | cli/js/files.ts | 112 | ||||
-rw-r--r-- | cli/js/files_test.ts | 62 | ||||
-rw-r--r-- | cli/js/lib.deno_runtime.d.ts | 53 |
4 files changed, 216 insertions, 12 deletions
diff --git a/cli/js/deno.ts b/cli/js/deno.ts index 513d9f284..e53f9a63a 100644 --- a/cli/js/deno.ts +++ b/cli/js/deno.ts @@ -19,6 +19,7 @@ export { seek, seekSync, close, + OpenOptions, OpenMode } from "./files.ts"; export { diff --git a/cli/js/files.ts b/cli/js/files.ts index 1d04c0e70..c966b9fa0 100644 --- a/cli/js/files.ts +++ b/cli/js/files.ts @@ -20,22 +20,69 @@ import { /** Open a file and return an instance of the `File` object * synchronously. * - * const file = Deno.openSync("/foo/bar.txt"); + * const file = Deno.openSync("/foo/bar.txt", { read: true, write: true }); + */ +export function openSync(filename: string, capability?: OpenOptions): File; +/** Open a file and return an instance of the `File` object + * synchronously. + * + * const file = Deno.openSync("/foo/bar.txt", "r"); */ -export function openSync(filename: string, mode: OpenMode = "r"): File { - const rid = sendSyncJson(dispatch.OP_OPEN, { filename, mode }); +export function openSync(filename: string, mode?: OpenMode): File; + +export function openSync( + filename: string, + modeOrOptions: OpenOptions | OpenMode = "r" +): File { + let mode = null; + let options = null; + + if (typeof modeOrOptions === "string") { + mode = modeOrOptions; + } else { + checkOpenOptions(modeOrOptions); + options = modeOrOptions; + } + + const rid = sendSyncJson(dispatch.OP_OPEN, { filename, options, mode }); return new File(rid); } /** Open a file and return an instance of the `File` object. * - * const file = await Deno.open("/foo/bar.txt"); + * const file = await Deno.open("/foo/bar.txt", { read: true, write: true }); + */ +export async function open( + filename: string, + options?: OpenOptions +): Promise<File>; + +/** Open a file and return an instance of the `File` object. + * + * const file = await Deno.open("/foo/bar.txt, "w+"); */ +export async function open(filename: string, mode?: OpenMode): Promise<File>; + +/**@internal*/ export async function open( filename: string, - mode: OpenMode = "r" + modeOrOptions: OpenOptions | OpenMode = "r" ): Promise<File> { - const rid = await sendAsyncJson(dispatch.OP_OPEN, { filename, mode }); + let mode = null; + let options = null; + + if (typeof modeOrOptions === "string") { + mode = modeOrOptions; + } else { + checkOpenOptions(modeOrOptions); + options = modeOrOptions; + } + + const rid = await sendAsyncJson(dispatch.OP_OPEN, { + filename, + options, + mode + }); return new File(rid); } @@ -216,6 +263,36 @@ export const stdout = new File(1); /** An instance of `File` for stderr. */ export const stderr = new File(2); +export interface OpenOptions { + /** Sets the option for read access. This option, when true, will indicate that the file should be read-able if opened. */ + read?: boolean; + /** Sets the option for write access. + * This option, when true, will indicate that the file should be write-able if opened. + * If the file already exists, any write calls on it will overwrite its contents, without truncating it. + */ + write?: boolean; + /** Sets the option for creating a new file. + * This option indicates whether a new file will be created if the file does not yet already exist. + * In order for the file to be created, write or append access must be used. + */ + create?: boolean; + /** Sets the option for truncating a previous file. + * If a file is successfully opened with this option set it will truncate the file to 0 length if it already exists. + * The file must be opened with write access for truncate to work. + */ + truncate?: boolean; + /**Sets the option for the append mode. + * This option, when true, means that writes will append to a file instead of overwriting previous contents. + * Note that setting { write: true, append: true } has the same effect as setting only { append: true }. + */ + append?: boolean; + /** Sets the option to always create a new file. + * This option indicates whether a new file will be created. No file is allowed to exist at the target location, also no (dangling) symlink. + * If { createNew: true } is set, create and truncate are ignored. + */ + createNew?: boolean; +} + export type OpenMode = /** Read-only. Default. Starts at beginning of file. */ | "r" @@ -241,3 +318,26 @@ export type OpenMode = | "x" /** Read-write. Behaves like `x` and allows to read from file. */ | "x+"; + +/** Check if OpenOptions is set to valid combination of options. + * @returns Tuple representing if openMode is valid and error message if it's not + * @internal + */ +function checkOpenOptions(options: OpenOptions): void { + if (Object.values(options).filter(val => val === true).length === 0) { + throw new Error("OpenOptions requires at least one option to be true"); + } + + if (options.truncate && !options.write) { + throw new Error("'truncate' option requires 'write' option"); + } + + const createOrCreateNewWithoutWriteOrAppend = + (options.create || options.createNew) && !(options.write || options.append); + + if (createOrCreateNewWithoutWriteOrAppend) { + throw new Error( + "'create' or 'createNew' options require 'write' or 'append' option" + ); + } +} diff --git a/cli/js/files_test.ts b/cli/js/files_test.ts index a4881296a..fca9a3859 100644 --- a/cli/js/files_test.ts +++ b/cli/js/files_test.ts @@ -1,5 +1,11 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { test, testPerm, assert, assertEquals } from "./test_util.ts"; +import { + test, + testPerm, + assert, + assertEquals, + assertStrContains +} from "./test_util.ts"; test(function filesStdioFileDescriptors(): void { assertEquals(Deno.stdin.rid, 0); @@ -78,9 +84,55 @@ testPerm({ write: false }, async function writePermFailure(): Promise<void> { } }); +test(async function openOptions(): Promise<void> { + const filename = "cli/tests/fixture.json"; + let err; + try { + await Deno.open(filename, { write: false }); + } catch (e) { + err = e; + } + assert(!!err); + assertStrContains( + err.message, + "OpenOptions requires at least one option to be true" + ); + + try { + await Deno.open(filename, { truncate: true, write: false }); + } catch (e) { + err = e; + } + assert(!!err); + assertStrContains(err.message, "'truncate' option requires 'write' option"); + + try { + await Deno.open(filename, { create: true, write: false }); + } catch (e) { + err = e; + } + assert(!!err); + assertStrContains( + err.message, + "'create' or 'createNew' options require 'write' or 'append' option" + ); + + try { + await Deno.open(filename, { createNew: true, append: false }); + } catch (e) { + err = e; + } + assert(!!err); + assertStrContains( + err.message, + "'create' or 'createNew' options require 'write' or 'append' option" + ); +}); + testPerm({ read: false }, async function readPermFailure(): Promise<void> { let caughtError = false; try { + await Deno.open("package.json", "r"); await Deno.open("cli/tests/fixture.json", "r"); } catch (e) { caughtError = true; @@ -95,7 +147,12 @@ testPerm({ write: true }, async function writeNullBufferFailure(): Promise< > { const tempDir = Deno.makeTempDirSync(); const filename = tempDir + "hello.txt"; - const file = await Deno.open(filename, "w"); + const w = { + write: true, + truncate: true, + create: true + }; + const file = await Deno.open(filename, w); // writing null should throw an error let err; @@ -183,7 +240,6 @@ testPerm({ read: true, write: true }, async function openModeWrite(): Promise< const encoder = new TextEncoder(); const filename = tempDir + "hello.txt"; const data = encoder.encode("Hello world!\n"); - let file = await Deno.open(filename, "w"); // assert file was created let fileInfo = Deno.statSync(filename); diff --git a/cli/js/lib.deno_runtime.d.ts b/cli/js/lib.deno_runtime.d.ts index 05553ffb7..c867213ee 100644 --- a/cli/js/lib.deno_runtime.d.ts +++ b/cli/js/lib.deno_runtime.d.ts @@ -312,7 +312,16 @@ declare namespace Deno { /** Open a file and return an instance of the `File` object * synchronously. * - * const file = Deno.openSync("/foo/bar.txt"); + * const file = Deno.openSYNC("/foo/bar.txt", { read: true, write: true }); + * + * Requires allow-read or allow-write or both depending on mode. + */ + export function openSync(filename: string, options?: OpenOptions): File; + + /** Open a file and return an instance of the `File` object + * synchronously. + * + * const file = Deno.openSync("/foo/bar.txt", "r"); * * Requires allow-read or allow-write or both depending on mode. */ @@ -320,7 +329,15 @@ declare namespace Deno { /** Open a file and return an instance of the `File` object. * - * const file = await Deno.open("/foo/bar.txt"); + * const file = await Deno.open("/foo/bar.txt", { read: true, write: true }); + * + * Requires allow-read or allow-write or both depending on mode. + */ + export function open(filename: string, options?: OpenOptions): Promise<File>; + + /** Open a file and return an instance of the `File` object. + * + * const file = await Deno.open("/foo/bar.txt, "w+"); * * Requires allow-read or allow-write or both depending on mode. */ @@ -439,8 +456,38 @@ declare namespace Deno { /** An instance of `File` for stderr. */ export const stderr: File; - /** UNSTABLE: merge https://github.com/denoland/deno/pull/3119 */ + export interface OpenOptions { + /** Sets the option for read access. This option, when true, will indicate that the file should be read-able if opened. */ + read?: boolean; + /** Sets the option for write access. + * This option, when true, will indicate that the file should be write-able if opened. + * If the file already exists, any write calls on it will overwrite its contents, without truncating it. + */ + write?: boolean; + /* Sets the option for creating a new file. + * This option indicates whether a new file will be created if the file does not yet already exist. + * In order for the file to be created, write or append access must be used. + */ + create?: boolean; + /** Sets the option for truncating a previous file. + * If a file is successfully opened with this option set it will truncate the file to 0 length if it already exists. + * The file must be opened with write access for truncate to work. + */ + truncate?: boolean; + /**Sets the option for the append mode. + * This option, when true, means that writes will append to a file instead of overwriting previous contents. + * Note that setting { write: true, append: true } has the same effect as setting only { append: true }. + */ + append?: boolean; + /** Sets the option to always create a new file. + * This option indicates whether a new file will be created. No file is allowed to exist at the target location, also no (dangling) symlink. + * If { createNew: true } is set, create and truncate are ignored. + */ + createNew?: boolean; + } + export type OpenMode = + /** Read-only. Default. Starts at beginning of file. */ | "r" /** Read-write. Start at beginning of file. */ | "r+" |