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:
parent
0f33bf6885
commit
ee1b8dc883
7 changed files with 327 additions and 0 deletions
7
std/node/README.md
Normal file
7
std/node/README.md
Normal 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
35
std/node/_utils.ts
Normal 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
68
std/node/fs.ts
Normal 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
47
std/node/fs_test.ts
Normal 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
1
std/node/testdata/hello.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
hello world
|
47
std/node/util.ts
Normal file
47
std/node/util.ts
Normal 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
122
std/node/util_test.ts
Normal 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));
|
||||
}
|
||||
});
|
Loading…
Reference in a new issue