1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-22 23:34:47 -05:00

feat: std/node (#3319)

This commit is contained in:
Vincent LE GOFF 2019-11-12 21:51:14 +01:00 committed by Ry Dahl
parent 0f33bf6885
commit ee1b8dc883
7 changed files with 327 additions and 0 deletions

7
std/node/README.md Normal file
View file

@ -0,0 +1,7 @@
# Deno Node compatibility
This module is meant to have a compatibility layer for the
[nodeJS standard library](https://nodejs.org/docs/latest-v12.x/api/).
**Warning** : Any function of this module should not be referred anywhere in the
deno standard library as it's a compatiblity module.

35
std/node/_utils.ts Normal file
View file

@ -0,0 +1,35 @@
export function notImplemented(msg?: string): never {
const message = msg ? `Not implemented: ${msg}` : "Not implemented";
throw new Error(message);
}
// API helpers
export type MaybeNull<T> = T | null;
export type MaybeDefined<T> = T | undefined;
export type MaybeEmpty<T> = T | null | undefined;
export function intoCallbackAPI<T>(
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
func: (...args: any[]) => Promise<T>,
cb: MaybeEmpty<(err: MaybeNull<Error>, value: MaybeEmpty<T>) => void>,
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
...args: any[]
): void {
func(...args)
.then(value => cb && cb(null, value))
.catch(err => cb && cb(err, null));
}
export function intoCallbackAPIWithIntercept<T1, T2>(
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
func: (...args: any[]) => Promise<T1>,
interceptor: (v: T1) => T2,
cb: MaybeEmpty<(err: MaybeNull<Error>, value: MaybeEmpty<T2>) => void>,
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
...args: any[]
): void {
func(...args)
.then(value => cb && cb(null, interceptor(value)))
.catch(err => cb && cb(err, null));
}

68
std/node/fs.ts Normal file
View file

@ -0,0 +1,68 @@
import { notImplemented, intoCallbackAPIWithIntercept } from "./_utils.ts";
const { readFile: denoReadFile, readFileSync: denoReadFileSync } = Deno;
type ReadFileCallback = (err: Error | null, data: string | Uint8Array) => void;
interface ReadFileOptions {
encoding?: string | null;
flag?: string;
}
function getEncoding(
optOrCallback?: ReadFileOptions | ReadFileCallback
): string | null {
if (!optOrCallback || typeof optOrCallback === "function") {
return null;
} else {
if (optOrCallback.encoding) {
if (
optOrCallback.encoding === "utf8" ||
optOrCallback.encoding === "utf-8"
) {
return "utf8";
} else {
notImplemented();
}
}
return null;
}
}
function maybeDecode(
data: Uint8Array,
encoding: string | null
): string | Uint8Array {
if (encoding === "utf8") {
return new TextDecoder().decode(data);
}
return data;
}
export function readFile(
path: string,
optOrCallback: ReadFileCallback | ReadFileOptions,
callback?: ReadFileCallback
): void {
let cb: ReadFileCallback | undefined;
if (typeof optOrCallback === "function") {
cb = optOrCallback;
} else {
cb = callback;
}
const encoding = getEncoding(optOrCallback);
intoCallbackAPIWithIntercept<Uint8Array, string | Uint8Array>(
denoReadFile,
(data: Uint8Array): string | Uint8Array => maybeDecode(data, encoding),
cb,
path
);
}
export function readFileSync(
path: string,
opt?: ReadFileOptions
): string | Uint8Array {
return maybeDecode(denoReadFileSync(path), getEncoding(opt));
}

47
std/node/fs_test.ts Normal file
View file

@ -0,0 +1,47 @@
import { readFile, readFileSync } from "./fs.ts";
import { test } from "../testing/mod.ts";
import * as path from "../path/mod.ts";
import { assertEquals, assert } from "../testing/asserts.ts";
const testData = path.resolve(path.join("node", "testdata", "hello.txt"));
// Need to convert to promises, otherwise test() won't report error correctly.
test(async function readFileSuccess() {
const data = await new Promise((res, rej) => {
readFile(testData, (err, data) => {
if (err) {
rej(err);
}
res(data);
});
});
assert(data instanceof Uint8Array);
assertEquals(new TextDecoder().decode(data as Uint8Array), "hello world");
});
test(async function readFileEncodeUtf8Success() {
const data = await new Promise((res, rej) => {
readFile(testData, { encoding: "utf8" }, (err, data) => {
if (err) {
rej(err);
}
res(data);
});
});
assertEquals(typeof data, "string");
assertEquals(data as string, "hello world");
});
test(function readFileSyncSuccess() {
const data = readFileSync(testData);
assert(data instanceof Uint8Array);
assertEquals(new TextDecoder().decode(data as Uint8Array), "hello world");
});
test(function readFileEncodeUtf8Success() {
const data = readFileSync(testData, { encoding: "utf8" });
assertEquals(typeof data, "string");
assertEquals(data as string, "hello world");
});

1
std/node/testdata/hello.txt vendored Normal file
View file

@ -0,0 +1 @@
hello world

47
std/node/util.ts Normal file
View file

@ -0,0 +1,47 @@
export function isArray(value: unknown): boolean {
return Array.isArray(value);
}
export function isBoolean(value: unknown): boolean {
return typeof value === "boolean" || value instanceof Boolean;
}
export function isNull(value: unknown): boolean {
return value === null;
}
export function isNullOrUndefined(value: unknown): boolean {
return value === null || value === undefined;
}
export function isNumber(value: unknown): boolean {
return typeof value === "number" || value instanceof Number;
}
export function isString(value: unknown): boolean {
return typeof value === "string" || value instanceof String;
}
export function isSymbol(value: unknown): boolean {
return typeof value === "symbol";
}
export function isUndefined(value: unknown): boolean {
return value === undefined;
}
export function isObject(value: unknown): boolean {
return value !== null && typeof value === "object";
}
export function isError(e: unknown): boolean {
return e instanceof Error;
}
export function isFunction(value: unknown): boolean {
return typeof value === "function";
}
export function isRegExp(value: unknown): boolean {
return value instanceof RegExp;
}

122
std/node/util_test.ts Normal file
View file

@ -0,0 +1,122 @@
import { test } from "../testing/mod.ts";
import { assert } from "../testing/asserts.ts";
import * as util from "./util.ts";
test({
name: "[util] isBoolean",
fn() {
assert(util.isBoolean(true));
assert(util.isBoolean(new Boolean()));
assert(util.isBoolean(new Boolean(true)));
assert(util.isBoolean(false));
assert(!util.isBoolean("deno"));
assert(!util.isBoolean("true"));
}
});
test({
name: "[util] isNull",
fn() {
let n;
assert(util.isNull(null));
assert(!util.isNull(n));
assert(!util.isNull(0));
assert(!util.isNull({}));
}
});
test({
name: "[util] isNullOrUndefined",
fn() {
let n;
assert(util.isNullOrUndefined(null));
assert(util.isNullOrUndefined(n));
assert(!util.isNullOrUndefined({}));
assert(!util.isNullOrUndefined("undefined"));
}
});
test({
name: "[util] isNumber",
fn() {
assert(util.isNumber(666));
assert(util.isNumber(new Number(666)));
assert(!util.isNumber("999"));
assert(!util.isNumber(null));
}
});
test({
name: "[util] isString",
fn() {
assert(util.isString("deno"));
assert(util.isString(new String("DIO")));
assert(!util.isString(1337));
}
});
test({
name: "[util] isSymbol",
fn() {}
});
test({
name: "[util] isUndefined",
fn() {
let t;
assert(util.isUndefined(t));
assert(!util.isUndefined("undefined"));
assert(!util.isUndefined({}));
}
});
test({
name: "[util] isObject",
fn() {
const dio = { stand: "Za Warudo" };
assert(util.isObject(dio));
assert(util.isObject(new RegExp(/Toki Wo Tomare/)));
assert(!util.isObject("Jotaro"));
}
});
test({
name: "[util] isError",
fn() {
const java = new Error();
const nodejs = new TypeError();
const deno = "Future";
assert(util.isError(java));
assert(util.isError(nodejs));
assert(!util.isError(deno));
}
});
test({
name: "[util] isFunction",
fn() {
const f = function(): void {};
assert(util.isFunction(f));
assert(!util.isFunction({}));
assert(!util.isFunction(new RegExp(/f/)));
}
});
test({
name: "[util] isRegExp",
fn() {
assert(util.isRegExp(new RegExp(/f/)));
assert(util.isRegExp(/fuManchu/));
assert(!util.isRegExp({ evil: "eye" }));
assert(!util.isRegExp(null));
}
});
test({
name: "[util] isArray",
fn() {
assert(util.isArray([]));
assert(!util.isArray({ yaNo: "array" }));
assert(!util.isArray(null));
}
});