1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-22 06:09:25 -05:00

feat(std/node): consistent Node.js builtin shapes (#8274)

This commit is contained in:
Guy Bedford 2020-11-09 06:25:13 -08:00 committed by GitHub
parent 293cae5e1f
commit 8b7f5531ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 1900 additions and 1843 deletions

599
std/node/_buffer.ts Normal file
View file

@ -0,0 +1,599 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import * as hex from "../encoding/hex.ts";
import * as base64 from "../encoding/base64.ts";
import { normalizeEncoding, notImplemented } from "./_utils.ts";
const notImplementedEncodings = [
"ascii",
"binary",
"latin1",
"ucs2",
"utf16le",
];
function checkEncoding(encoding = "utf8", strict = true): string {
if (typeof encoding !== "string" || (strict && encoding === "")) {
if (!strict) return "utf8";
throw new TypeError(`Unkown encoding: ${encoding}`);
}
const normalized = normalizeEncoding(encoding);
if (normalized === undefined) {
throw new TypeError(`Unkown encoding: ${encoding}`);
}
if (notImplementedEncodings.includes(encoding)) {
notImplemented(`"${encoding}" encoding`);
}
return normalized;
}
interface EncodingOp {
byteLength(string: string): number;
}
// https://github.com/nodejs/node/blob/56dbe466fdbc598baea3bfce289bf52b97b8b8f7/lib/buffer.js#L598
const encodingOps: { [key: string]: EncodingOp } = {
utf8: {
byteLength: (string: string): number =>
new TextEncoder().encode(string).byteLength,
},
ucs2: {
byteLength: (string: string): number => string.length * 2,
},
utf16le: {
byteLength: (string: string): number => string.length * 2,
},
latin1: {
byteLength: (string: string): number => string.length,
},
ascii: {
byteLength: (string: string): number => string.length,
},
base64: {
byteLength: (string: string): number =>
base64ByteLength(string, string.length),
},
hex: {
byteLength: (string: string): number => string.length >>> 1,
},
};
function base64ByteLength(str: string, bytes: number): number {
// Handle padding
if (str.charCodeAt(bytes - 1) === 0x3d) bytes--;
if (bytes > 1 && str.charCodeAt(bytes - 1) === 0x3d) bytes--;
// Base64 ratio: 3/4
return (bytes * 3) >>> 2;
}
/**
* See also https://nodejs.org/api/buffer.html
*/
export class Buffer extends Uint8Array {
/**
* Allocates a new Buffer of size bytes.
*/
static alloc(
size: number,
fill?: number | string | Uint8Array | Buffer,
encoding = "utf8",
): Buffer {
if (typeof size !== "number") {
throw new TypeError(
`The "size" argument must be of type number. Received type ${typeof size}`,
);
}
const buf = new Buffer(size);
if (size === 0) return buf;
let bufFill;
if (typeof fill === "string") {
encoding = checkEncoding(encoding);
if (
typeof fill === "string" &&
fill.length === 1 &&
encoding === "utf8"
) {
buf.fill(fill.charCodeAt(0));
} else bufFill = Buffer.from(fill, encoding);
} else if (typeof fill === "number") {
buf.fill(fill);
} else if (fill instanceof Uint8Array) {
if (fill.length === 0) {
throw new TypeError(
`The argument "value" is invalid. Received ${fill.constructor.name} []`,
);
}
bufFill = fill;
}
if (bufFill) {
if (bufFill.length > buf.length) {
bufFill = bufFill.subarray(0, buf.length);
}
let offset = 0;
while (offset < size) {
buf.set(bufFill, offset);
offset += bufFill.length;
if (offset + bufFill.length >= size) break;
}
if (offset !== size) {
buf.set(bufFill.subarray(0, size - offset), offset);
}
}
return buf;
}
static allocUnsafe(size: number): Buffer {
return new Buffer(size);
}
/**
* Returns the byte length of a string when encoded. This is not the same as
* String.prototype.length, which does not account for the encoding that is
* used to convert the string into bytes.
*/
static byteLength(
string: string | Buffer | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
encoding = "utf8",
): number {
if (typeof string != "string") return string.byteLength;
encoding = normalizeEncoding(encoding) || "utf8";
return encodingOps[encoding].byteLength(string);
}
/**
* Returns a new Buffer which is the result of concatenating all the Buffer
* instances in the list together.
*/
static concat(list: Buffer[] | Uint8Array[], totalLength?: number): Buffer {
if (totalLength == undefined) {
totalLength = 0;
for (const buf of list) {
totalLength += buf.length;
}
}
const buffer = Buffer.allocUnsafe(totalLength);
let pos = 0;
for (const item of list) {
let buf: Buffer;
if (!(item instanceof Buffer)) {
buf = Buffer.from(item);
} else {
buf = item;
}
buf.copy(buffer, pos);
pos += buf.length;
}
return buffer;
}
/**
* Allocates a new Buffer using an array of bytes in the range 0 255. Array
* entries outside that range will be truncated to fit into it.
*/
static from(array: number[]): Buffer;
/**
* This creates a view of the ArrayBuffer without copying the underlying
* memory. For example, when passed a reference to the .buffer property of a
* TypedArray instance, the newly created Buffer will share the same allocated
* memory as the TypedArray.
*/
static from(
arrayBuffer: ArrayBuffer | SharedArrayBuffer,
byteOffset?: number,
length?: number,
): Buffer;
/**
* Copies the passed buffer data onto a new Buffer instance.
*/
static from(buffer: Buffer | Uint8Array): Buffer;
/**
* Creates a new Buffer containing string.
*/
static from(string: string, encoding?: string): Buffer;
static from(
// deno-lint-ignore no-explicit-any
value: any,
offsetOrEncoding?: number | string,
length?: number,
): Buffer {
const offset = typeof offsetOrEncoding === "string"
? undefined
: offsetOrEncoding;
let encoding = typeof offsetOrEncoding === "string"
? offsetOrEncoding
: undefined;
if (typeof value == "string") {
encoding = checkEncoding(encoding, false);
if (encoding === "hex") return new Buffer(hex.decodeString(value).buffer);
if (encoding === "base64") return new Buffer(base64.decode(value).buffer);
return new Buffer(new TextEncoder().encode(value).buffer);
}
// workaround for https://github.com/microsoft/TypeScript/issues/38446
return new Buffer(value, offset!, length);
}
/**
* Returns true if obj is a Buffer, false otherwise.
*/
static isBuffer(obj: unknown): obj is Buffer {
return obj instanceof Buffer;
}
// deno-lint-ignore no-explicit-any
static isEncoding(encoding: any): boolean {
return (
typeof encoding === "string" &&
encoding.length !== 0 &&
normalizeEncoding(encoding) !== undefined
);
}
/**
* Copies data from a region of buf to a region in target, even if the target
* memory region overlaps with buf.
*/
copy(
targetBuffer: Buffer | Uint8Array,
targetStart = 0,
sourceStart = 0,
sourceEnd = this.length,
): number {
const sourceBuffer = this
.subarray(sourceStart, sourceEnd)
.subarray(0, Math.max(0, targetBuffer.length - targetStart));
if (sourceBuffer.length === 0) return 0;
targetBuffer.set(sourceBuffer, targetStart);
return sourceBuffer.length;
}
/*
* Returns true if both buf and otherBuffer have exactly the same bytes, false otherwise.
*/
equals(otherBuffer: Uint8Array | Buffer): boolean {
if (!(otherBuffer instanceof Uint8Array)) {
throw new TypeError(
`The "otherBuffer" argument must be an instance of Buffer or Uint8Array. Received type ${typeof otherBuffer}`,
);
}
if (this === otherBuffer) return true;
if (this.byteLength !== otherBuffer.byteLength) return false;
for (let i = 0; i < this.length; i++) {
if (this[i] !== otherBuffer[i]) return false;
}
return true;
}
readBigInt64BE(offset = 0): bigint {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getBigInt64(offset);
}
readBigInt64LE(offset = 0): bigint {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getBigInt64(offset, true);
}
readBigUInt64BE(offset = 0): bigint {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getBigUint64(offset);
}
readBigUInt64LE(offset = 0): bigint {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getBigUint64(offset, true);
}
readDoubleBE(offset = 0): number {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getFloat64(offset);
}
readDoubleLE(offset = 0): number {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getFloat64(offset, true);
}
readFloatBE(offset = 0): number {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getFloat32(offset);
}
readFloatLE(offset = 0): number {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getFloat32(offset, true);
}
readInt8(offset = 0): number {
return new DataView(this.buffer, this.byteOffset, this.byteLength).getInt8(
offset,
);
}
readInt16BE(offset = 0): number {
return new DataView(this.buffer, this.byteOffset, this.byteLength).getInt16(
offset,
);
}
readInt16LE(offset = 0): number {
return new DataView(this.buffer, this.byteOffset, this.byteLength).getInt16(
offset,
true,
);
}
readInt32BE(offset = 0): number {
return new DataView(this.buffer, this.byteOffset, this.byteLength).getInt32(
offset,
);
}
readInt32LE(offset = 0): number {
return new DataView(this.buffer, this.byteOffset, this.byteLength).getInt32(
offset,
true,
);
}
readUInt8(offset = 0): number {
return new DataView(this.buffer, this.byteOffset, this.byteLength).getUint8(
offset,
);
}
readUInt16BE(offset = 0): number {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getUint16(offset);
}
readUInt16LE(offset = 0): number {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getUint16(offset, true);
}
readUInt32BE(offset = 0): number {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getUint32(offset);
}
readUInt32LE(offset = 0): number {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getUint32(offset, true);
}
/**
* Returns a new Buffer that references the same memory as the original, but
* offset and cropped by the start and end indices.
*/
slice(begin = 0, end = this.length): Buffer {
// workaround for https://github.com/microsoft/TypeScript/issues/38665
return this.subarray(begin, end) as Buffer;
}
/**
* Returns a JSON representation of buf. JSON.stringify() implicitly calls
* this function when stringifying a Buffer instance.
*/
toJSON(): Record<string, unknown> {
return { type: "Buffer", data: Array.from(this) };
}
/**
* Decodes buf to a string according to the specified character encoding in
* encoding. start and end may be passed to decode only a subset of buf.
*/
toString(encoding = "utf8", start = 0, end = this.length): string {
encoding = checkEncoding(encoding);
const b = this.subarray(start, end);
if (encoding === "hex") return hex.encodeToString(b);
if (encoding === "base64") return base64.encode(b.buffer);
return new TextDecoder(encoding).decode(b);
}
/**
* Writes string to buf at offset according to the character encoding in
* encoding. The length parameter is the number of bytes to write. If buf did
* not contain enough space to fit the entire string, only part of string will
* be written. However, partially encoded characters will not be written.
*/
write(string: string, offset = 0, length = this.length): number {
return new TextEncoder().encodeInto(
string,
this.subarray(offset, offset + length),
).written;
}
writeBigInt64BE(value: bigint, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setBigInt64(
offset,
value,
);
return offset + 4;
}
writeBigInt64LE(value: bigint, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setBigInt64(
offset,
value,
true,
);
return offset + 4;
}
writeBigUInt64BE(value: bigint, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setBigUint64(
offset,
value,
);
return offset + 4;
}
writeBigUInt64LE(value: bigint, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setBigUint64(
offset,
value,
true,
);
return offset + 4;
}
writeDoubleBE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setFloat64(
offset,
value,
);
return offset + 8;
}
writeDoubleLE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setFloat64(
offset,
value,
true,
);
return offset + 8;
}
writeFloatBE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setFloat32(
offset,
value,
);
return offset + 4;
}
writeFloatLE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setFloat32(
offset,
value,
true,
);
return offset + 4;
}
writeInt8(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setInt8(
offset,
value,
);
return offset + 1;
}
writeInt16BE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setInt16(
offset,
value,
);
return offset + 2;
}
writeInt16LE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setInt16(
offset,
value,
true,
);
return offset + 2;
}
writeInt32BE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setUint32(
offset,
value,
);
return offset + 4;
}
writeInt32LE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setInt32(
offset,
value,
true,
);
return offset + 4;
}
writeUInt8(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setUint8(
offset,
value,
);
return offset + 1;
}
writeUInt16BE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setUint16(
offset,
value,
);
return offset + 2;
}
writeUInt16LE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setUint16(
offset,
value,
true,
);
return offset + 2;
}
writeUInt32BE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setUint32(
offset,
value,
);
return offset + 4;
}
writeUInt32LE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setUint32(
offset,
value,
true,
);
return offset + 4;
}
}

