diff options
author | Benjamin Lupton <b@lupton.cc> | 2020-06-24 12:32:43 +1000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-23 22:32:43 -0400 |
commit | 49c54c0805ab26410a62e0251fee3a28b98c0e13 (patch) | |
tree | b9fcb2713622f2739557f2caffd51d8bb454300b /std/node/_fs | |
parent | d16337cc9c59732fe81655482e08b72d844472e6 (diff) |
fix(std/node): fix readFile types, add encoding types (#6451)
Diffstat (limited to 'std/node/_fs')
-rw-r--r-- | std/node/_fs/_fs_appendFile.ts | 9 | ||||
-rw-r--r-- | std/node/_fs/_fs_appendFile_test.ts | 4 | ||||
-rw-r--r-- | std/node/_fs/_fs_common.ts | 36 | ||||
-rw-r--r-- | std/node/_fs/_fs_readFile.ts | 89 | ||||
-rw-r--r-- | std/node/_fs/_fs_writeFile.ts | 7 | ||||
-rw-r--r-- | std/node/_fs/_fs_writeFile_test.ts | 4 | ||||
-rw-r--r-- | std/node/_fs/promises/_fs_readFile.ts | 22 | ||||
-rw-r--r-- | std/node/_fs/promises/_fs_readFile_test.ts | 30 | ||||
-rw-r--r-- | std/node/_fs/promises/_fs_writeFile.ts | 4 | ||||
-rw-r--r-- | std/node/_fs/promises/_fs_writeFile_test.ts | 2 |
10 files changed, 158 insertions, 49 deletions
diff --git a/std/node/_fs/_fs_appendFile.ts b/std/node/_fs/_fs_appendFile.ts index c0f347dbf..c057c1f65 100644 --- a/std/node/_fs/_fs_appendFile.ts +++ b/std/node/_fs/_fs_appendFile.ts @@ -1,5 +1,6 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. import { + Encodings, WriteFileOptions, isFileOptions, CallbackWithError, @@ -15,13 +16,13 @@ import { fromFileUrl } from "../path.ts"; export function appendFile( pathOrRid: string | number | URL, data: string, - optionsOrCallback: string | WriteFileOptions | CallbackWithError, + optionsOrCallback: Encodings | WriteFileOptions | CallbackWithError, callback?: CallbackWithError ): void { pathOrRid = pathOrRid instanceof URL ? fromFileUrl(pathOrRid) : pathOrRid; const callbackFn: CallbackWithError | undefined = optionsOrCallback instanceof Function ? optionsOrCallback : callback; - const options: string | WriteFileOptions | undefined = + const options: Encodings | WriteFileOptions | undefined = optionsOrCallback instanceof Function ? undefined : optionsOrCallback; if (!callbackFn) { throw new Error("No callback function supplied"); @@ -79,7 +80,7 @@ function closeRidIfNecessary(isPathString: boolean, rid: number): void { export function appendFileSync( pathOrRid: string | number | URL, data: string, - options?: string | WriteFileOptions + options?: Encodings | WriteFileOptions ): void { let rid = -1; @@ -115,7 +116,7 @@ export function appendFileSync( } function validateEncoding( - encodingOption: string | WriteFileOptions | undefined + encodingOption: Encodings | WriteFileOptions | undefined ): void { if (!encodingOption) return; diff --git a/std/node/_fs/_fs_appendFile_test.ts b/std/node/_fs/_fs_appendFile_test.ts index 1286ff900..9c0ccb666 100644 --- a/std/node/_fs/_fs_appendFile_test.ts +++ b/std/node/_fs/_fs_appendFile_test.ts @@ -23,6 +23,7 @@ Deno.test({ fn() { assertThrows( () => { + // @ts-expect-error Type '"made-up-encoding"' is not assignable to type appendFile("some/path", "some data", "made-up-encoding", () => {}); }, Error, @@ -33,6 +34,7 @@ Deno.test({ appendFile( "some/path", "some data", + // @ts-expect-error Type '"made-up-encoding"' is not assignable to type { encoding: "made-up-encoding" }, () => {} ); @@ -41,6 +43,7 @@ Deno.test({ "Only 'utf8' encoding is currently supported" ); assertThrows( + // @ts-expect-error Type '"made-up-encoding"' is not assignable to type () => appendFileSync("some/path", "some data", "made-up-encoding"), Error, "Only 'utf8' encoding is currently supported" @@ -48,6 +51,7 @@ Deno.test({ assertThrows( () => appendFileSync("some/path", "some data", { + // @ts-expect-error Type '"made-up-encoding"' is not assignable to type encoding: "made-up-encoding", }), Error, diff --git a/std/node/_fs/_fs_common.ts b/std/node/_fs/_fs_common.ts index bf7c0f675..43d3b8064 100644 --- a/std/node/_fs/_fs_common.ts +++ b/std/node/_fs/_fs_common.ts @@ -4,11 +4,32 @@ import { notImplemented } from "../_utils.ts"; export type CallbackWithError = (err?: Error | null) => void; +export type TextEncodings = + | "ascii" + | "utf8" + | "utf-8" + | "utf16le" + | "ucs2" + | "ucs-2" + | "base64" + | "latin1" + | "hex"; +export type BinaryEncodings = "binary"; +export type Encodings = TextEncodings | BinaryEncodings; + export interface FileOptions { - encoding?: string; + encoding?: Encodings; flag?: string; } +export type TextOptionsArgument = + | TextEncodings + | ({ encoding: TextEncodings } & FileOptions); +export type BinaryOptionsArgument = + | BinaryEncodings + | ({ encoding: BinaryEncodings } & FileOptions); +export type FileOptionsArgument = Encodings | FileOptions; + export interface WriteFileOptions extends FileOptions { mode?: number; } @@ -26,8 +47,8 @@ export function isFileOptions( } export function getEncoding( - optOrCallback?: FileOptions | WriteFileOptions | Function | string -): string | null { + optOrCallback?: FileOptions | WriteFileOptions | Function | Encodings | null +): Encodings | null { if (!optOrCallback || typeof optOrCallback === "function") { return null; } @@ -38,13 +59,15 @@ export function getEncoding( return encoding; } -export function checkEncoding(encoding: string | null): string | null { +export function checkEncoding(encoding: Encodings | null): Encodings | null { if (!encoding) return null; if (encoding === "utf8" || encoding === "utf-8") { return "utf8"; } - if (encoding === "buffer") { - return "buffer"; + if (encoding === "binary") { + return "binary"; + // before this was buffer, however buffer is not used in Node + // node -e "require('fs').readFile('../world.txt', 'buffer', console.log)" } const notImplementedEncodings = [ @@ -53,7 +76,6 @@ export function checkEncoding(encoding: string | null): string | null { "base64", "hex", "ascii", - "binary", "ucs2", ]; diff --git a/std/node/_fs/_fs_readFile.ts b/std/node/_fs/_fs_readFile.ts index d4093ff7f..39c3d8393 100644 --- a/std/node/_fs/_fs_readFile.ts +++ b/std/node/_fs/_fs_readFile.ts @@ -1,30 +1,58 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { intoCallbackAPIWithIntercept, MaybeEmpty } from "../_utils.ts"; -import { getEncoding, FileOptions } from "./_fs_common.ts"; +import { + Encodings, + getEncoding, + FileOptionsArgument, + TextOptionsArgument, + BinaryOptionsArgument, + TextEncodings, + BinaryEncodings, +} from "./_fs_common.ts"; import { Buffer } from "../buffer.ts"; import { fromFileUrl } from "../path.ts"; -type ReadFileCallback = ( - err: MaybeEmpty<Error>, - data: MaybeEmpty<string | Buffer> -) => void; - +function maybeDecode(data: Uint8Array, encoding: TextEncodings): string; +function maybeDecode( + data: Uint8Array, + encoding: BinaryEncodings | null +): Buffer; function maybeDecode( data: Uint8Array, - encoding: string | null + encoding: Encodings | null ): string | Buffer { const buffer = new Buffer(data.buffer, data.byteOffset, data.byteLength); - if (encoding) return buffer.toString(encoding); + if (encoding && encoding !== "binary") return buffer.toString(encoding); return buffer; } +type TextCallback = (err: Error | null, data?: string) => void; +type BinaryCallback = (err: Error | null, data?: Buffer) => void; +type GenericCallback = (err: Error | null, data?: string | Buffer) => void; +type Callback = TextCallback | BinaryCallback | GenericCallback; + +export function readFile( + path: string | URL, + options: TextOptionsArgument, + callback: TextCallback +): void; +export function readFile( + path: string | URL, + options: BinaryOptionsArgument, + callback: BinaryCallback +): void; +export function readFile( + path: string | URL, + options: null | undefined | FileOptionsArgument, + callback: BinaryCallback +): void; +export function readFile(path: string | URL, callback: BinaryCallback): void; export function readFile( path: string | URL, - optOrCallback: ReadFileCallback | FileOptions | string | undefined, - callback?: ReadFileCallback + optOrCallback?: FileOptionsArgument | Callback | null | undefined, + callback?: Callback ): void { path = path instanceof URL ? fromFileUrl(path) : path; - let cb: ReadFileCallback | undefined; + let cb: Callback | undefined; if (typeof optOrCallback === "function") { cb = optOrCallback; } else { @@ -33,18 +61,39 @@ export function readFile( const encoding = getEncoding(optOrCallback); - intoCallbackAPIWithIntercept<Uint8Array, string | Buffer>( - Deno.readFile, - (data: Uint8Array): string | Buffer => maybeDecode(data, encoding), - cb, - path - ); + const p = Deno.readFile(path); + + if (cb) { + p.then((data: Uint8Array) => { + if (encoding && encoding !== "binary") { + const text = maybeDecode(data, encoding); + return (cb as TextCallback)(null, text); + } + const buffer = maybeDecode(data, encoding); + (cb as BinaryCallback)(null, buffer); + }).catch((err) => cb && cb(err)); + } } export function readFileSync( path: string | URL, - opt?: FileOptions | string + opt: TextOptionsArgument +): string; +export function readFileSync( + path: string | URL, + opt?: BinaryOptionsArgument +): Buffer; +export function readFileSync( + path: string | URL, + opt?: FileOptionsArgument ): string | Buffer { path = path instanceof URL ? fromFileUrl(path) : path; - return maybeDecode(Deno.readFileSync(path), getEncoding(opt)); + const data = Deno.readFileSync(path); + const encoding = getEncoding(opt); + if (encoding && encoding !== "binary") { + const text = maybeDecode(data, encoding); + return text; + } + const buffer = maybeDecode(data, encoding); + return buffer; } diff --git a/std/node/_fs/_fs_writeFile.ts b/std/node/_fs/_fs_writeFile.ts index 4ede42638..54bdb801c 100644 --- a/std/node/_fs/_fs_writeFile.ts +++ b/std/node/_fs/_fs_writeFile.ts @@ -3,6 +3,7 @@ import { notImplemented } from "../_utils.ts"; import { fromFileUrl } from "../path.ts"; import { + Encodings, WriteFileOptions, CallbackWithError, isFileOptions, @@ -14,12 +15,12 @@ import { export function writeFile( pathOrRid: string | number | URL, data: string | Uint8Array, - optOrCallback: string | CallbackWithError | WriteFileOptions | undefined, + optOrCallback: Encodings | CallbackWithError | WriteFileOptions | undefined, callback?: CallbackWithError ): void { const callbackFn: CallbackWithError | undefined = optOrCallback instanceof Function ? optOrCallback : callback; - const options: string | WriteFileOptions | undefined = + const options: Encodings | WriteFileOptions | undefined = optOrCallback instanceof Function ? undefined : optOrCallback; if (!callbackFn) { @@ -71,7 +72,7 @@ export function writeFile( export function writeFileSync( pathOrRid: string | number | URL, data: string | Uint8Array, - options?: string | WriteFileOptions + options?: Encodings | WriteFileOptions ): void { pathOrRid = pathOrRid instanceof URL ? fromFileUrl(pathOrRid) : pathOrRid; diff --git a/std/node/_fs/_fs_writeFile_test.ts b/std/node/_fs/_fs_writeFile_test.ts index 81913d0b0..3f874a2af 100644 --- a/std/node/_fs/_fs_writeFile_test.ts +++ b/std/node/_fs/_fs_writeFile_test.ts @@ -24,6 +24,7 @@ Deno.test("Callback must be a function error", function fn() { Deno.test("Invalid encoding results in error()", function testEncodingErrors() { assertThrows( () => { + // @ts-expect-error Type '"made-up-encoding"' is not assignable to type writeFile("some/path", "some data", "made-up-encoding", () => {}); }, Error, @@ -32,6 +33,7 @@ Deno.test("Invalid encoding results in error()", function testEncodingErrors() { assertThrows( () => { + // @ts-expect-error Type '"made-up-encoding"' is not assignable to type writeFileSync("some/path", "some data", "made-up-encoding"); }, Error, @@ -44,6 +46,7 @@ Deno.test("Invalid encoding results in error()", function testEncodingErrors() { "some/path", "some data", { + // @ts-expect-error Type '"made-up-encoding"' is not assignable to type encoding: "made-up-encoding", }, () => {} @@ -56,6 +59,7 @@ Deno.test("Invalid encoding results in error()", function testEncodingErrors() { assertThrows( () => { writeFileSync("some/path", "some data", { + // @ts-expect-error Type '"made-up-encoding"' is not assignable to type encoding: "made-up-encoding", }); }, diff --git a/std/node/_fs/promises/_fs_readFile.ts b/std/node/_fs/promises/_fs_readFile.ts index 9e4a4ed43..83ef9ac50 100644 --- a/std/node/_fs/promises/_fs_readFile.ts +++ b/std/node/_fs/promises/_fs_readFile.ts @@ -1,16 +1,28 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { FileOptions } from "../_fs_common.ts"; -import { MaybeEmpty } from "../../_utils.ts"; - +import { + FileOptionsArgument, + BinaryOptionsArgument, + TextOptionsArgument, +} from "../_fs_common.ts"; import { readFile as readFileCallback } from "../_fs_readFile.ts"; export function readFile( path: string | URL, - options?: FileOptions | string -): Promise<MaybeEmpty<string | Uint8Array>> { + options: TextOptionsArgument +): Promise<string>; +export function readFile( + path: string | URL, + options?: BinaryOptionsArgument +): Promise<Uint8Array>; +export function readFile( + path: string | URL, + options?: FileOptionsArgument +): Promise<string | Uint8Array> { return new Promise((resolve, reject) => { readFileCallback(path, options, (err, data): void => { if (err) return reject(err); + if (data == null) + return reject(new Error("Invalid state: data missing, but no error")); resolve(data); }); }); diff --git a/std/node/_fs/promises/_fs_readFile_test.ts b/std/node/_fs/promises/_fs_readFile_test.ts index c92907fec..f5be2318b 100644 --- a/std/node/_fs/promises/_fs_readFile_test.ts +++ b/std/node/_fs/promises/_fs_readFile_test.ts @@ -7,24 +7,38 @@ const testData = path.resolve( ); Deno.test("readFileSuccess", async function () { - const data = await readFile(testData); + const data: Uint8Array = await readFile(testData); assert(data instanceof Uint8Array); - assertEquals(new TextDecoder().decode(data as Uint8Array), "hello world"); + assertEquals(new TextDecoder().decode(data), "hello world"); }); -Deno.test("readFileEncodeUtf8Success", async function () { - const data = await readFile(testData, { encoding: "utf8" }); +Deno.test("readFileBinarySuccess", async function () { + const data: Uint8Array = await readFile(testData, "binary"); + + assert(data instanceof Uint8Array); + assertEquals(new TextDecoder().decode(data), "hello world"); +}); + +Deno.test("readFileBinaryObjectSuccess", async function () { + const data: Uint8Array = await readFile(testData, { encoding: "binary" }); + + assert(data instanceof Uint8Array); + assertEquals(new TextDecoder().decode(data), "hello world"); +}); + +Deno.test("readFileStringObjectSuccess", async function () { + const data: string = await readFile(testData, { encoding: "utf8" }); assertEquals(typeof data, "string"); - assertEquals(data as string, "hello world"); + assertEquals(data, "hello world"); }); -Deno.test("readFileEncodingAsString", async function () { - const data = await readFile(testData, "utf8"); +Deno.test("readFileStringSuccess", async function () { + const data: string = await readFile(testData, "utf8"); assertEquals(typeof data, "string"); - assertEquals(data as string, "hello world"); + assertEquals(data, "hello world"); }); Deno.test("readFileError", async function () { diff --git a/std/node/_fs/promises/_fs_writeFile.ts b/std/node/_fs/promises/_fs_writeFile.ts index e89276c97..4f7c39a6a 100644 --- a/std/node/_fs/promises/_fs_writeFile.ts +++ b/std/node/_fs/promises/_fs_writeFile.ts @@ -1,12 +1,12 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { WriteFileOptions } from "../_fs_common.ts"; +import { Encodings, WriteFileOptions } from "../_fs_common.ts"; import { writeFile as writeFileCallback } from "../_fs_writeFile.ts"; export function writeFile( pathOrRid: string | number | URL, data: string | Uint8Array, - options?: string | WriteFileOptions + options?: Encodings | WriteFileOptions ): Promise<void> { return new Promise((resolve, reject) => { writeFileCallback(pathOrRid, data, options, (err?: Error | null) => { diff --git a/std/node/_fs/promises/_fs_writeFile_test.ts b/std/node/_fs/promises/_fs_writeFile_test.ts index 574bbfc35..777971046 100644 --- a/std/node/_fs/promises/_fs_writeFile_test.ts +++ b/std/node/_fs/promises/_fs_writeFile_test.ts @@ -12,6 +12,7 @@ const decoder = new TextDecoder("utf-8"); Deno.test("Invalid encoding results in error()", function testEncodingErrors() { assertThrowsAsync( async () => { + // @ts-expect-error Type '"made-up-encoding"' is not assignable to type await writeFile("some/path", "some data", "made-up-encoding"); }, Error, @@ -20,6 +21,7 @@ Deno.test("Invalid encoding results in error()", function testEncodingErrors() { assertThrowsAsync( async () => { await writeFile("some/path", "some data", { + // @ts-expect-error Type '"made-up-encoding"' is not assignable to type encoding: "made-up-encoding", }); }, |