3
std/node/_crypto.ts Normal file
View file

@ -0,0 +1,3 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
export { default as randomBytes } from "./_crypto/randomBytes.ts";
export { pbkdf2, pbkdf2Sync } from "./_crypto/pbkdf2.ts";

View file

@ -1,5 +1,5 @@
import { createHash } from "../../hash/mod.ts";
import Buffer from "../buffer.ts";
import { Buffer } from "../buffer.ts";
import { MAX_ALLOC } from "./constants.ts";
import { HASH_DATA } from "./types.ts";

View file

@ -1,4 +1,4 @@
import Buffer from "../buffer.ts";
import { Buffer } from "../buffer.ts";
export const MAX_RANDOM_VALUES = 65536;
export const MAX_SIZE = 4294967295;

View file

@ -1,3 +1,3 @@
import Buffer from "../buffer.ts";
import { Buffer } from "../buffer.ts";
export type HASH_DATA = string | ArrayBufferView | Buffer;

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

@ -0,0 +1,68 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { access, accessSync } from "./_fs/_fs_access.ts";
import { appendFile, appendFileSync } from "./_fs/_fs_appendFile.ts";
import { chmod, chmodSync } from "./_fs/_fs_chmod.ts";
import { chown, chownSync } from "./_fs/_fs_chown.ts";
import { close, closeSync } from "./_fs/_fs_close.ts";
import * as constants from "./_fs/_fs_constants.ts";
import { readFile, readFileSync } from "./_fs/_fs_readFile.ts";
import { readlink, readlinkSync } from "./_fs/_fs_readlink.ts";
import { exists, existsSync } from "./_fs/_fs_exists.ts";
import { mkdir, mkdirSync } from "./_fs/_fs_mkdir.ts";
import { copyFile, copyFileSync } from "./_fs/_fs_copy.ts";
import { writeFile, writeFileSync } from "./_fs/_fs_writeFile.ts";
import { readdir, readdirSync } from "./_fs/_fs_readdir.ts";
import { realpath, realpathSync } from "./_fs/_fs_realpath.ts";
import { rename, renameSync } from "./_fs/_fs_rename.ts";
import { rmdir, rmdirSync } from "./_fs/_fs_rmdir.ts";
import { unlink, unlinkSync } from "./_fs/_fs_unlink.ts";
import { watch } from "./_fs/_fs_watch.ts";
import { open, openSync } from "./_fs/_fs_open.ts";
import { stat, statSync } from "./_fs/_fs_stat.ts";
import { lstat, lstatSync } from "./_fs/_fs_lstat.ts";
import * as promises from "./_fs/promises/mod.ts";
export {
access,
accessSync,
appendFile,
appendFileSync,
chmod,
chmodSync,
chown,
chownSync,
close,
closeSync,
constants,
copyFile,
copyFileSync,
exists,
existsSync,
lstat,
lstatSync,
mkdir,
mkdirSync,
open,
openSync,
promises,
readdir,
readdirSync,
readFile,
readFileSync,
readlink,
readlinkSync,
realpath,
realpathSync,
rename,
renameSync,
rmdir,
rmdirSync,
stat,
statSync,
unlink,
unlinkSync,
watch,
writeFile,
writeFileSync,
};

224
std/node/_os.ts Normal file
View file

@ -0,0 +1,224 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
import { notImplemented } from "./_utils.ts";
import { validateIntegerRange } from "./_utils.ts";
import { EOL as fsEOL } from "../fs/eol.ts";
import process from "./process.ts";
const SEE_GITHUB_ISSUE = "See https://github.com/denoland/deno/issues/3802";
interface CPUTimes {
/** The number of milliseconds the CPU has spent in user mode */
user: number;
/** The number of milliseconds the CPU has spent in nice mode */
nice: number;
/** The number of milliseconds the CPU has spent in sys mode */
sys: number;
/** The number of milliseconds the CPU has spent in idle mode */
idle: number;
/** The number of milliseconds the CPU has spent in irq mode */
irq: number;
}
interface CPUCoreInfo {
model: string;
/** in MHz */
speed: number;
times: CPUTimes;
}
interface NetworkAddress {
/** The assigned IPv4 or IPv6 address */
address: string;
/** The IPv4 or IPv6 network mask */
netmask: string;
family: "IPv4" | "IPv6";
/** The MAC address of the network interface */
mac: string;
/** true if the network interface is a loopback or similar interface that is not remotely accessible; otherwise false */
internal: boolean;
/** The numeric IPv6 scope ID (only specified when family is IPv6) */
scopeid?: number;
/** The assigned IPv4 or IPv6 address with the routing prefix in CIDR notation. If the netmask is invalid, this property is set to null. */
cidr: string;
}
interface NetworkInterfaces {
[key: string]: NetworkAddress[];
}
export interface UserInfoOptions {
encoding: string;
}
interface UserInfo {
username: string;
uid: number;
gid: number;
shell: string;
homedir: string;
}
arch[Symbol.toPrimitive] = (): string => arch();
endianness[Symbol.toPrimitive] = (): string => endianness();
freemem[Symbol.toPrimitive] = (): number => freemem();
homedir[Symbol.toPrimitive] = (): string | null => homedir();
hostname[Symbol.toPrimitive] = (): string | null => hostname();
platform[Symbol.toPrimitive] = (): string => platform();
release[Symbol.toPrimitive] = (): string => release();
totalmem[Symbol.toPrimitive] = (): number => totalmem();
type[Symbol.toPrimitive] = (): string => type();
uptime[Symbol.toPrimitive] = (): number => uptime();
/** Returns the operating system CPU architecture for which the Deno binary was compiled */
export function arch(): string {
return Deno.build.arch;
}
/** Not yet implemented */
export function cpus(): CPUCoreInfo[] {
notImplemented(SEE_GITHUB_ISSUE);
}
/**
* Returns a string identifying the endianness of the CPU for which the Deno
* binary was compiled. Possible values are 'BE' for big endian and 'LE' for
* little endian.
**/
export function endianness(): "BE" | "LE" {
// Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView#Endianness
const buffer = new ArrayBuffer(2);
new DataView(buffer).setInt16(0, 256, true /* littleEndian */);
// Int16Array uses the platform's endianness.
return new Int16Array(buffer)[0] === 256 ? "LE" : "BE";
}
/** Not yet implemented */
export function freemem(): number {
notImplemented(SEE_GITHUB_ISSUE);
}
/** Not yet implemented */
export function getPriority(pid = 0): number {
validateIntegerRange(pid, "pid");
notImplemented(SEE_GITHUB_ISSUE);
}
/** Returns the string path of the current user's home directory. */
export function homedir(): string | null {
notImplemented(SEE_GITHUB_ISSUE);
}
/** Returns the host name of the operating system as a string. */
export function hostname(): string {
notImplemented(SEE_GITHUB_ISSUE);
}
/** Returns an array containing the 1, 5, and 15 minute load averages */
export function loadavg(): number[] {
if (Deno.build.os === "windows") {
return [0, 0, 0];
}
return Deno.loadavg();
}
/** Not yet implemented */
export function networkInterfaces(): NetworkInterfaces {
notImplemented(SEE_GITHUB_ISSUE);
}
/** Returns the a string identifying the operating system platform. The value is set at compile time. Possible values are 'darwin', 'linux', and 'win32'. */
export function platform(): string {
return process.platform;
}
/** Returns the operating system as a string */
export function release(): string {
return Deno.osRelease();
}
/** Not yet implemented */
export function setPriority(pid: number, priority?: number): void {
/* The node API has the 'pid' as the first parameter and as optional.
This makes for a problematic implementation in Typescript. */
if (priority === undefined) {
priority = pid;
pid = 0;
}
validateIntegerRange(pid, "pid");
validateIntegerRange(priority, "priority", -20, 19);
notImplemented(SEE_GITHUB_ISSUE);
}
/** Returns the operating system's default directory for temporary files as a string. */
export function tmpdir(): string | null {
notImplemented(SEE_GITHUB_ISSUE);
}
/** Not yet implemented */
export function totalmem(): number {
notImplemented(SEE_GITHUB_ISSUE);
}
/** Not yet implemented */
export function type(): string {
notImplemented(SEE_GITHUB_ISSUE);
}
/** Not yet implemented */
export function uptime(): number {
notImplemented(SEE_GITHUB_ISSUE);
}
/** Not yet implemented */
export function userInfo(
options: UserInfoOptions = { encoding: "utf-8" },
): UserInfo {
notImplemented(SEE_GITHUB_ISSUE);
}
export const constants = {
// UV_UDP_REUSEADDR: 4, //see https://nodejs.org/docs/latest-v12.x/api/os.html#os_libuv_constants
dlopen: {
// see https://nodejs.org/docs/latest-v12.x/api/os.html#os_dlopen_constants
},
errno: {
// see https://nodejs.org/docs/latest-v12.x/api/os.html#os_error_constants
},
signals: Deno.Signal,
priority: {
// see https://nodejs.org/docs/latest-v12.x/api/os.html#os_priority_constants
},
};
export const EOL = Deno.build.os == "windows" ? fsEOL.CRLF : fsEOL.LF;

156
std/node/_querystring.ts Normal file
View file

@ -0,0 +1,156 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
interface ParseOptions {
/** The function to use when decoding percent-encoded characters in the query string. */
decodeURIComponent?: (string: string) => string;
/** Specifies the maximum number of keys to parse. */
maxKeys?: number;
}
export const hexTable = new Array(256);
for (let i = 0; i < 256; ++i) {
hexTable[i] = "%" + ((i < 16 ? "0" : "") + i.toString(16)).toUpperCase();
}
/**
* Parses a URL query string into a collection of key and value pairs.
* @param str The URL query string to parse
* @param sep The substring used to delimit key and value pairs in the query string. Default: '&'.
* @param eq The substring used to delimit keys and values in the query string. Default: '='.
* @param options The parse options
*/
export function parse(
str: string,
sep = "&",
eq = "=",
{ decodeURIComponent = unescape, maxKeys = 1000 }: ParseOptions = {},
): { [key: string]: string[] | string } {
const entries = str
.split(sep)
.map((entry) => entry.split(eq).map(decodeURIComponent));
const final: { [key: string]: string[] | string } = {};
let i = 0;
while (true) {
if ((Object.keys(final).length === maxKeys && !!maxKeys) || !entries[i]) {
break;
}
const [key, val] = entries[i];
if (final[key]) {
if (Array.isArray(final[key])) {
(final[key] as string[]).push(val);
} else {
final[key] = [final[key] as string, val];
}
} else {
final[key] = val;
}
i++;
}
return final;
}
interface StringifyOptions {
/** The function to use when converting URL-unsafe characters to percent-encoding in the query string. */
encodeURIComponent?: (string: string) => string;
}
export function encodeStr(
str: string,
noEscapeTable: number[],
hexTable: string[],
): string {
const len = str.length;
if (len === 0) return "";
let out = "";
let lastPos = 0;
for (let i = 0; i < len; i++) {
let c = str.charCodeAt(i);
// ASCII
if (c < 0x80) {
if (noEscapeTable[c] === 1) continue;
if (lastPos < i) out += str.slice(lastPos, i);
lastPos = i + 1;
out += hexTable[c];
continue;
}
if (lastPos < i) out += str.slice(lastPos, i);
// Multi-byte characters ...
if (c < 0x800) {
lastPos = i + 1;
out += hexTable[0xc0 | (c >> 6)] + hexTable[0x80 | (c & 0x3f)];
continue;
}
if (c < 0xd800 || c >= 0xe000) {
lastPos = i + 1;
out += hexTable[0xe0 | (c >> 12)] +
hexTable[0x80 | ((c >> 6) & 0x3f)] +
hexTable[0x80 | (c & 0x3f)];
continue;
}
// Surrogate pair
++i;
// This branch should never happen because all URLSearchParams entries
// should already be converted to USVString. But, included for
// completion's sake anyway.
if (i >= len) throw new Deno.errors.InvalidData("invalid URI");
const c2 = str.charCodeAt(i) & 0x3ff;
lastPos = i + 1;
c = 0x10000 + (((c & 0x3ff) << 10) | c2);
out += hexTable[0xf0 | (c >> 18)] +
hexTable[0x80 | ((c >> 12) & 0x3f)] +
hexTable[0x80 | ((c >> 6) & 0x3f)] +
hexTable[0x80 | (c & 0x3f)];
}
if (lastPos === 0) return str;
if (lastPos < len) return out + str.slice(lastPos);
return out;
}
/**
* Produces a URL query string from a given obj by iterating through the object's "own properties".
* @param obj The object to serialize into a URL query string.
* @param sep The substring used to delimit key and value pairs in the query string. Default: '&'.
* @param eq The substring used to delimit keys and values in the query string. Default: '='.
* @param options The stringify options
*/
export function stringify(
// deno-lint-ignore no-explicit-any
obj: Record<string, any>,
sep = "&",
eq = "=",
{ encodeURIComponent = escape }: StringifyOptions = {},
): string {
const final = [];
for (const entry of Object.entries(obj)) {
if (Array.isArray(entry[1])) {
for (const val of entry[1]) {
final.push(encodeURIComponent(entry[0]) + eq + encodeURIComponent(val));
}
} else if (typeof entry[1] !== "object" && entry[1] !== undefined) {
final.push(entry.map(encodeURIComponent).join(eq));
} else {
final.push(encodeURIComponent(entry[0]) + eq);
}
}
return final.join(sep);
}
/** Alias of querystring.parse() */
export const decode = parse;
/** Alias of querystring.stringify() */
export const encode = stringify;
export const unescape = decodeURIComponent;
export const escape = encodeURIComponent;

299
std/node/_string_decoder.ts Normal file
View file

@ -0,0 +1,299 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
import { Buffer } from "./buffer.ts";
import { normalizeEncoding as castEncoding, notImplemented } from "./_utils.ts";
enum NotImplemented {
"ascii",
"latin1",
"utf16le",
}
function normalizeEncoding(enc?: string): string {
const encoding = castEncoding(enc ?? null);
if (encoding && encoding in NotImplemented) notImplemented(encoding);
if (!encoding && typeof enc === "string" && enc.toLowerCase() !== "raw") {
throw new Error(`Unknown encoding: ${enc}`);
}
return String(encoding);
}
/*
* Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a
* continuation byte. If an invalid byte is detected, -2 is returned.
* */
function utf8CheckByte(byte: number): number {
if (byte <= 0x7f) return 0;
else if (byte >> 5 === 0x06) return 2;
else if (byte >> 4 === 0x0e) return 3;
else if (byte >> 3 === 0x1e) return 4;
return byte >> 6 === 0x02 ? -1 : -2;
}
/*
* Checks at most 3 bytes at the end of a Buffer in order to detect an
* incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4)
* needed to complete the UTF-8 character (if applicable) are returned.
* */
function utf8CheckIncomplete(
self: StringDecoderBase,
buf: Buffer,
i: number,
): number {
let j = buf.length - 1;
if (j < i) return 0;
let nb = utf8CheckByte(buf[j]);
if (nb >= 0) {
if (nb > 0) self.lastNeed = nb - 1;
return nb;
}
if (--j < i || nb === -2) return 0;
nb = utf8CheckByte(buf[j]);
if (nb >= 0) {
if (nb > 0) self.lastNeed = nb - 2;
return nb;
}
if (--j < i || nb === -2) return 0;
nb = utf8CheckByte(buf[j]);
if (nb >= 0) {
if (nb > 0) {
if (nb === 2) nb = 0;
else self.lastNeed = nb - 3;
}
return nb;
}
return 0;
}
/*
* Validates as many continuation bytes for a multi-byte UTF-8 character as
* needed or are available. If we see a non-continuation byte where we expect
* one, we "replace" the validated continuation bytes we've seen so far with
* a single UTF-8 replacement character ('\ufffd'), to match v8's UTF-8 decoding
* behavior. The continuation byte check is included three times in the case
* where all of the continuation bytes for a character exist in the same buffer.
* It is also done this way as a slight performance increase instead of using a
* loop.
* */
function utf8CheckExtraBytes(
self: StringDecoderBase,
buf: Buffer,
): string | undefined {
if ((buf[0] & 0xc0) !== 0x80) {
self.lastNeed = 0;
return "\ufffd";
}
if (self.lastNeed > 1 && buf.length > 1) {
if ((buf[1] & 0xc0) !== 0x80) {
self.lastNeed = 1;
return "\ufffd";
}
if (self.lastNeed > 2 && buf.length > 2) {
if ((buf[2] & 0xc0) !== 0x80) {
self.lastNeed = 2;
return "\ufffd";
}
}
}
}
/*
* Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer.
* */
function utf8FillLastComplete(
this: StringDecoderBase,
buf: Buffer,
): string | undefined {
const p = this.lastTotal - this.lastNeed;
const r = utf8CheckExtraBytes(this, buf);
if (r !== undefined) return r;
if (this.lastNeed <= buf.length) {
buf.copy(this.lastChar, p, 0, this.lastNeed);
return this.lastChar.toString(this.encoding, 0, this.lastTotal);
}
buf.copy(this.lastChar, p, 0, buf.length);
this.lastNeed -= buf.length;
}
/*
* Attempts to complete a partial non-UTF-8 character using bytes from a Buffer
* */
function utf8FillLastIncomplete(
this: StringDecoderBase,
buf: Buffer,
): string | undefined {
if (this.lastNeed <= buf.length) {
buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed);
return this.lastChar.toString(this.encoding, 0, this.lastTotal);
}
buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length);
this.lastNeed -= buf.length;
}
/*
* Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a
* partial character, the character's bytes are buffered until the required
* number of bytes are available.
* */
function utf8Text(this: StringDecoderBase, buf: Buffer, i: number): string {
const total = utf8CheckIncomplete(this, buf, i);
if (!this.lastNeed) return buf.toString("utf8", i);
this.lastTotal = total;
const end = buf.length - (total - this.lastNeed);
buf.copy(this.lastChar, 0, end);
return buf.toString("utf8", i, end);
}
/*
* For UTF-8, a replacement character is added when ending on a partial
* character.
* */
function utf8End(this: Utf8Decoder, buf?: Buffer): string {
const r = buf && buf.length ? this.write(buf) : "";
if (this.lastNeed) return r + "\ufffd";
return r;
}
function utf8Write(this: Utf8Decoder | Base64Decoder, buf: Buffer): string {
if (buf.length === 0) return "";
let r;
let i;
if (this.lastNeed) {
r = this.fillLast(buf);
if (r === undefined) return "";
i = this.lastNeed;
this.lastNeed = 0;
} else {
i = 0;
}
if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i);
return r || "";
}
function base64Text(this: StringDecoderBase, buf: Buffer, i: number): string {
const n = (buf.length - i) % 3;
if (n === 0) return buf.toString("base64", i);
this.lastNeed = 3 - n;
this.lastTotal = 3;
if (n === 1) {
this.lastChar[0] = buf[buf.length - 1];
} else {
this.lastChar[0] = buf[buf.length - 2];
this.lastChar[1] = buf[buf.length - 1];
}
return buf.toString("base64", i, buf.length - n);
}
function base64End(this: Base64Decoder, buf?: Buffer): string {
const r = buf && buf.length ? this.write(buf) : "";
if (this.lastNeed) {
return r + this.lastChar.toString("base64", 0, 3 - this.lastNeed);
}
return r;
}
function simpleWrite(this: StringDecoderBase, buf: Buffer): string {
return buf.toString(this.encoding);
}
function simpleEnd(this: GenericDecoder, buf?: Buffer): string {
return buf && buf.length ? this.write(buf) : "";
}
class StringDecoderBase {
public lastChar: Buffer;
public lastNeed = 0;
public lastTotal = 0;
constructor(public encoding: string, nb: number) {
this.lastChar = Buffer.allocUnsafe(nb);
}
}
class Base64Decoder extends StringDecoderBase {
public end = base64End;
public fillLast = utf8FillLastIncomplete;
public text = base64Text;
public write = utf8Write;
constructor(encoding?: string) {
super(normalizeEncoding(encoding), 3);
}
}
class GenericDecoder extends StringDecoderBase {
public end = simpleEnd;
public fillLast = undefined;
public text = utf8Text;
public write = simpleWrite;
constructor(encoding?: string) {
super(normalizeEncoding(encoding), 4);
}
}
class Utf8Decoder extends StringDecoderBase {
public end = utf8End;
public fillLast = utf8FillLastComplete;
public text = utf8Text;
public write = utf8Write;
constructor(encoding?: string) {
super(normalizeEncoding(encoding), 4);
}
}
/*
* StringDecoder provides an interface for efficiently splitting a series of
* buffers into a series of JS strings without breaking apart multi-byte
* characters.
* */
export class StringDecoder {
public encoding: string;
public end: (buf?: Buffer) => string;
public fillLast: ((buf: Buffer) => string | undefined) | undefined;
public lastChar: Buffer;
public lastNeed: number;
public lastTotal: number;
public text: (buf: Buffer, n: number) => string;
public write: (buf: Buffer) => string;
constructor(encoding?: string) {
let decoder;
switch (encoding) {
case "utf8":
decoder = new Utf8Decoder(encoding);
break;
case "base64":
decoder = new Base64Decoder(encoding);
break;
default:
decoder = new GenericDecoder(encoding);
}
this.encoding = decoder.encoding;
this.end = decoder.end;
this.fillLast = decoder.fillLast;
this.lastChar = decoder.lastChar;
this.lastNeed = decoder.lastNeed;
this.lastTotal = decoder.lastTotal;
this.text = decoder.text;
this.write = decoder.write;
}
}

14
std/node/_timers.ts Normal file
View file

@ -0,0 +1,14 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// TODO: implement the 'NodeJS.Timeout' and 'NodeJS.Immediate' versions of the timers.
// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/1163ead296d84e7a3c80d71e7c81ecbd1a130e9a/types/node/v12/globals.d.ts#L1120-L1131
export const setTimeout = window.setTimeout;
export const clearTimeout = window.clearTimeout;
export const setInterval = window.setInterval;
export const clearInterval = window.clearInterval;
export const setImmediate = (
// deno-lint-ignore no-explicit-any
cb: (...args: any[]) => void,
// deno-lint-ignore no-explicit-any
...args: any[]
): number => window.setTimeout(cb, 0, ...args);
export const clearImmediate = window.clearTimeout;

140
std/node/_url.ts Normal file
View file

@ -0,0 +1,140 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
import {
CHAR_BACKWARD_SLASH,
CHAR_FORWARD_SLASH,
CHAR_LOWERCASE_A,
CHAR_LOWERCASE_Z,
} from "../path/_constants.ts";
import * as path from "./path.ts";
const isWindows = Deno.build.os === "windows";
const forwardSlashRegEx = /\//g;
const percentRegEx = /%/g;
const backslashRegEx = /\\/g;
const newlineRegEx = /\n/g;
const carriageReturnRegEx = /\r/g;
const tabRegEx = /\t/g;
const _url = URL;
export { _url as URL };
/**
* Get fully resolved platform-specific file path from the given URL string/ object
* @param path The file URL string or URL object to convert to a path
*/
export function fileURLToPath(path: string | URL): string {
if (typeof path === "string") path = new URL(path);
else if (!(path instanceof URL)) {
throw new Deno.errors.InvalidData(
"invalid argument path , must be a string or URL",
);
}
if (path.protocol !== "file:") {
throw new Deno.errors.InvalidData("invalid url scheme");
}
return isWindows ? getPathFromURLWin(path) : getPathFromURLPosix(path);
}
function getPathFromURLWin(url: URL): string {
const hostname = url.hostname;
let pathname = url.pathname;
for (let n = 0; n < pathname.length; n++) {
if (pathname[n] === "%") {
const third = pathname.codePointAt(n + 2) || 0x20;
if (
(pathname[n + 1] === "2" && third === 102) || // 2f 2F /
(pathname[n + 1] === "5" && third === 99)
) {
// 5c 5C \
throw new Deno.errors.InvalidData(
"must not include encoded \\ or / characters",
);
}
}
}
pathname = pathname.replace(forwardSlashRegEx, "\\");
pathname = decodeURIComponent(pathname);
if (hostname !== "") {
//TODO add support for punycode encodings
return `\\\\${hostname}${pathname}`;
} else {
// Otherwise, it's a local path that requires a drive letter
const letter = pathname.codePointAt(1)! | 0x20;
const sep = pathname[2];
if (
letter < CHAR_LOWERCASE_A ||
letter > CHAR_LOWERCASE_Z || // a..z A..Z
sep !== ":"
) {
throw new Deno.errors.InvalidData("file url path must be absolute");
}
return pathname.slice(1);
}
}
function getPathFromURLPosix(url: URL): string {
if (url.hostname !== "") {
throw new Deno.errors.InvalidData("invalid file url hostname");
}
const pathname = url.pathname;
for (let n = 0; n < pathname.length; n++) {
if (pathname[n] === "%") {
const third = pathname.codePointAt(n + 2) || 0x20;
if (pathname[n + 1] === "2" && third === 102) {
throw new Deno.errors.InvalidData(
"must not include encoded / characters",
);
}
}
}
return decodeURIComponent(pathname);
}
/** Get fully resolved platform-specific File URL from the given file path */
export function pathToFileURL(filepath: string): URL {
let resolved = path.resolve(filepath);
// path.resolve strips trailing slashes so we must add them back
const filePathLast = filepath.charCodeAt(filepath.length - 1);
if (
(filePathLast === CHAR_FORWARD_SLASH ||
(isWindows && filePathLast === CHAR_BACKWARD_SLASH)) &&
resolved[resolved.length - 1] !== path.sep
) {
resolved += "/";
}
const outURL = new URL("file://");
if (resolved.includes("%")) resolved = resolved.replace(percentRegEx, "%25");
// In posix, "/" is a valid character in paths
if (!isWindows && resolved.includes("\\")) {
resolved = resolved.replace(backslashRegEx, "%5C");
}
if (resolved.includes("\n")) resolved = resolved.replace(newlineRegEx, "%0A");
if (resolved.includes("\r")) {
resolved = resolved.replace(carriageReturnRegEx, "%0D");
}
if (resolved.includes("\t")) resolved = resolved.replace(tabRegEx, "%09");
outURL.pathname = resolved;
return outURL;
}

134
std/node/_util.ts Normal file
View file

@ -0,0 +1,134 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
export { promisify } from "./_util/_util_promisify.ts";
export { callbackify } from "./_util/_util_callbackify.ts";
import { codes, errorMap } from "./_errors.ts";
import * as types from "./_util/_util_types.ts";
export { types };
const NumberIsSafeInteger = Number.isSafeInteger;
const {
ERR_OUT_OF_RANGE,
ERR_INVALID_ARG_TYPE,
} = codes;
const DEFAULT_INSPECT_OPTIONS = {
showHidden: false,
depth: 2,
colors: false,
customInspect: true,
showProxy: false,
maxArrayLength: 100,
maxStringLength: Infinity,
breakLength: 80,
compact: 3,
sorted: false,
getters: false,
};
inspect.defaultOptions = DEFAULT_INSPECT_OPTIONS;
inspect.custom = Deno.customInspect;
// TODO(schwarzkopfb): make it in-line with Node's implementation
// Ref: https://nodejs.org/dist/latest-v14.x/docs/api/util.html#util_util_inspect_object_options
// deno-lint-ignore no-explicit-any
export function inspect(object: unknown, ...opts: any): string {
opts = { ...DEFAULT_INSPECT_OPTIONS, ...opts };
return Deno.inspect(object, {
depth: opts.depth,
iterableLimit: opts.maxArrayLength,
compact: !!opts.compact,
sorted: !!opts.sorted,
showProxy: !!opts.showProxy,
});
}
/** @deprecated - use `Array.isArray()` instead. */
export function isArray(value: unknown): boolean {
return Array.isArray(value);
}
/** @deprecated - use `typeof value === "boolean" || value instanceof Boolean` instead. */
export function isBoolean(value: unknown): boolean {
return typeof value === "boolean" || value instanceof Boolean;
}
/** @deprecated - use `value === null` instead. */
export function isNull(value: unknown): boolean {
return value === null;
}
/** @deprecated - use `value === null || value === undefined` instead. */
export function isNullOrUndefined(value: unknown): boolean {
return value === null || value === undefined;
}
/** @deprecated - use `typeof value === "number" || value instanceof Number` instead. */
export function isNumber(value: unknown): boolean {
return typeof value === "number" || value instanceof Number;
}
/** @deprecated - use `typeof value === "string" || value instanceof String` instead. */
export function isString(value: unknown): boolean {
return typeof value === "string" || value instanceof String;
}
/** @deprecated - use `typeof value === "symbol"` instead. */
export function isSymbol(value: unknown): boolean {
return typeof value === "symbol";
}
/** @deprecated - use `value === undefined` instead. */
export function isUndefined(value: unknown): boolean {
return value === undefined;
}
/** @deprecated - use `value !== null && typeof value === "object"` instead. */
export function isObject(value: unknown): boolean {
return value !== null && typeof value === "object";
}
/** @deprecated - use `e instanceof Error` instead. */
export function isError(e: unknown): boolean {
return e instanceof Error;
}
/** @deprecated - use `typeof value === "function"` instead. */
export function isFunction(value: unknown): boolean {
return typeof value === "function";
}
/** @deprecated - use `value instanceof RegExp` instead. */
export function isRegExp(value: unknown): boolean {
return value instanceof RegExp;
}
/** @deprecated - use `value === null || (typeof value !== "object" && typeof value !== "function")` instead. */
export function isPrimitive(value: unknown): boolean {
return (
value === null || (typeof value !== "object" && typeof value !== "function")
);
}
/**
* Returns a system error name from an error code number.
* @param code error code number
*/
export function getSystemErrorName(code: number): string | undefined {
if (typeof code !== "number") {
throw new ERR_INVALID_ARG_TYPE("err", "number", code);
}
if (code >= 0 || !NumberIsSafeInteger(code)) {
throw new ERR_OUT_OF_RANGE("err", "a negative integer", code);
}
return errorMap.get(code)?.[0];
}
import { _TextDecoder, _TextEncoder } from "./_utils.ts";
/** The global TextDecoder */
export type TextDecoder = import("./_utils.ts")._TextDecoder;
export const TextDecoder = _TextDecoder;
/** The global TextEncoder */
export type TextEncoder = import("./_utils.ts")._TextEncoder;
export const TextEncoder = _TextEncoder;

View file

@ -1,25 +1,42 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import {
assertEquals,
assertMatch,
assertNotEquals,
assertNotStrictEquals,
assertStrictEquals,
assertThrows,
} from "../testing/asserts.ts";
export { AssertionError } from "./assertion_error.ts";
export {
assert,
assert as default,
assert as ok,
import {
assertEquals as deepStrictEqual,
AssertionError,
assertMatch as match,
assertNotEquals as notDeepStrictEqual,
assertNotStrictEquals as notStrictEqual,
assertStrictEquals as strictEqual,
assertThrows as throws,
fail,
} from "../testing/asserts.ts";
export const deepStrictEqual = assertEquals;
export const notDeepStrictEqual = assertNotEquals;
export const strictEqual = assertStrictEquals;
export const notStrictEqual = assertNotStrictEquals;
export const match = assertMatch;
export const throws = assertThrows;
function assert(expr: unknown, msg = ""): asserts expr {
if (!expr) {
throw new AssertionError(msg);
}
}
const ok = assert;
export default assert;
Object.assign(assert, {
deepStrictEqual,
fail,
match,
notDeepStrictEqual,
notStrictEqual,
ok,
strictEqual,
throws,
});
export {
deepStrictEqual,
fail,
match,
notDeepStrictEqual,
notStrictEqual,
ok,
strictEqual,
throws,
};

View file

@ -13,7 +13,6 @@ import {
import AssertionError from "./assertion_error.ts";
import assert, {
assert as assert_,
AssertionError as AssertionError_,
deepStrictEqual,
fail,
@ -26,13 +25,7 @@ import assert, {
} from "./assert.ts";
Deno.test("API should be exposed", () => {
assertStrictEquals(
assert_,
assert,
"`assert()` should be the default export",
);
assertStrictEquals(assert_, denoAssert, "`assert()` should be exposed");
assertStrictEquals(assert_, ok, "`assert()` should be an alias of `ok()`");
assertStrictEquals(assert, ok, "`assert()` should be an alias of `ok()`");
assertStrictEquals(
assertEquals,
deepStrictEqual,

View file

@ -1,601 +1,4 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import * as hex from "../encoding/hex.ts";
import * as base64 from "../encoding/base64.ts";
import { normalizeEncoding, notImplemented } from "./_utils.ts";
const notImplementedEncodings = [
"ascii",
"binary",
"latin1",
"ucs2",
"utf16le",
];
function checkEncoding(encoding = "utf8", strict = true): string {
if (typeof encoding !== "string" || (strict && encoding === "")) {
if (!strict) return "utf8";
throw new TypeError(`Unkown encoding: ${encoding}`);
}
const normalized = normalizeEncoding(encoding);
if (normalized === undefined) {
throw new TypeError(`Unkown encoding: ${encoding}`);
}
if (notImplementedEncodings.includes(encoding)) {
notImplemented(`"${encoding}" encoding`);
}
return normalized;
}
interface EncodingOp {
byteLength(string: string): number;
}
// https://github.com/nodejs/node/blob/56dbe466fdbc598baea3bfce289bf52b97b8b8f7/lib/buffer.js#L598
const encodingOps: { [key: string]: EncodingOp } = {
utf8: {
byteLength: (string: string): number =>
new TextEncoder().encode(string).byteLength,
},
ucs2: {
byteLength: (string: string): number => string.length * 2,
},
utf16le: {
byteLength: (string: string): number => string.length * 2,
},
latin1: {
byteLength: (string: string): number => string.length,
},
ascii: {
byteLength: (string: string): number => string.length,
},
base64: {
byteLength: (string: string): number =>
base64ByteLength(string, string.length),
},
hex: {
byteLength: (string: string): number => string.length >>> 1,
},
};
function base64ByteLength(str: string, bytes: number): number {
// Handle padding
if (str.charCodeAt(bytes - 1) === 0x3d) bytes--;
if (bytes > 1 && str.charCodeAt(bytes - 1) === 0x3d) bytes--;
// Base64 ratio: 3/4
return (bytes * 3) >>> 2;
}
/**
* See also https://nodejs.org/api/buffer.html
*/
export default class Buffer extends Uint8Array {
/**
* Allocates a new Buffer of size bytes.
*/
static alloc(
size: number,
fill?: number | string | Uint8Array | Buffer,
encoding = "utf8",
): Buffer {
if (typeof size !== "number") {
throw new TypeError(
`The "size" argument must be of type number. Received type ${typeof size}`,
);
}
const buf = new Buffer(size);
if (size === 0) return buf;
let bufFill;
if (typeof fill === "string") {
encoding = checkEncoding(encoding);
if (
typeof fill === "string" &&
fill.length === 1 &&
encoding === "utf8"
) {
buf.fill(fill.charCodeAt(0));
} else bufFill = Buffer.from(fill, encoding);
} else if (typeof fill === "number") {
buf.fill(fill);
} else if (fill instanceof Uint8Array) {
if (fill.length === 0) {
throw new TypeError(
`The argument "value" is invalid. Received ${fill.constructor.name} []`,
);
}
bufFill = fill;
}
if (bufFill) {
if (bufFill.length > buf.length) {
bufFill = bufFill.subarray(0, buf.length);
}
let offset = 0;
while (offset < size) {
buf.set(bufFill, offset);
offset += bufFill.length;
if (offset + bufFill.length >= size) break;
}
if (offset !== size) {
buf.set(bufFill.subarray(0, size - offset), offset);
}
}
return buf;
}
static allocUnsafe(size: number): Buffer {
return new Buffer(size);
}
/**
* Returns the byte length of a string when encoded. This is not the same as
* String.prototype.length, which does not account for the encoding that is
* used to convert the string into bytes.
*/
static byteLength(
string: string | Buffer | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
encoding = "utf8",
): number {
if (typeof string != "string") return string.byteLength;
encoding = normalizeEncoding(encoding) || "utf8";
return encodingOps[encoding].byteLength(string);
}
/**
* Returns a new Buffer which is the result of concatenating all the Buffer
* instances in the list together.
*/
static concat(list: Buffer[] | Uint8Array[], totalLength?: number): Buffer {
if (totalLength == undefined) {
totalLength = 0;
for (const buf of list) {
totalLength += buf.length;
}
}
const buffer = Buffer.allocUnsafe(totalLength);
let pos = 0;
for (const item of list) {
let buf: Buffer;
if (!(item instanceof Buffer)) {
buf = Buffer.from(item);
} else {
buf = item;
}
buf.copy(buffer, pos);
pos += buf.length;
}
return buffer;
}
/**
* Allocates a new Buffer using an array of bytes in the range 0 255. Array
* entries outside that range will be truncated to fit into it.
*/
static from(array: number[]): Buffer;
/**
* This creates a view of the ArrayBuffer without copying the underlying
* memory. For example, when passed a reference to the .buffer property of a
* TypedArray instance, the newly created Buffer will share the same allocated
* memory as the TypedArray.
*/
static from(
arrayBuffer: ArrayBuffer | SharedArrayBuffer,
byteOffset?: number,
length?: number,
): Buffer;
/**
* Copies the passed buffer data onto a new Buffer instance.
*/
static from(buffer: Buffer | Uint8Array): Buffer;
/**
* Creates a new Buffer containing string.
*/
static from(string: string, encoding?: string): Buffer;
static from(
// deno-lint-ignore no-explicit-any
value: any,
offsetOrEncoding?: number | string,
length?: number,
): Buffer {
const offset = typeof offsetOrEncoding === "string"
? undefined
: offsetOrEncoding;
let encoding = typeof offsetOrEncoding === "string"
? offsetOrEncoding
: undefined;
if (typeof value == "string") {
encoding = checkEncoding(encoding, false);
if (encoding === "hex") return new Buffer(hex.decodeString(value).buffer);
if (encoding === "base64") return new Buffer(base64.decode(value).buffer);
return new Buffer(new TextEncoder().encode(value).buffer);
}
// workaround for https://github.com/microsoft/TypeScript/issues/38446
return new Buffer(value, offset!, length);
}
/**
* Returns true if obj is a Buffer, false otherwise.
*/
static isBuffer(obj: unknown): obj is Buffer {
return obj instanceof Buffer;
}
// deno-lint-ignore no-explicit-any
static isEncoding(encoding: any): boolean {
return (
typeof encoding === "string" &&
encoding.length !== 0 &&
normalizeEncoding(encoding) !== undefined
);
}
/**
* Copies data from a region of buf to a region in target, even if the target
* memory region overlaps with buf.
*/
copy(
targetBuffer: Buffer | Uint8Array,
targetStart = 0,
sourceStart = 0,
sourceEnd = this.length,
): number {
const sourceBuffer = this
.subarray(sourceStart, sourceEnd)
.subarray(0, Math.max(0, targetBuffer.length - targetStart));
if (sourceBuffer.length === 0) return 0;
targetBuffer.set(sourceBuffer, targetStart);
return sourceBuffer.length;
}
/*
* Returns true if both buf and otherBuffer have exactly the same bytes, false otherwise.
*/
equals(otherBuffer: Uint8Array | Buffer): boolean {
if (!(otherBuffer instanceof Uint8Array)) {
throw new TypeError(
`The "otherBuffer" argument must be an instance of Buffer or Uint8Array. Received type ${typeof otherBuffer}`,
);
}
if (this === otherBuffer) return true;
if (this.byteLength !== otherBuffer.byteLength) return false;
for (let i = 0; i < this.length; i++) {
if (this[i] !== otherBuffer[i]) return false;
}
return true;
}
readBigInt64BE(offset = 0): bigint {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getBigInt64(offset);
}
readBigInt64LE(offset = 0): bigint {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getBigInt64(offset, true);
}
readBigUInt64BE(offset = 0): bigint {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getBigUint64(offset);
}
readBigUInt64LE(offset = 0): bigint {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getBigUint64(offset, true);
}
readDoubleBE(offset = 0): number {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getFloat64(offset);
}
readDoubleLE(offset = 0): number {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getFloat64(offset, true);
}
readFloatBE(offset = 0): number {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getFloat32(offset);
}
readFloatLE(offset = 0): number {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getFloat32(offset, true);
}
readInt8(offset = 0): number {
return new DataView(this.buffer, this.byteOffset, this.byteLength).getInt8(
offset,
);
}
readInt16BE(offset = 0): number {
return new DataView(this.buffer, this.byteOffset, this.byteLength).getInt16(
offset,
);
}
readInt16LE(offset = 0): number {
return new DataView(this.buffer, this.byteOffset, this.byteLength).getInt16(
offset,
true,
);
}
readInt32BE(offset = 0): number {
return new DataView(this.buffer, this.byteOffset, this.byteLength).getInt32(
offset,
);
}
readInt32LE(offset = 0): number {
return new DataView(this.buffer, this.byteOffset, this.byteLength).getInt32(
offset,
true,
);
}
readUInt8(offset = 0): number {
return new DataView(this.buffer, this.byteOffset, this.byteLength).getUint8(
offset,
);
}
readUInt16BE(offset = 0): number {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getUint16(offset);
}
readUInt16LE(offset = 0): number {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getUint16(offset, true);
}
readUInt32BE(offset = 0): number {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getUint32(offset);
}
readUInt32LE(offset = 0): number {
return new DataView(
this.buffer,
this.byteOffset,
this.byteLength,
).getUint32(offset, true);
}
/**
* Returns a new Buffer that references the same memory as the original, but
* offset and cropped by the start and end indices.
*/
slice(begin = 0, end = this.length): Buffer {
// workaround for https://github.com/microsoft/TypeScript/issues/38665
return this.subarray(begin, end) as Buffer;
}
/**
* Returns a JSON representation of buf. JSON.stringify() implicitly calls
* this function when stringifying a Buffer instance.
*/
toJSON(): Record<string, unknown> {
return { type: "Buffer", data: Array.from(this) };
}
/**
* Decodes buf to a string according to the specified character encoding in
* encoding. start and end may be passed to decode only a subset of buf.
*/
toString(encoding = "utf8", start = 0, end = this.length): string {
encoding = checkEncoding(encoding);
const b = this.subarray(start, end);
if (encoding === "hex") return hex.encodeToString(b);
if (encoding === "base64") return base64.encode(b.buffer);
return new TextDecoder(encoding).decode(b);
}
/**
* Writes string to buf at offset according to the character encoding in
* encoding. The length parameter is the number of bytes to write. If buf did
* not contain enough space to fit the entire string, only part of string will
* be written. However, partially encoded characters will not be written.
*/
write(string: string, offset = 0, length = this.length): number {
return new TextEncoder().encodeInto(
string,
this.subarray(offset, offset + length),
).written;
}
writeBigInt64BE(value: bigint, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setBigInt64(
offset,
value,
);
return offset + 4;
}
writeBigInt64LE(value: bigint, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setBigInt64(
offset,
value,
true,
);
return offset + 4;
}
writeBigUInt64BE(value: bigint, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setBigUint64(
offset,
value,
);
return offset + 4;
}
writeBigUInt64LE(value: bigint, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setBigUint64(
offset,
value,
true,
);
return offset + 4;
}
writeDoubleBE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setFloat64(
offset,
value,
);
return offset + 8;
}
writeDoubleLE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setFloat64(
offset,
value,
true,
);
return offset + 8;
}
writeFloatBE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setFloat32(
offset,
value,
);
return offset + 4;
}
writeFloatLE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setFloat32(
offset,
value,
true,
);
return offset + 4;
}
writeInt8(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setInt8(
offset,
value,
);
return offset + 1;
}
writeInt16BE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setInt16(
offset,
value,
);
return offset + 2;
}
writeInt16LE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setInt16(
offset,
value,
true,
);
return offset + 2;
}
writeInt32BE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setUint32(
offset,
value,
);
return offset + 4;
}
writeInt32LE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setInt32(
offset,
value,
true,
);
return offset + 4;
}
writeUInt8(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setUint8(
offset,
value,
);
return offset + 1;
}
writeUInt16BE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setUint16(
offset,
value,
);
return offset + 2;
}
writeUInt16LE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setUint16(
offset,
value,
true,
);
return offset + 2;
}
writeUInt32BE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setUint32(
offset,
value,
);
return offset + 4;
}
writeUInt32LE(value: number, offset = 0): number {
new DataView(this.buffer, this.byteOffset, this.byteLength).setUint32(
offset,
value,
true,
);
return offset + 4;
}
}
export { Buffer };
export * from "./_buffer.ts";
import * as m from "./_buffer.ts";
export default m;

View file

@ -1,6 +1,6 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { assert, assertEquals, assertThrows } from "../testing/asserts.ts";
import Buffer from "./buffer.ts";
import { Buffer } from "./buffer.ts";
Deno.test({
name: "Buffer global scope",

View file

@ -1,4 +1,4 @@
import randomBytes from "./_crypto/randomBytes.ts";
import { pbkdf2, pbkdf2Sync } from "./_crypto/pbkdf2.ts";
export { pbkdf2, pbkdf2Sync, randomBytes };
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
export * from "./_crypto.ts";
import * as m from "./_crypto.ts";
export default m;

View file

@ -31,12 +31,36 @@ export interface WrappedFunction extends Function {
listener: GenericFunction;
}
// deno-lint-ignore no-explicit-any
function createIterResult(value: any, done: boolean): IteratorResult<any> {
return { value, done };
}
interface AsyncIterable {
// deno-lint-ignore no-explicit-any
next(): Promise<IteratorResult<any, any>>;
// deno-lint-ignore no-explicit-any
return(): Promise<IteratorResult<any, any>>;
throw(err: Error): void;
// deno-lint-ignore no-explicit-any
[Symbol.asyncIterator](): any;
}
export let defaultMaxListeners = 10;
/**
* See also https://nodejs.org/api/events.html
*/
export default class EventEmitter {
public static defaultMaxListeners = 10;
public static captureRejectionSymbol = Symbol.for("nodejs.rejection");
public static errorMonitor = Symbol("events.errorMonitor");
public static get defaultMaxListeners() {
return defaultMaxListeners;
}
public static set defaultMaxListeners(value: number) {
defaultMaxListeners = value;
}
private maxListeners: number | undefined;
private _events: Map<
string | symbol,
@ -367,180 +391,168 @@ export default class EventEmitter {
this.maxListeners = n;
return this;
}
/**
* Creates a Promise that is fulfilled when the EventEmitter emits the given
* event or that is rejected when the EventEmitter emits 'error'. The Promise
* will resolve with an array of all the arguments emitted to the given event.
*/
public static once(
emitter: EventEmitter | EventTarget,
name: string,
// deno-lint-ignore no-explicit-any
): Promise<any[]> {
return new Promise((resolve, reject) => {
if (emitter instanceof EventTarget) {
// EventTarget does not have `error` event semantics like Node
// EventEmitters, we do not listen to `error` events here.
emitter.addEventListener(
name,
(...args) => {
resolve(args);
},
{ once: true, passive: false, capture: false },
);
return;
} else if (emitter instanceof EventEmitter) {
// deno-lint-ignore no-explicit-any
const eventListener = (...args: any[]): void => {
if (errorListener !== undefined) {
emitter.removeListener("error", errorListener);
}
resolve(args);
};
let errorListener: GenericFunction;
// Adding an error listener is not optional because
// if an error is thrown on an event emitter we cannot
// guarantee that the actual event we are waiting will
// be fired. The result could be a silent way to create
// memory or file descriptor leaks, which is something
// we should avoid.
if (name !== "error") {
// deno-lint-ignore no-explicit-any
errorListener = (err: any): void => {
emitter.removeListener(name, eventListener);
reject(err);
};
emitter.once("error", errorListener);
}
emitter.once(name, eventListener);
return;
}
});
}
/**
* Returns an AsyncIterator that iterates eventName events. It will throw if
* the EventEmitter emits 'error'. It removes all listeners when exiting the
* loop. The value returned by each iteration is an array composed of the
* emitted event arguments.
*/
public static on(
emitter: EventEmitter,
event: string | symbol,
): AsyncIterable {
// deno-lint-ignore no-explicit-any
const unconsumedEventValues: any[] = [];
// deno-lint-ignore no-explicit-any
const unconsumedPromises: any[] = [];
let error: Error | null = null;
let finished = false;
const iterator = {
// deno-lint-ignore no-explicit-any
next(): Promise<IteratorResult<any>> {
// First, we consume all unread events
// deno-lint-ignore no-explicit-any
const value: any = unconsumedEventValues.shift();
if (value) {
return Promise.resolve(createIterResult(value, false));
}
// Then we error, if an error happened
// This happens one time if at all, because after 'error'
// we stop listening
if (error) {
const p: Promise<never> = Promise.reject(error);
// Only the first element errors
error = null;
return p;
}
// If the iterator is finished, resolve to done
if (finished) {
return Promise.resolve(createIterResult(undefined, true));
}
// Wait until an event happens
return new Promise(function (resolve, reject) {
unconsumedPromises.push({ resolve, reject });
});
},
// deno-lint-ignore no-explicit-any
return(): Promise<IteratorResult<any>> {
emitter.removeListener(event, eventHandler);
emitter.removeListener("error", errorHandler);
finished = true;
for (const promise of unconsumedPromises) {
promise.resolve(createIterResult(undefined, true));
}
return Promise.resolve(createIterResult(undefined, true));
},
throw(err: Error): void {
error = err;
emitter.removeListener(event, eventHandler);
emitter.removeListener("error", errorHandler);
},
// deno-lint-ignore no-explicit-any
[Symbol.asyncIterator](): any {
return this;
},
};
emitter.on(event, eventHandler);
emitter.on("error", errorHandler);
return iterator;
// deno-lint-ignore no-explicit-any
function eventHandler(...args: any[]): void {
const promise = unconsumedPromises.shift();
if (promise) {
promise.resolve(createIterResult(args, false));
} else {
unconsumedEventValues.push(args);
}
}
// deno-lint-ignore no-explicit-any
function errorHandler(err: any): void {
finished = true;
const toError = unconsumedPromises.shift();
if (toError) {
toError.reject(err);
} else {
// The next time we call next()
error = err;
}
iterator.return();
}
}
}
export { EventEmitter };
/**
* Creates a Promise that is fulfilled when the EventEmitter emits the given
* event or that is rejected when the EventEmitter emits 'error'. The Promise
* will resolve with an array of all the arguments emitted to the given event.
*/
export function once(
emitter: EventEmitter | EventTarget,
name: string,
// deno-lint-ignore no-explicit-any
): Promise<any[]> {
return new Promise((resolve, reject) => {
if (emitter instanceof EventTarget) {
// EventTarget does not have `error` event semantics like Node
// EventEmitters, we do not listen to `error` events here.
emitter.addEventListener(
name,
(...args) => {
resolve(args);
},
{ once: true, passive: false, capture: false },
);
return;
} else if (emitter instanceof EventEmitter) {
// deno-lint-ignore no-explicit-any
const eventListener = (...args: any[]): void => {
if (errorListener !== undefined) {
emitter.removeListener("error", errorListener);
}
resolve(args);
};
let errorListener: GenericFunction;
// Adding an error listener is not optional because
// if an error is thrown on an event emitter we cannot
// guarantee that the actual event we are waiting will
// be fired. The result could be a silent way to create
// memory or file descriptor leaks, which is something
// we should avoid.
if (name !== "error") {
// deno-lint-ignore no-explicit-any
errorListener = (err: any): void => {
emitter.removeListener(name, eventListener);
reject(err);
};
emitter.once("error", errorListener);
}
emitter.once(name, eventListener);
return;
}
});
}
// deno-lint-ignore no-explicit-any
function createIterResult(value: any, done: boolean): IteratorResult<any> {
return { value, done };
}
interface AsyncInterable {
// deno-lint-ignore no-explicit-any
next(): Promise<IteratorResult<any, any>>;
// deno-lint-ignore no-explicit-any
return(): Promise<IteratorResult<any, any>>;
throw(err: Error): void;
// deno-lint-ignore no-explicit-any
[Symbol.asyncIterator](): any;
}
/**
* Returns an AsyncIterator that iterates eventName events. It will throw if
* the EventEmitter emits 'error'. It removes all listeners when exiting the
* loop. The value returned by each iteration is an array composed of the
* emitted event arguments.
*/
export function on(
emitter: EventEmitter,
event: string | symbol,
): AsyncInterable {
// deno-lint-ignore no-explicit-any
const unconsumedEventValues: any[] = [];
// deno-lint-ignore no-explicit-any
const unconsumedPromises: any[] = [];
let error: Error | null = null;
let finished = false;
const iterator = {
// deno-lint-ignore no-explicit-any
next(): Promise<IteratorResult<any>> {
// First, we consume all unread events
// deno-lint-ignore no-explicit-any
const value: any = unconsumedEventValues.shift();
if (value) {
return Promise.resolve(createIterResult(value, false));
}
// Then we error, if an error happened
// This happens one time if at all, because after 'error'
// we stop listening
if (error) {
const p: Promise<never> = Promise.reject(error);
// Only the first element errors
error = null;
return p;
}
// If the iterator is finished, resolve to done
if (finished) {
return Promise.resolve(createIterResult(undefined, true));
}
// Wait until an event happens
return new Promise(function (resolve, reject) {
unconsumedPromises.push({ resolve, reject });
});
},
// deno-lint-ignore no-explicit-any
return(): Promise<IteratorResult<any>> {
emitter.removeListener(event, eventHandler);
emitter.removeListener("error", errorHandler);
finished = true;
for (const promise of unconsumedPromises) {
promise.resolve(createIterResult(undefined, true));
}
return Promise.resolve(createIterResult(undefined, true));
},
throw(err: Error): void {
error = err;
emitter.removeListener(event, eventHandler);
emitter.removeListener("error", errorHandler);
},
// deno-lint-ignore no-explicit-any
[Symbol.asyncIterator](): any {
return this;
},
};
emitter.on(event, eventHandler);
emitter.on("error", errorHandler);
return iterator;
// deno-lint-ignore no-explicit-any
function eventHandler(...args: any[]): void {
const promise = unconsumedPromises.shift();
if (promise) {
promise.resolve(createIterResult(args, false));
} else {
unconsumedEventValues.push(args);
}
}
// deno-lint-ignore no-explicit-any
function errorHandler(err: any): void {
finished = true;
const toError = unconsumedPromises.shift();
if (toError) {
toError.reject(err);
} else {
// The next time we call next()
error = err;
}
iterator.return();
}
}
export const captureRejectionSymbol = Symbol.for("nodejs.rejection");
export const once = EventEmitter.once;
export const on = EventEmitter.on;
export const captureRejectionSymbol = EventEmitter.captureRejectionSymbol;
export const errorMonitor = EventEmitter.errorMonitor;

View file

@ -1,68 +1,4 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { access, accessSync } from "./_fs/_fs_access.ts";
import { appendFile, appendFileSync } from "./_fs/_fs_appendFile.ts";
import { chmod, chmodSync } from "./_fs/_fs_chmod.ts";
import { chown, chownSync } from "./_fs/_fs_chown.ts";
import { close, closeSync } from "./_fs/_fs_close.ts";
import * as constants from "./_fs/_fs_constants.ts";
import { readFile, readFileSync } from "./_fs/_fs_readFile.ts";
import { readlink, readlinkSync } from "./_fs/_fs_readlink.ts";
import { exists, existsSync } from "./_fs/_fs_exists.ts";
import { mkdir, mkdirSync } from "./_fs/_fs_mkdir.ts";
import { copyFile, copyFileSync } from "./_fs/_fs_copy.ts";
import { writeFile, writeFileSync } from "./_fs/_fs_writeFile.ts";
import { readdir, readdirSync } from "./_fs/_fs_readdir.ts";
import { realpath, realpathSync } from "./_fs/_fs_realpath.ts";
import { rename, renameSync } from "./_fs/_fs_rename.ts";
import { rmdir, rmdirSync } from "./_fs/_fs_rmdir.ts";
import { unlink, unlinkSync } from "./_fs/_fs_unlink.ts";
import { watch } from "./_fs/_fs_watch.ts";
import { open, openSync } from "./_fs/_fs_open.ts";
import { stat, statSync } from "./_fs/_fs_stat.ts";
import { lstat, lstatSync } from "./_fs/_fs_lstat.ts";
import * as promises from "./_fs/promises/mod.ts";
export {
access,
accessSync,
appendFile,
appendFileSync,
chmod,
chmodSync,
chown,
chownSync,
close,
closeSync,
constants,
copyFile,
copyFileSync,
exists,
existsSync,
lstat,
lstatSync,
mkdir,
mkdirSync,
open,
openSync,
promises,
readdir,
readdirSync,
readFile,
readFileSync,
readlink,
readlinkSync,
realpath,
realpathSync,
rename,
renameSync,
rmdir,
rmdirSync,
stat,
statSync,
unlink,
unlinkSync,
watch,
writeFile,
writeFileSync,
};
export * from "./_fs.ts";
import * as m from "./_fs.ts";
export default m;

View file

@ -1,224 +1,4 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
import { notImplemented } from "./_utils.ts";
import { validateIntegerRange } from "./_utils.ts";
import { EOL as fsEOL } from "../fs/eol.ts";
import process from "./process.ts";
const SEE_GITHUB_ISSUE = "See https://github.com/denoland/deno/issues/3802";
interface CPUTimes {
/** The number of milliseconds the CPU has spent in user mode */
user: number;
/** The number of milliseconds the CPU has spent in nice mode */
nice: number;
/** The number of milliseconds the CPU has spent in sys mode */
sys: number;
/** The number of milliseconds the CPU has spent in idle mode */
idle: number;
/** The number of milliseconds the CPU has spent in irq mode */
irq: number;
}
interface CPUCoreInfo {
model: string;
/** in MHz */
speed: number;
times: CPUTimes;
}
interface NetworkAddress {
/** The assigned IPv4 or IPv6 address */
address: string;
/** The IPv4 or IPv6 network mask */
netmask: string;
family: "IPv4" | "IPv6";
/** The MAC address of the network interface */
mac: string;
/** true if the network interface is a loopback or similar interface that is not remotely accessible; otherwise false */
internal: boolean;
/** The numeric IPv6 scope ID (only specified when family is IPv6) */
scopeid?: number;
/** The assigned IPv4 or IPv6 address with the routing prefix in CIDR notation. If the netmask is invalid, this property is set to null. */
cidr: string;
}
interface NetworkInterfaces {
[key: string]: NetworkAddress[];
}
export interface UserInfoOptions {
encoding: string;
}
interface UserInfo {
username: string;
uid: number;
gid: number;
shell: string;
homedir: string;
}
arch[Symbol.toPrimitive] = (): string => arch();
endianness[Symbol.toPrimitive] = (): string => endianness();
freemem[Symbol.toPrimitive] = (): number => freemem();
homedir[Symbol.toPrimitive] = (): string | null => homedir();
hostname[Symbol.toPrimitive] = (): string | null => hostname();
platform[Symbol.toPrimitive] = (): string => platform();
release[Symbol.toPrimitive] = (): string => release();
totalmem[Symbol.toPrimitive] = (): number => totalmem();
type[Symbol.toPrimitive] = (): string => type();
uptime[Symbol.toPrimitive] = (): number => uptime();
/** Returns the operating system CPU architecture for which the Deno binary was compiled */
export function arch(): string {
return Deno.build.arch;
}
/** Not yet implemented */
export function cpus(): CPUCoreInfo[] {
notImplemented(SEE_GITHUB_ISSUE);
}
/**
* Returns a string identifying the endianness of the CPU for which the Deno
* binary was compiled. Possible values are 'BE' for big endian and 'LE' for
* little endian.
**/
export function endianness(): "BE" | "LE" {
// Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView#Endianness
const buffer = new ArrayBuffer(2);
new DataView(buffer).setInt16(0, 256, true /* littleEndian */);
// Int16Array uses the platform's endianness.
return new Int16Array(buffer)[0] === 256 ? "LE" : "BE";
}
/** Not yet implemented */
export function freemem(): number {
notImplemented(SEE_GITHUB_ISSUE);
}
/** Not yet implemented */
export function getPriority(pid = 0): number {
validateIntegerRange(pid, "pid");
notImplemented(SEE_GITHUB_ISSUE);
}
/** Returns the string path of the current user's home directory. */
export function homedir(): string | null {
notImplemented(SEE_GITHUB_ISSUE);
}
/** Returns the host name of the operating system as a string. */
export function hostname(): string {
notImplemented(SEE_GITHUB_ISSUE);
}
/** Returns an array containing the 1, 5, and 15 minute load averages */
export function loadavg(): number[] {
if (Deno.build.os === "windows") {
return [0, 0, 0];
}
return Deno.loadavg();
}
/** Not yet implemented */
export function networkInterfaces(): NetworkInterfaces {
notImplemented(SEE_GITHUB_ISSUE);
}
/** Returns the a string identifying the operating system platform. The value is set at compile time. Possible values are 'darwin', 'linux', and 'win32'. */
export function platform(): string {
return process.platform;
}
/** Returns the operating system as a string */
export function release(): string {
return Deno.osRelease();
}
/** Not yet implemented */
export function setPriority(pid: number, priority?: number): void {
/* The node API has the 'pid' as the first parameter and as optional.
This makes for a problematic implementation in Typescript. */
if (priority === undefined) {
priority = pid;
pid = 0;
}
validateIntegerRange(pid, "pid");
validateIntegerRange(priority, "priority", -20, 19);
notImplemented(SEE_GITHUB_ISSUE);
}
/** Returns the operating system's default directory for temporary files as a string. */
export function tmpdir(): string | null {
notImplemented(SEE_GITHUB_ISSUE);
}
/** Not yet implemented */
export function totalmem(): number {
notImplemented(SEE_GITHUB_ISSUE);
}
/** Not yet implemented */
export function type(): string {
notImplemented(SEE_GITHUB_ISSUE);
}
/** Not yet implemented */
export function uptime(): number {
notImplemented(SEE_GITHUB_ISSUE);
}
/** Not yet implemented */
export function userInfo(
options: UserInfoOptions = { encoding: "utf-8" },
): UserInfo {
notImplemented(SEE_GITHUB_ISSUE);
}
export const constants = {
// UV_UDP_REUSEADDR: 4, //see https://nodejs.org/docs/latest-v12.x/api/os.html#os_libuv_constants
dlopen: {
// see https://nodejs.org/docs/latest-v12.x/api/os.html#os_dlopen_constants
},
errno: {
// see https://nodejs.org/docs/latest-v12.x/api/os.html#os_error_constants
},
signals: Deno.Signal,
priority: {
// see https://nodejs.org/docs/latest-v12.x/api/os.html#os_priority_constants
},
};
export const EOL = Deno.build.os == "windows" ? fsEOL.CRLF : fsEOL.LF;
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
export * from "./_os.ts";
import * as m from "./_os.ts";
export default m;

View file

@ -1,2 +1,4 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
export * from "../path/mod.ts";
import * as m from "../path/mod.ts";
export default m;

View file

@ -1,156 +1,4 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
interface ParseOptions {
/** The function to use when decoding percent-encoded characters in the query string. */
decodeURIComponent?: (string: string) => string;
/** Specifies the maximum number of keys to parse. */
maxKeys?: number;
}
export const hexTable = new Array(256);
for (let i = 0; i < 256; ++i) {
hexTable[i] = "%" + ((i < 16 ? "0" : "") + i.toString(16)).toUpperCase();
}
/**
* Parses a URL query string into a collection of key and value pairs.
* @param str The URL query string to parse
* @param sep The substring used to delimit key and value pairs in the query string. Default: '&'.
* @param eq The substring used to delimit keys and values in the query string. Default: '='.
* @param options The parse options
*/
export function parse(
str: string,
sep = "&",
eq = "=",
{ decodeURIComponent = unescape, maxKeys = 1000 }: ParseOptions = {},
): { [key: string]: string[] | string } {
const entries = str
.split(sep)
.map((entry) => entry.split(eq).map(decodeURIComponent));
const final: { [key: string]: string[] | string } = {};
let i = 0;
while (true) {
if ((Object.keys(final).length === maxKeys && !!maxKeys) || !entries[i]) {
break;
}
const [key, val] = entries[i];
if (final[key]) {
if (Array.isArray(final[key])) {
(final[key] as string[]).push(val);
} else {
final[key] = [final[key] as string, val];
}
} else {
final[key] = val;
}
i++;
}
return final;
}
interface StringifyOptions {
/** The function to use when converting URL-unsafe characters to percent-encoding in the query string. */
encodeURIComponent?: (string: string) => string;
}
export function encodeStr(
str: string,
noEscapeTable: number[],
hexTable: string[],
): string {
const len = str.length;
if (len === 0) return "";
let out = "";
let lastPos = 0;
for (let i = 0; i < len; i++) {
let c = str.charCodeAt(i);
// ASCII
if (c < 0x80) {
if (noEscapeTable[c] === 1) continue;
if (lastPos < i) out += str.slice(lastPos, i);
lastPos = i + 1;
out += hexTable[c];
continue;
}
if (lastPos < i) out += str.slice(lastPos, i);
// Multi-byte characters ...
if (c < 0x800) {
lastPos = i + 1;
out += hexTable[0xc0 | (c >> 6)] + hexTable[0x80 | (c & 0x3f)];
continue;
}
if (c < 0xd800 || c >= 0xe000) {
lastPos = i + 1;
out += hexTable[0xe0 | (c >> 12)] +
hexTable[0x80 | ((c >> 6) & 0x3f)] +
hexTable[0x80 | (c & 0x3f)];
continue;
}
// Surrogate pair
++i;
// This branch should never happen because all URLSearchParams entries
// should already be converted to USVString. But, included for
// completion's sake anyway.
if (i >= len) throw new Deno.errors.InvalidData("invalid URI");
const c2 = str.charCodeAt(i) & 0x3ff;
lastPos = i + 1;
c = 0x10000 + (((c & 0x3ff) << 10) | c2);
out += hexTable[0xf0 | (c >> 18)] +
hexTable[0x80 | ((c >> 12) & 0x3f)] +
hexTable[0x80 | ((c >> 6) & 0x3f)] +
hexTable[0x80 | (c & 0x3f)];
}
if (lastPos === 0) return str;
if (lastPos < len) return out + str.slice(lastPos);
return out;
}
/**
* Produces a URL query string from a given obj by iterating through the object's "own properties".
* @param obj The object to serialize into a URL query string.
* @param sep The substring used to delimit key and value pairs in the query string. Default: '&'.
* @param eq The substring used to delimit keys and values in the query string. Default: '='.
* @param options The stringify options
*/
export function stringify(
// deno-lint-ignore no-explicit-any
obj: Record<string, any>,
sep = "&",
eq = "=",
{ encodeURIComponent = escape }: StringifyOptions = {},
): string {
const final = [];
for (const entry of Object.entries(obj)) {
if (Array.isArray(entry[1])) {
for (const val of entry[1]) {
final.push(encodeURIComponent(entry[0]) + eq + encodeURIComponent(val));
}
} else if (typeof entry[1] !== "object" && entry[1] !== undefined) {
final.push(entry.map(encodeURIComponent).join(eq));
} else {
final.push(encodeURIComponent(entry[0]) + eq);
}
}
return final.join(sep);
}
/** Alias of querystring.parse() */
export const decode = parse;
/** Alias of querystring.stringify() */
export const encode = stringify;
export const unescape = decodeURIComponent;
export const escape = encodeURIComponent;
export * from "./_querystring.ts";
import * as m from "./_querystring.ts";
export default m;

View file

@ -1,299 +1,4 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
import { Buffer } from "./buffer.ts";
import { normalizeEncoding as castEncoding, notImplemented } from "./_utils.ts";
enum NotImplemented {
"ascii",
"latin1",
"utf16le",
}
function normalizeEncoding(enc?: string): string {
const encoding = castEncoding(enc ?? null);
if (encoding && encoding in NotImplemented) notImplemented(encoding);
if (!encoding && typeof enc === "string" && enc.toLowerCase() !== "raw") {
throw new Error(`Unknown encoding: ${enc}`);
}
return String(encoding);
}
/*
* Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a
* continuation byte. If an invalid byte is detected, -2 is returned.
* */
function utf8CheckByte(byte: number): number {
if (byte <= 0x7f) return 0;
else if (byte >> 5 === 0x06) return 2;
else if (byte >> 4 === 0x0e) return 3;
else if (byte >> 3 === 0x1e) return 4;
return byte >> 6 === 0x02 ? -1 : -2;
}
/*
* Checks at most 3 bytes at the end of a Buffer in order to detect an
* incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4)
* needed to complete the UTF-8 character (if applicable) are returned.
* */
function utf8CheckIncomplete(
self: StringDecoderBase,
buf: Buffer,
i: number,
): number {
let j = buf.length - 1;
if (j < i) return 0;
let nb = utf8CheckByte(buf[j]);
if (nb >= 0) {
if (nb > 0) self.lastNeed = nb - 1;
return nb;
}
if (--j < i || nb === -2) return 0;
nb = utf8CheckByte(buf[j]);
if (nb >= 0) {
if (nb > 0) self.lastNeed = nb - 2;
return nb;
}
if (--j < i || nb === -2) return 0;
nb = utf8CheckByte(buf[j]);
if (nb >= 0) {
if (nb > 0) {
if (nb === 2) nb = 0;
else self.lastNeed = nb - 3;
}
return nb;
}
return 0;
}
/*
* Validates as many continuation bytes for a multi-byte UTF-8 character as
* needed or are available. If we see a non-continuation byte where we expect
* one, we "replace" the validated continuation bytes we've seen so far with
* a single UTF-8 replacement character ('\ufffd'), to match v8's UTF-8 decoding
* behavior. The continuation byte check is included three times in the case
* where all of the continuation bytes for a character exist in the same buffer.
* It is also done this way as a slight performance increase instead of using a
* loop.
* */
function utf8CheckExtraBytes(
self: StringDecoderBase,
buf: Buffer,
): string | undefined {
if ((buf[0] & 0xc0) !== 0x80) {
self.lastNeed = 0;
return "\ufffd";
}
if (self.lastNeed > 1 && buf.length > 1) {
if ((buf[1] & 0xc0) !== 0x80) {
self.lastNeed = 1;
return "\ufffd";
}
if (self.lastNeed > 2 && buf.length > 2) {
if ((buf[2] & 0xc0) !== 0x80) {
self.lastNeed = 2;
return "\ufffd";
}
}
}
}
/*
* Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer.
* */
function utf8FillLastComplete(
this: StringDecoderBase,
buf: Buffer,
): string | undefined {
const p = this.lastTotal - this.lastNeed;
const r = utf8CheckExtraBytes(this, buf);
if (r !== undefined) return r;
if (this.lastNeed <= buf.length) {
buf.copy(this.lastChar, p, 0, this.lastNeed);
return this.lastChar.toString(this.encoding, 0, this.lastTotal);
}
buf.copy(this.lastChar, p, 0, buf.length);
this.lastNeed -= buf.length;
}
/*
* Attempts to complete a partial non-UTF-8 character using bytes from a Buffer
* */
function utf8FillLastIncomplete(
this: StringDecoderBase,
buf: Buffer,
): string | undefined {
if (this.lastNeed <= buf.length) {
buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed);
return this.lastChar.toString(this.encoding, 0, this.lastTotal);
}
buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length);
this.lastNeed -= buf.length;
}
/*
* Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a
* partial character, the character's bytes are buffered until the required
* number of bytes are available.
* */
function utf8Text(this: StringDecoderBase, buf: Buffer, i: number): string {
const total = utf8CheckIncomplete(this, buf, i);
if (!this.lastNeed) return buf.toString("utf8", i);
this.lastTotal = total;
const end = buf.length - (total - this.lastNeed);
buf.copy(this.lastChar, 0, end);
return buf.toString("utf8", i, end);
}
/*
* For UTF-8, a replacement character is added when ending on a partial
* character.
* */
function utf8End(this: Utf8Decoder, buf?: Buffer): string {
const r = buf && buf.length ? this.write(buf) : "";
if (this.lastNeed) return r + "\ufffd";
return r;
}
function utf8Write(this: Utf8Decoder | Base64Decoder, buf: Buffer): string {
if (buf.length === 0) return "";
let r;
let i;
if (this.lastNeed) {
r = this.fillLast(buf);
if (r === undefined) return "";
i = this.lastNeed;
this.lastNeed = 0;
} else {
i = 0;
}
if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i);
return r || "";
}
function base64Text(this: StringDecoderBase, buf: Buffer, i: number): string {
const n = (buf.length - i) % 3;
if (n === 0) return buf.toString("base64", i);
this.lastNeed = 3 - n;
this.lastTotal = 3;
if (n === 1) {
this.lastChar[0] = buf[buf.length - 1];
} else {
this.lastChar[0] = buf[buf.length - 2];
this.lastChar[1] = buf[buf.length - 1];
}
return buf.toString("base64", i, buf.length - n);
}
function base64End(this: Base64Decoder, buf?: Buffer): string {
const r = buf && buf.length ? this.write(buf) : "";
if (this.lastNeed) {
return r + this.lastChar.toString("base64", 0, 3 - this.lastNeed);
}
return r;
}
function simpleWrite(this: StringDecoderBase, buf: Buffer): string {
return buf.toString(this.encoding);
}
function simpleEnd(this: GenericDecoder, buf?: Buffer): string {
return buf && buf.length ? this.write(buf) : "";
}
class StringDecoderBase {
public lastChar: Buffer;
public lastNeed = 0;
public lastTotal = 0;
constructor(public encoding: string, nb: number) {
this.lastChar = Buffer.allocUnsafe(nb);
}
}
class Base64Decoder extends StringDecoderBase {
public end = base64End;
public fillLast = utf8FillLastIncomplete;
public text = base64Text;
public write = utf8Write;
constructor(encoding?: string) {
super(normalizeEncoding(encoding), 3);
}
}
class GenericDecoder extends StringDecoderBase {
public end = simpleEnd;
public fillLast = undefined;
public text = utf8Text;
public write = simpleWrite;
constructor(encoding?: string) {
super(normalizeEncoding(encoding), 4);
}
}
class Utf8Decoder extends StringDecoderBase {
public end = utf8End;
public fillLast = utf8FillLastComplete;
public text = utf8Text;
public write = utf8Write;
constructor(encoding?: string) {
super(normalizeEncoding(encoding), 4);
}
}
/*
* StringDecoder provides an interface for efficiently splitting a series of
* buffers into a series of JS strings without breaking apart multi-byte
* characters.
* */
export class StringDecoder {
public encoding: string;
public end: (buf?: Buffer) => string;
public fillLast: ((buf: Buffer) => string | undefined) | undefined;
public lastChar: Buffer;
public lastNeed: number;
public lastTotal: number;
public text: (buf: Buffer, n: number) => string;
public write: (buf: Buffer) => string;
constructor(encoding?: string) {
let decoder;
switch (encoding) {
case "utf8":
decoder = new Utf8Decoder(encoding);
break;
case "base64":
decoder = new Base64Decoder(encoding);
break;
default:
decoder = new GenericDecoder(encoding);
}
this.encoding = decoder.encoding;
this.end = decoder.end;
this.fillLast = decoder.fillLast;
this.lastChar = decoder.lastChar;
this.lastNeed = decoder.lastNeed;
this.lastTotal = decoder.lastTotal;
this.text = decoder.text;
this.write = decoder.write;
}
}
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
export * from "./_string_decoder.ts";
import * as m from "./_string_decoder.ts";
export default m;

View file

@ -1,6 +1,6 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { assertEquals } from "../testing/asserts.ts";
import Buffer from "./buffer.ts";
import { Buffer } from "./buffer.ts";
import { StringDecoder } from "./string_decoder.ts";
Deno.test({

View file

@ -1,14 +1,4 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// TODO: implement the 'NodeJS.Timeout' and 'NodeJS.Immediate' versions of the timers.
// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/1163ead296d84e7a3c80d71e7c81ecbd1a130e9a/types/node/v12/globals.d.ts#L1120-L1131
export const setTimeout = window.setTimeout;
export const clearTimeout = window.clearTimeout;
export const setInterval = window.setInterval;
export const clearInterval = window.clearInterval;
export const setImmediate = (
// deno-lint-ignore no-explicit-any
cb: (...args: any[]) => void,
// deno-lint-ignore no-explicit-any
...args: any[]
): number => window.setTimeout(cb, 0, ...args);
export const clearImmediate = window.clearTimeout;
export * from "./_timers.ts";
import * as m from "./_timers.ts";
export default m;

View file

@ -1,140 +1,4 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
import {
CHAR_BACKWARD_SLASH,
CHAR_FORWARD_SLASH,
CHAR_LOWERCASE_A,
CHAR_LOWERCASE_Z,
} from "../path/_constants.ts";
import * as path from "./path.ts";
const isWindows = Deno.build.os === "windows";
const forwardSlashRegEx = /\//g;
const percentRegEx = /%/g;
const backslashRegEx = /\\/g;
const newlineRegEx = /\n/g;
const carriageReturnRegEx = /\r/g;
const tabRegEx = /\t/g;
const _url = URL;
export { _url as URL };
/**
* Get fully resolved platform-specific file path from the given URL string/ object
* @param path The file URL string or URL object to convert to a path
*/
export function fileURLToPath(path: string | URL): string {
if (typeof path === "string") path = new URL(path);
else if (!(path instanceof URL)) {
throw new Deno.errors.InvalidData(
"invalid argument path , must be a string or URL",
);
}
if (path.protocol !== "file:") {
throw new Deno.errors.InvalidData("invalid url scheme");
}
return isWindows ? getPathFromURLWin(path) : getPathFromURLPosix(path);
}
function getPathFromURLWin(url: URL): string {
const hostname = url.hostname;
let pathname = url.pathname;
for (let n = 0; n < pathname.length; n++) {
if (pathname[n] === "%") {
const third = pathname.codePointAt(n + 2) || 0x20;
if (
(pathname[n + 1] === "2" && third === 102) || // 2f 2F /
(pathname[n + 1] === "5" && third === 99)
) {
// 5c 5C \
throw new Deno.errors.InvalidData(
"must not include encoded \\ or / characters",
);
}
}
}
pathname = pathname.replace(forwardSlashRegEx, "\\");
pathname = decodeURIComponent(pathname);
if (hostname !== "") {
//TODO add support for punycode encodings
return `\\\\${hostname}${pathname}`;
} else {
// Otherwise, it's a local path that requires a drive letter
const letter = pathname.codePointAt(1)! | 0x20;
const sep = pathname[2];
if (
letter < CHAR_LOWERCASE_A ||
letter > CHAR_LOWERCASE_Z || // a..z A..Z
sep !== ":"
) {
throw new Deno.errors.InvalidData("file url path must be absolute");
}
return pathname.slice(1);
}
}
function getPathFromURLPosix(url: URL): string {
if (url.hostname !== "") {
throw new Deno.errors.InvalidData("invalid file url hostname");
}
const pathname = url.pathname;
for (let n = 0; n < pathname.length; n++) {
if (pathname[n] === "%") {
const third = pathname.codePointAt(n + 2) || 0x20;
if (pathname[n + 1] === "2" && third === 102) {
throw new Deno.errors.InvalidData(
"must not include encoded / characters",
);
}
}
}
return decodeURIComponent(pathname);
}
/** Get fully resolved platform-specific File URL from the given file path */
export function pathToFileURL(filepath: string): URL {
let resolved = path.resolve(filepath);
// path.resolve strips trailing slashes so we must add them back
const filePathLast = filepath.charCodeAt(filepath.length - 1);
if (
(filePathLast === CHAR_FORWARD_SLASH ||
(isWindows && filePathLast === CHAR_BACKWARD_SLASH)) &&
resolved[resolved.length - 1] !== path.sep
) {
resolved += "/";
}
const outURL = new URL("file://");
if (resolved.includes("%")) resolved = resolved.replace(percentRegEx, "%25");
// In posix, "/" is a valid character in paths
if (!isWindows && resolved.includes("\\")) {
resolved = resolved.replace(backslashRegEx, "%5C");
}
if (resolved.includes("\n")) resolved = resolved.replace(newlineRegEx, "%0A");
if (resolved.includes("\r")) {
resolved = resolved.replace(carriageReturnRegEx, "%0D");
}
if (resolved.includes("\t")) resolved = resolved.replace(tabRegEx, "%09");
outURL.pathname = resolved;
return outURL;
}
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
export * from "./_url.ts";
import * as m from "./_url.ts";
export default m;

View file

@ -1,134 +1,4 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
export { promisify } from "./_util/_util_promisify.ts";
export { callbackify } from "./_util/_util_callbackify.ts";
import { codes, errorMap } from "./_errors.ts";
import * as types from "./_util/_util_types.ts";
export { types };
const NumberIsSafeInteger = Number.isSafeInteger;
const {
ERR_OUT_OF_RANGE,
ERR_INVALID_ARG_TYPE,
} = codes;
const DEFAULT_INSPECT_OPTIONS = {
showHidden: false,
depth: 2,
colors: false,
customInspect: true,
showProxy: false,
maxArrayLength: 100,
maxStringLength: Infinity,
breakLength: 80,
compact: 3,
sorted: false,
getters: false,
};
inspect.defaultOptions = DEFAULT_INSPECT_OPTIONS;
inspect.custom = Deno.customInspect;
// TODO(schwarzkopfb): make it in-line with Node's implementation
// Ref: https://nodejs.org/dist/latest-v14.x/docs/api/util.html#util_util_inspect_object_options
// deno-lint-ignore no-explicit-any
export function inspect(object: unknown, ...opts: any): string {
opts = { ...DEFAULT_INSPECT_OPTIONS, ...opts };
return Deno.inspect(object, {
depth: opts.depth,
iterableLimit: opts.maxArrayLength,
compact: !!opts.compact,
sorted: !!opts.sorted,
showProxy: !!opts.showProxy,
});
}
/** @deprecated - use `Array.isArray()` instead. */
export function isArray(value: unknown): boolean {
return Array.isArray(value);
}
/** @deprecated - use `typeof value === "boolean" || value instanceof Boolean` instead. */
export function isBoolean(value: unknown): boolean {
return typeof value === "boolean" || value instanceof Boolean;
}
/** @deprecated - use `value === null` instead. */
export function isNull(value: unknown): boolean {
return value === null;
}
/** @deprecated - use `value === null || value === undefined` instead. */
export function isNullOrUndefined(value: unknown): boolean {
return value === null || value === undefined;
}
/** @deprecated - use `typeof value === "number" || value instanceof Number` instead. */
export function isNumber(value: unknown): boolean {
return typeof value === "number" || value instanceof Number;
}
/** @deprecated - use `typeof value === "string" || value instanceof String` instead. */
export function isString(value: unknown): boolean {
return typeof value === "string" || value instanceof String;
}
/** @deprecated - use `typeof value === "symbol"` instead. */
export function isSymbol(value: unknown): boolean {
return typeof value === "symbol";
}
/** @deprecated - use `value === undefined` instead. */
export function isUndefined(value: unknown): boolean {
return value === undefined;
}
/** @deprecated - use `value !== null && typeof value === "object"` instead. */
export function isObject(value: unknown): boolean {
return value !== null && typeof value === "object";
}
/** @deprecated - use `e instanceof Error` instead. */
export function isError(e: unknown): boolean {
return e instanceof Error;
}
/** @deprecated - use `typeof value === "function"` instead. */
export function isFunction(value: unknown): boolean {
return typeof value === "function";
}
/** @deprecated - use `value instanceof RegExp` instead. */
export function isRegExp(value: unknown): boolean {
return value instanceof RegExp;
}
/** @deprecated - use `value === null || (typeof value !== "object" && typeof value !== "function")` instead. */
export function isPrimitive(value: unknown): boolean {
return (
value === null || (typeof value !== "object" && typeof value !== "function")
);
}
/**
* Returns a system error name from an error code number.
* @param code error code number
*/
export function getSystemErrorName(code: number): string | undefined {
if (typeof code !== "number") {
throw new ERR_INVALID_ARG_TYPE("err", "number", code);
}
if (code >= 0 || !NumberIsSafeInteger(code)) {
throw new ERR_OUT_OF_RANGE("err", "a negative integer", code);
}
return errorMap.get(code)?.[0];
}
import { _TextDecoder, _TextEncoder } from "./_utils.ts";
/** The global TextDecoder */
export type TextDecoder = import("./_utils.ts")._TextDecoder;
export const TextDecoder = _TextDecoder;
/** The global TextEncoder */
export type TextEncoder = import("./_utils.ts")._TextEncoder;
export const TextEncoder = _TextEncoder;
export * from "./_util.ts";
import * as m from "./_util.ts";
export default m;