1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-25 15:29:32 -05:00

Port internal TS code to JS (#6793)

Co-authored-by: Ryan Dahl <ry@tinyclouds.org>
This commit is contained in:
Bartek Iwańczuk 2020-07-19 19:49:44 +02:00 committed by GitHub
parent 53adde866d
commit fa61956f03
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
204 changed files with 16611 additions and 19384 deletions

View file

@ -1,9 +1,11 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use deno_core::include_crate_modules;
use deno_core::js_check;
use deno_core::CoreIsolate;
use deno_core::StartupData;
use std::collections::HashMap;
use std::env;
use std::path::Path;
use std::path::PathBuf;
#[cfg(target_os = "windows")]
@ -11,6 +13,67 @@ extern crate winapi;
#[cfg(target_os = "windows")]
extern crate winres;
fn create_snapshot(
mut isolate: CoreIsolate,
snapshot_path: &Path,
files: Vec<String>,
) {
for file in files {
println!("cargo:rerun-if-changed={}", file);
js_check(isolate.execute(&file, &std::fs::read_to_string(&file).unwrap()));
}
let snapshot = isolate.snapshot();
let snapshot_slice: &[u8] = &*snapshot;
println!("Snapshot size: {}", snapshot_slice.len());
std::fs::write(&snapshot_path, snapshot_slice).unwrap();
println!("Snapshot written to: {} ", snapshot_path.display());
}
fn create_runtime_snapshot(snapshot_path: &Path, files: Vec<String>) {
let runtime_isolate = CoreIsolate::new(StartupData::None, true);
create_snapshot(runtime_isolate, snapshot_path, files);
}
fn create_compiler_snapshot(
snapshot_path: &Path,
files: Vec<String>,
cwd: &Path,
) {
let mut runtime_isolate = CoreIsolate::new(StartupData::None, true);
let mut custom_libs: HashMap<String, PathBuf> = HashMap::new();
custom_libs.insert(
"lib.deno.window.d.ts".to_string(),
cwd.join("js2/lib.deno.window.d.ts"),
);
custom_libs.insert(
"lib.deno.worker.d.ts".to_string(),
cwd.join("js2/lib.deno.worker.d.ts"),
);
custom_libs.insert(
"lib.deno.shared_globals.d.ts".to_string(),
cwd.join("js2/lib.deno.shared_globals.d.ts"),
);
custom_libs.insert(
"lib.deno.ns.d.ts".to_string(),
cwd.join("js2/lib.deno.ns.d.ts"),
);
custom_libs.insert(
"lib.deno.unstable.d.ts".to_string(),
cwd.join("js2/lib.deno.unstable.d.ts"),
);
runtime_isolate.register_op(
"op_fetch_asset",
deno_typescript::op_fetch_asset(custom_libs),
);
js_check(
runtime_isolate.execute("typescript.js", deno_typescript::TYPESCRIPT_CODE),
);
create_snapshot(runtime_isolate, snapshot_path, files);
}
fn main() {
// Don't build V8 if "cargo doc" is being run. This is to support docs.rs.
if env::var_os("RUSTDOCFLAGS").is_some() {
@ -30,82 +93,31 @@ fn main() {
std::env::var("TARGET").unwrap()
);
let extern_crate_modules = include_crate_modules![deno_core];
let c = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
let o = PathBuf::from(env::var_os("OUT_DIR").unwrap());
// Main snapshot
let root_names = vec![c.join("js/main.ts")];
let bundle_path = o.join("CLI_SNAPSHOT.js");
let snapshot_path = o.join("CLI_SNAPSHOT.bin");
let runtime_snapshot_path = o.join("CLI_SNAPSHOT.bin");
let compiler_snapshot_path = o.join("COMPILER_SNAPSHOT.bin");
let main_module_name = deno_typescript::compile_bundle(
&bundle_path,
root_names,
Some(extern_crate_modules.clone()),
)
.expect("Bundle compilation failed");
assert!(bundle_path.exists());
let mut js_files = std::fs::read_dir("js2/")
.unwrap()
.map(|dir_entry| {
let file = dir_entry.unwrap();
file.path().to_string_lossy().to_string()
})
.filter(|filename| filename.ends_with(".js"))
.collect::<Vec<String>>();
let mut runtime_isolate = CoreIsolate::new(StartupData::None, true);
js_files.sort();
deno_typescript::mksnapshot_bundle(
&mut runtime_isolate,
&snapshot_path,
&bundle_path,
&main_module_name,
)
.expect("Failed to create snapshot");
// Compiler snapshot
let root_names = vec![c.join("js/compiler.ts")];
let bundle_path = o.join("COMPILER_SNAPSHOT.js");
let snapshot_path = o.join("COMPILER_SNAPSHOT.bin");
let main_module_name = deno_typescript::compile_bundle(
&bundle_path,
root_names,
Some(extern_crate_modules),
)
.expect("Bundle compilation failed");
assert!(bundle_path.exists());
let mut runtime_isolate = CoreIsolate::new(StartupData::None, true);
let mut custom_libs: HashMap<String, PathBuf> = HashMap::new();
custom_libs.insert(
"lib.deno.window.d.ts".to_string(),
c.join("js/lib.deno.window.d.ts"),
);
custom_libs.insert(
"lib.deno.worker.d.ts".to_string(),
c.join("js/lib.deno.worker.d.ts"),
);
custom_libs.insert(
"lib.deno.shared_globals.d.ts".to_string(),
c.join("js/lib.deno.shared_globals.d.ts"),
);
custom_libs.insert(
"lib.deno.ns.d.ts".to_string(),
c.join("js/lib.deno.ns.d.ts"),
);
custom_libs.insert(
"lib.deno.unstable.d.ts".to_string(),
c.join("js/lib.deno.unstable.d.ts"),
);
runtime_isolate.register_op(
"op_fetch_asset",
deno_typescript::op_fetch_asset(custom_libs),
);
deno_typescript::mksnapshot_bundle_ts(
&mut runtime_isolate,
&snapshot_path,
&bundle_path,
&main_module_name,
)
.expect("Failed to create snapshot");
let runtime_files = js_files
.clone()
.into_iter()
.filter(|filepath| !filepath.ends_with("compiler.js"))
.collect::<Vec<String>>();
create_runtime_snapshot(&runtime_snapshot_path, runtime_files);
create_compiler_snapshot(&compiler_snapshot_path, js_files, &c);
set_binary_metadata();
}

View file

@ -1461,8 +1461,8 @@ mod tests {
.await;
assert!(r.is_err());
let p =
std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("js/main.ts");
let p = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("js2/99_main.js");
let specifier =
ModuleSpecifier::resolve_url_or_path(p.to_str().unwrap()).unwrap();
let r = fetcher
@ -1484,8 +1484,8 @@ mod tests {
.await;
assert!(r.is_err());
let p =
std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("js/main.ts");
let p = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("js2/99_main.js");
let specifier =
ModuleSpecifier::resolve_url_or_path(p.to_str().unwrap()).unwrap();
let r = fetcher

View file

@ -2,19 +2,13 @@ pub const TS_VERSION: &str = env!("TS_VERSION");
pub static CLI_SNAPSHOT: &[u8] =
include_bytes!(concat!(env!("OUT_DIR"), "/CLI_SNAPSHOT.bin"));
pub static CLI_SNAPSHOT_MAP: &[u8] =
include_bytes!(concat!(env!("OUT_DIR"), "/CLI_SNAPSHOT.js.map"));
pub static COMPILER_SNAPSHOT: &[u8] =
include_bytes!(concat!(env!("OUT_DIR"), "/COMPILER_SNAPSHOT.bin"));
pub static COMPILER_SNAPSHOT_MAP: &[u8] =
include_bytes!(concat!(env!("OUT_DIR"), "/COMPILER_SNAPSHOT.js.map"));
pub static DENO_NS_LIB: &str = include_str!("js/lib.deno.ns.d.ts");
pub static DENO_NS_LIB: &str = include_str!("js2/lib.deno.ns.d.ts");
pub static SHARED_GLOBALS_LIB: &str =
include_str!("js/lib.deno.shared_globals.d.ts");
pub static WINDOW_LIB: &str = include_str!("js/lib.deno.window.d.ts");
pub static UNSTABLE_NS_LIB: &str = include_str!("js/lib.deno.unstable.d.ts");
include_str!("js2/lib.deno.shared_globals.d.ts");
pub static WINDOW_LIB: &str = include_str!("js2/lib.deno.window.d.ts");
pub static UNSTABLE_NS_LIB: &str = include_str!("js2/lib.deno.unstable.d.ts");
#[test]
fn cli_snapshot() {

View file

@ -1,232 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// This code has been ported almost directly from Go's src/bytes/buffer.go
// Copyright 2009 The Go Authors. All rights reserved. BSD license.
// https://github.com/golang/go/blob/master/LICENSE
import type { Reader, Writer, ReaderSync, WriterSync } from "./io.ts";
import { assert } from "./util.ts";
// MIN_READ is the minimum ArrayBuffer size passed to a read call by
// buffer.ReadFrom. As long as the Buffer has at least MIN_READ bytes beyond
// what is required to hold the contents of r, readFrom() will not grow the
// underlying buffer.
const MIN_READ = 32 * 1024;
const MAX_SIZE = 2 ** 32 - 2;
// `off` is the offset into `dst` where it will at which to begin writing values
// from `src`.
// Returns the number of bytes copied.
function copyBytes(src: Uint8Array, dst: Uint8Array, off = 0): number {
const r = dst.byteLength - off;
if (src.byteLength > r) {
src = src.subarray(0, r);
}
dst.set(src, off);
return src.byteLength;
}
export class Buffer implements Reader, ReaderSync, Writer, WriterSync {
#buf: Uint8Array; // contents are the bytes buf[off : len(buf)]
#off = 0; // read at buf[off], write at buf[buf.byteLength]
constructor(ab?: ArrayBuffer) {
if (ab == null) {
this.#buf = new Uint8Array(0);
return;
}
this.#buf = new Uint8Array(ab);
}
bytes(options: { copy?: boolean } = { copy: true }): Uint8Array {
if (options.copy === false) return this.#buf.subarray(this.#off);
return this.#buf.slice(this.#off);
}
empty(): boolean {
return this.#buf.byteLength <= this.#off;
}
get length(): number {
return this.#buf.byteLength - this.#off;
}
get capacity(): number {
return this.#buf.buffer.byteLength;
}
truncate(n: number): void {
if (n === 0) {
this.reset();
return;
}
if (n < 0 || n > this.length) {
throw Error("bytes.Buffer: truncation out of range");
}
this.#reslice(this.#off + n);
}
reset(): void {
this.#reslice(0);
this.#off = 0;
}
#tryGrowByReslice = (n: number): number => {
const l = this.#buf.byteLength;
if (n <= this.capacity - l) {
this.#reslice(l + n);
return l;
}
return -1;
};
#reslice = (len: number): void => {
assert(len <= this.#buf.buffer.byteLength);
this.#buf = new Uint8Array(this.#buf.buffer, 0, len);
};
readSync(p: Uint8Array): number | null {
if (this.empty()) {
// Buffer is empty, reset to recover space.
this.reset();
if (p.byteLength === 0) {
// this edge case is tested in 'bufferReadEmptyAtEOF' test
return 0;
}
return null;
}
const nread = copyBytes(this.#buf.subarray(this.#off), p);
this.#off += nread;
return nread;
}
read(p: Uint8Array): Promise<number | null> {
const rr = this.readSync(p);
return Promise.resolve(rr);
}
writeSync(p: Uint8Array): number {
const m = this.#grow(p.byteLength);
return copyBytes(p, this.#buf, m);
}
write(p: Uint8Array): Promise<number> {
const n = this.writeSync(p);
return Promise.resolve(n);
}
#grow = (n: number): number => {
const m = this.length;
// If buffer is empty, reset to recover space.
if (m === 0 && this.#off !== 0) {
this.reset();
}
// Fast: Try to grow by means of a reslice.
const i = this.#tryGrowByReslice(n);
if (i >= 0) {
return i;
}
const c = this.capacity;
if (n <= Math.floor(c / 2) - m) {
// We can slide things down instead of allocating a new
// ArrayBuffer. We only need m+n <= c to slide, but
// we instead let capacity get twice as large so we
// don't spend all our time copying.
copyBytes(this.#buf.subarray(this.#off), this.#buf);
} else if (c + n > MAX_SIZE) {
throw new Error("The buffer cannot be grown beyond the maximum size.");
} else {
// Not enough space anywhere, we need to allocate.
const buf = new Uint8Array(Math.min(2 * c + n, MAX_SIZE));
copyBytes(this.#buf.subarray(this.#off), buf);
this.#buf = buf;
}
// Restore this.#off and len(this.#buf).
this.#off = 0;
this.#reslice(Math.min(m + n, MAX_SIZE));
return m;
};
grow(n: number): void {
if (n < 0) {
throw Error("Buffer.grow: negative count");
}
const m = this.#grow(n);
this.#reslice(m);
}
async readFrom(r: Reader): Promise<number> {
let n = 0;
const tmp = new Uint8Array(MIN_READ);
while (true) {
const shouldGrow = this.capacity - this.length < MIN_READ;
// read into tmp buffer if there's not enough room
// otherwise read directly into the internal buffer
const buf = shouldGrow
? tmp
: new Uint8Array(this.#buf.buffer, this.length);
const nread = await r.read(buf);
if (nread === null) {
return n;
}
// write will grow if needed
if (shouldGrow) this.writeSync(buf.subarray(0, nread));
else this.#reslice(this.length + nread);
n += nread;
}
}
readFromSync(r: ReaderSync): number {
let n = 0;
const tmp = new Uint8Array(MIN_READ);
while (true) {
const shouldGrow = this.capacity - this.length < MIN_READ;
// read into tmp buffer if there's not enough room
// otherwise read directly into the internal buffer
const buf = shouldGrow
? tmp
: new Uint8Array(this.#buf.buffer, this.length);
const nread = r.readSync(buf);
if (nread === null) {
return n;
}
// write will grow if needed
if (shouldGrow) this.writeSync(buf.subarray(0, nread));
else this.#reslice(this.length + nread);
n += nread;
}
}
}
export async function readAll(r: Reader): Promise<Uint8Array> {
const buf = new Buffer();
await buf.readFrom(r);
return buf.bytes();
}
export function readAllSync(r: ReaderSync): Uint8Array {
const buf = new Buffer();
buf.readFromSync(r);
return buf.bytes();
}
export async function writeAll(w: Writer, arr: Uint8Array): Promise<void> {
let nwritten = 0;
while (nwritten < arr.length) {
nwritten += await w.write(arr.subarray(nwritten));
}
}
export function writeAllSync(w: WriterSync, arr: Uint8Array): void {
let nwritten = 0;
while (nwritten < arr.length) {
nwritten += w.writeSync(arr.subarray(nwritten));
}
}

View file

@ -1,19 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
export const build = {
target: "unknown",
arch: "unknown",
os: "unknown",
vendor: "unknown",
env: undefined as string | undefined,
};
export function setBuildInfo(target: string): void {
const [arch, vendor, os, env] = target.split("-", 4);
build.target = target;
build.arch = arch;
build.vendor = vendor;
build.os = os;
build.env = env;
Object.freeze(build);
}

View file

@ -1,78 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
interface Code {
open: string;
close: string;
regexp: RegExp;
}
function code(open: number, close: number): Code {
return {
open: `\x1b[${open}m`,
close: `\x1b[${close}m`,
regexp: new RegExp(`\\x1b\\[${close}m`, "g"),
};
}
function run(str: string, code: Code): string {
return !globalThis || !globalThis.Deno || globalThis.Deno.noColor
? str
: `${code.open}${str.replace(code.regexp, code.open)}${code.close}`;
}
export function bold(str: string): string {
return run(str, code(1, 22));
}
export function italic(str: string): string {
return run(str, code(3, 23));
}
export function yellow(str: string): string {
return run(str, code(33, 39));
}
export function cyan(str: string): string {
return run(str, code(36, 39));
}
export function red(str: string): string {
return run(str, code(31, 39));
}
export function green(str: string): string {
return run(str, code(32, 39));
}
export function bgRed(str: string): string {
return run(str, code(41, 49));
}
export function white(str: string): string {
return run(str, code(37, 39));
}
export function gray(str: string): string {
return run(str, code(90, 39));
}
export function magenta(str: string): string {
return run(str, code(35, 39));
}
export function dim(str: string): string {
return run(str, code(2, 22));
}
// https://github.com/chalk/ansi-regex/blob/2b56fb0c7a07108e5b54241e8faec160d393aedb/index.js
const ANSI_PATTERN = new RegExp(
[
"[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
"(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))",
].join("|"),
"g",
);
export function stripColor(string: string): string {
return string.replace(ANSI_PATTERN, "");
}

File diff suppressed because it is too large Load diff

View file

@ -1,86 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// This file contains the runtime APIs which will dispatch work to the internal
// compiler within Deno.
import type { DiagnosticItem } from "./diagnostics.ts";
import * as util from "./util.ts";
import * as runtimeCompilerOps from "./ops/runtime_compiler.ts";
import type { TranspileOnlyResult } from "./ops/runtime_compiler.ts";
import type { CompilerOptions } from "./compiler_options.ts";
function checkRelative(specifier: string): string {
return specifier.match(/^([\.\/\\]|https?:\/{2}|file:\/{2})/)
? specifier
: `./${specifier}`;
}
// TODO(bartlomieju): change return type to interface?
export function transpileOnly(
sources: Record<string, string>,
options: CompilerOptions = {},
): Promise<Record<string, TranspileOnlyResult>> {
util.log("Deno.transpileOnly", { sources: Object.keys(sources), options });
const payload = {
sources,
options: JSON.stringify(options),
};
return runtimeCompilerOps.transpile(payload);
}
// TODO(bartlomieju): change return type to interface?
export async function compile(
rootName: string,
sources?: Record<string, string>,
options: CompilerOptions = {},
): Promise<[DiagnosticItem[] | undefined, Record<string, string>]> {
const payload = {
rootName: sources ? rootName : checkRelative(rootName),
sources,
options: JSON.stringify(options),
bundle: false,
};
util.log("Deno.compile", {
rootName: payload.rootName,
sources: !!sources,
options,
});
const result = await runtimeCompilerOps.compile(payload);
util.assert(result.emitMap);
const maybeDiagnostics = result.diagnostics.length === 0
? undefined
: result.diagnostics;
const emitMap: Record<string, string> = {};
for (const [key, emittedSource] of Object.entries(result.emitMap)) {
emitMap[key] = emittedSource.contents;
}
return [maybeDiagnostics, emitMap];
}
// TODO(bartlomieju): change return type to interface?
export async function bundle(
rootName: string,
sources?: Record<string, string>,
options: CompilerOptions = {},
): Promise<[DiagnosticItem[] | undefined, string]> {
const payload = {
rootName: sources ? rootName : checkRelative(rootName),
sources,
options: JSON.stringify(options),
bundle: true,
};
util.log("Deno.bundle", {
rootName: payload.rootName,
sources: !!sources,
options,
});
const result = await runtimeCompilerOps.compile(payload);
util.assert(result.output);
const maybeDiagnostics = result.diagnostics.length === 0
? undefined
: result.diagnostics;
return [maybeDiagnostics, result.output];
}

View file

@ -1,133 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
export interface CompilerOptions {
allowJs?: boolean;
allowSyntheticDefaultImports?: boolean;
allowUmdGlobalAccess?: boolean;
allowUnreachableCode?: boolean;
allowUnusedLabels?: boolean;
alwaysStrict?: boolean;
baseUrl?: string;
checkJs?: boolean;
declaration?: boolean;
declarationDir?: string;
declarationMap?: boolean;
downlevelIteration?: boolean;
emitBOM?: boolean;
emitDeclarationOnly?: boolean;
emitDecoratorMetadata?: boolean;
esModuleInterop?: boolean;
experimentalDecorators?: boolean;
inlineSourceMap?: boolean;
inlineSources?: boolean;
isolatedModules?: boolean;
jsx?: "react" | "preserve" | "react-native";
jsxFactory?: string;
keyofStringsOnly?: string;
useDefineForClassFields?: boolean;
lib?: string[];
locale?: string;
mapRoot?: string;
module?:
| "none"
| "commonjs"
| "amd"
| "system"
| "umd"
| "es6"
| "es2015"
| "esnext";
noEmitHelpers?: boolean;
noFallthroughCasesInSwitch?: boolean;
noImplicitAny?: boolean;
noImplicitReturns?: boolean;
noImplicitThis?: boolean;
noImplicitUseStrict?: boolean;
noResolve?: boolean;
noStrictGenericChecks?: boolean;
noUnusedLocals?: boolean;
noUnusedParameters?: boolean;
outDir?: string;
paths?: Record<string, string[]>;
preserveConstEnums?: boolean;
removeComments?: boolean;
resolveJsonModule?: boolean;
rootDir?: string;
rootDirs?: string[];
sourceMap?: boolean;
sourceRoot?: string;
strict?: boolean;
strictBindCallApply?: boolean;
strictFunctionTypes?: boolean;
strictPropertyInitialization?: boolean;
strictNullChecks?: boolean;
suppressExcessPropertyErrors?: boolean;
suppressImplicitAnyIndexErrors?: boolean;
target?:
| "es3"
| "es5"
| "es6"
| "es2015"
| "es2016"
| "es2017"
| "es2018"
| "es2019"
| "es2020"
| "esnext";
types?: string[];
}

View file

@ -1,5 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// This allows us to access core in API even if we
// dispose window.Deno
export const core = globalThis.Deno.core as DenoCore;

View file

@ -1,91 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// This module exports stable Deno APIs.
export {
Buffer,
readAll,
readAllSync,
writeAll,
writeAllSync,
} from "./buffer.ts";
export { build } from "./build.ts";
export { chmodSync, chmod } from "./ops/fs/chmod.ts";
export { chownSync, chown } from "./ops/fs/chown.ts";
export { customInspect, inspect } from "./web/console.ts";
export { copyFileSync, copyFile } from "./ops/fs/copy_file.ts";
export { chdir, cwd } from "./ops/fs/dir.ts";
export { errors } from "./errors.ts";
export {
File,
open,
openSync,
create,
createSync,
stdin,
stdout,
stderr,
seek,
seekSync,
} from "./files.ts";
export type { OpenOptions } from "./files.ts";
export { read, readSync, write, writeSync } from "./ops/io.ts";
export { watchFs } from "./ops/fs_events.ts";
export type { FsEvent } from "./ops/fs_events.ts";
export { internalSymbol as internal } from "./internals.ts";
export { copy, iter, iterSync } from "./io.ts";
export { SeekMode } from "./io.ts";
export type {
Reader,
ReaderSync,
Writer,
WriterSync,
Closer,
Seeker,
} from "./io.ts";
export {
makeTempDirSync,
makeTempDir,
makeTempFileSync,
makeTempFile,
} from "./ops/fs/make_temp.ts";
export type { MakeTempOptions } from "./ops/fs/make_temp.ts";
export { metrics } from "./ops/runtime.ts";
export type { Metrics } from "./ops/runtime.ts";
export { mkdirSync, mkdir } from "./ops/fs/mkdir.ts";
export type { MkdirOptions } from "./ops/fs/mkdir.ts";
export { connect, listen } from "./net.ts";
export type { Listener, Conn } from "./net.ts";
export { env, exit, execPath } from "./ops/os.ts";
export { Process, run } from "./process.ts";
export type { RunOptions, ProcessStatus } from "./process.ts";
export { readDirSync, readDir } from "./ops/fs/read_dir.ts";
export type { DirEntry } from "./ops/fs/read_dir.ts";
export { readFileSync, readFile } from "./read_file.ts";
export { readTextFileSync, readTextFile } from "./read_text_file.ts";
export { readLinkSync, readLink } from "./ops/fs/read_link.ts";
export { realPathSync, realPath } from "./ops/fs/real_path.ts";
export { removeSync, remove } from "./ops/fs/remove.ts";
export type { RemoveOptions } from "./ops/fs/remove.ts";
export { renameSync, rename } from "./ops/fs/rename.ts";
export { resources, close } from "./ops/resources.ts";
export { statSync, lstatSync, stat, lstat } from "./ops/fs/stat.ts";
export type { FileInfo } from "./ops/fs/stat.ts";
export { connectTls, listenTls } from "./tls.ts";
export { truncateSync, truncate } from "./ops/fs/truncate.ts";
export { isatty } from "./ops/tty.ts";
export { version } from "./version.ts";
export { writeFileSync, writeFile } from "./write_file.ts";
export type { WriteFileOptions } from "./write_file.ts";
export { writeTextFileSync, writeTextFile } from "./write_text_file.ts";
export const args: string[] = [];
export { test } from "./testing.ts";
export type { TestDefinition } from "./testing.ts";
// These are internal Deno APIs. We are marking them as internal so they do not
// appear in the runtime type library.
export { core } from "./core.ts";
export let pid: number;
export let noColor: boolean;

View file

@ -1,30 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// This module exports unstable Deno APIs.
export { umask } from "./ops/fs/umask.ts";
export { linkSync, link } from "./ops/fs/link.ts";
export { fstatSync, fstat } from "./ops/fs/stat.ts";
export { fdatasyncSync, fdatasync, fsyncSync, fsync } from "./ops/fs/sync.ts";
export { symlinkSync, symlink } from "./ops/fs/symlink.ts";
export { loadavg, osRelease, hostname } from "./ops/os.ts";
export { openPlugin } from "./ops/plugins.ts";
export { transpileOnly, compile, bundle } from "./compiler_api.ts";
export { applySourceMap, formatDiagnostics } from "./ops/errors.ts";
export { signal, signals, Signal, SignalStream } from "./signals.ts";
export { setRaw, consoleSize } from "./ops/tty.ts";
export { utimeSync, utime } from "./ops/fs/utime.ts";
export { ftruncateSync, ftruncate } from "./ops/fs/truncate.ts";
export { shutdown, ShutdownMode } from "./net.ts";
export { listen, listenDatagram, connect } from "./net_unstable.ts";
export { startTls } from "./tls.ts";
export { kill } from "./ops/process.ts";
export { permissions, Permissions } from "./permissions.ts";
export { PermissionStatus } from "./permissions.ts";
export type { PermissionName, PermissionState } from "./permissions.ts";
export { DiagnosticCategory } from "./diagnostics.ts";
export type {
Diagnostic,
DiagnosticItem,
DiagnosticMessageChain,
} from "./diagnostics.ts";

View file

@ -1,51 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// Diagnostic provides an abstraction for advice/errors received from a
// compiler, which is strongly influenced by the format of TypeScript
// diagnostics.
export enum DiagnosticCategory {
Log = 0,
Debug = 1,
Info = 2,
Error = 3,
Warning = 4,
Suggestion = 5,
}
export interface DiagnosticMessageChain {
message: string;
category: DiagnosticCategory;
code: number;
next?: DiagnosticMessageChain[];
}
export interface DiagnosticItem {
message: string;
messageChain?: DiagnosticMessageChain;
relatedInformation?: DiagnosticItem[];
sourceLine?: string;
lineNumber?: number;
scriptResourceName?: string;
startPosition?: number;
endPosition?: number;
category: DiagnosticCategory;
code: number;
startColumn?: number;
endColumn?: number;
}
export interface Diagnostic {
items: DiagnosticItem[];
}

View file

@ -1,252 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// These utilities are used by compiler.ts to format TypeScript diagnostics
// into Deno Diagnostics.
import {
Diagnostic,
DiagnosticCategory,
DiagnosticMessageChain,
DiagnosticItem,
} from "./diagnostics.ts";
const unstableDenoGlobalProperties = [
"umask",
"linkSync",
"link",
"symlinkSync",
"symlink",
"loadavg",
"osRelease",
"openPlugin",
"DiagnosticCategory",
"DiagnosticMessageChain",
"DiagnosticItem",
"Diagnostic",
"formatDiagnostics",
"CompilerOptions",
"TranspileOnlyResult",
"transpileOnly",
"compile",
"bundle",
"Location",
"applySourceMap",
"LinuxSignal",
"MacOSSignal",
"Signal",
"SignalStream",
"signal",
"signals",
"setRaw",
"utimeSync",
"utime",
"ShutdownMode",
"shutdown",
"DatagramConn",
"UnixListenOptions",
"listen",
"listenDatagram",
"UnixConnectOptions",
"connect",
"StartTlsOptions",
"startTls",
"kill",
"PermissionName",
"PermissionState",
"RunPermissionDescriptor",
"ReadPermissionDescriptor",
"WritePermissionDescriptor",
"NetPermissionDescriptor",
"EnvPermissionDescriptor",
"PluginPermissionDescriptor",
"HrtimePermissionDescriptor",
"PermissionDescriptor",
"Permissions",
"PermissionStatus",
"hostname",
"ppid",
];
function transformMessageText(messageText: string, code: number): string {
switch (code) {
case 2339: {
const property = messageText
.replace(/^Property '/, "")
.replace(/' does not exist on type 'typeof Deno'\./, "");
if (
messageText.endsWith("on type 'typeof Deno'.") &&
unstableDenoGlobalProperties.includes(property)
) {
return `${messageText} 'Deno.${property}' is an unstable API. Did you forget to run with the '--unstable' flag?`;
}
break;
}
case 2551: {
const suggestionMessagePattern = / Did you mean '(.+)'\?$/;
const property = messageText
.replace(/^Property '/, "")
.replace(/' does not exist on type 'typeof Deno'\./, "")
.replace(suggestionMessagePattern, "");
const suggestion = messageText.match(suggestionMessagePattern);
const replacedMessageText = messageText.replace(
suggestionMessagePattern,
"",
);
if (suggestion && unstableDenoGlobalProperties.includes(property)) {
const suggestedProperty = suggestion[1];
return `${replacedMessageText} 'Deno.${property}' is an unstable API. Did you forget to run with the '--unstable' flag, or did you mean '${suggestedProperty}'?`;
}
break;
}
}
return messageText;
}
interface SourceInformation {
sourceLine: string;
lineNumber: number;
scriptResourceName: string;
startColumn: number;
endColumn: number;
}
function fromDiagnosticCategory(
category: ts.DiagnosticCategory,
): DiagnosticCategory {
switch (category) {
case ts.DiagnosticCategory.Error:
return DiagnosticCategory.Error;
case ts.DiagnosticCategory.Message:
return DiagnosticCategory.Info;
case ts.DiagnosticCategory.Suggestion:
return DiagnosticCategory.Suggestion;
case ts.DiagnosticCategory.Warning:
return DiagnosticCategory.Warning;
default:
throw new Error(
`Unexpected DiagnosticCategory: "${category}"/"${
ts.DiagnosticCategory[category]
}"`,
);
}
}
function getSourceInformation(
sourceFile: ts.SourceFile,
start: number,
length: number,
): SourceInformation {
const scriptResourceName = sourceFile.fileName;
const {
line: lineNumber,
character: startColumn,
} = sourceFile.getLineAndCharacterOfPosition(start);
const endPosition = sourceFile.getLineAndCharacterOfPosition(start + length);
const endColumn = lineNumber === endPosition.line
? endPosition.character
: startColumn;
const lastLineInFile = sourceFile.getLineAndCharacterOfPosition(
sourceFile.text.length,
).line;
const lineStart = sourceFile.getPositionOfLineAndCharacter(lineNumber, 0);
const lineEnd = lineNumber < lastLineInFile
? sourceFile.getPositionOfLineAndCharacter(lineNumber + 1, 0)
: sourceFile.text.length;
const sourceLine = sourceFile.text
.slice(lineStart, lineEnd)
.replace(/\s+$/g, "")
.replace("\t", " ");
return {
sourceLine,
lineNumber,
scriptResourceName,
startColumn,
endColumn,
};
}
function fromDiagnosticMessageChain(
messageChain: ts.DiagnosticMessageChain[] | undefined,
): DiagnosticMessageChain[] | undefined {
if (!messageChain) {
return undefined;
}
return messageChain.map(({ messageText, code, category, next }) => {
const message = transformMessageText(messageText, code);
return {
message,
code,
category: fromDiagnosticCategory(category),
next: fromDiagnosticMessageChain(next),
};
});
}
function parseDiagnostic(
item: ts.Diagnostic | ts.DiagnosticRelatedInformation,
): DiagnosticItem {
const {
messageText,
category: sourceCategory,
code,
file,
start: startPosition,
length,
} = item;
const sourceInfo = file && startPosition && length
? getSourceInformation(file, startPosition, length)
: undefined;
const endPosition = startPosition && length
? startPosition + length
: undefined;
const category = fromDiagnosticCategory(sourceCategory);
let message: string;
let messageChain: DiagnosticMessageChain | undefined;
if (typeof messageText === "string") {
message = transformMessageText(messageText, code);
} else {
message = transformMessageText(messageText.messageText, messageText.code);
messageChain = fromDiagnosticMessageChain([messageText])![0];
}
const base = {
message,
messageChain,
code,
category,
startPosition,
endPosition,
};
return sourceInfo ? { ...base, ...sourceInfo } : base;
}
function parseRelatedInformation(
relatedInformation: readonly ts.DiagnosticRelatedInformation[],
): DiagnosticItem[] {
const result: DiagnosticItem[] = [];
for (const item of relatedInformation) {
result.push(parseDiagnostic(item));
}
return result;
}
export function fromTypeScriptDiagnostic(
diagnostics: readonly ts.Diagnostic[],
): Diagnostic {
const items: DiagnosticItem[] = [];
for (const sourceDiagnostic of diagnostics) {
const item: DiagnosticItem = parseDiagnostic(sourceDiagnostic);
if (sourceDiagnostic.relatedInformation) {
item.relatedInformation = parseRelatedInformation(
sourceDiagnostic.relatedInformation,
);
}
items.push(item);
}
return { items };
}

View file

@ -1,265 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// Some of the code here is adapted directly from V8 and licensed under a BSD
// style license available here: https://github.com/v8/v8/blob/24886f2d1c565287d33d71e4109a53bf0b54b75c/LICENSE.v8
import * as colors from "./colors.ts";
import { applySourceMap, Location } from "./ops/errors.ts";
import { assert } from "./util.ts";
import { exposeForTest } from "./internals.ts";
function patchCallSite(callSite: CallSite, location: Location): CallSite {
return {
getThis(): unknown {
return callSite.getThis();
},
getTypeName(): string | null {
return callSite.getTypeName();
},
getFunction(): Function | null {
return callSite.getFunction();
},
getFunctionName(): string | null {
return callSite.getFunctionName();
},
getMethodName(): string | null {
return callSite.getMethodName();
},
getFileName(): string | null {
return location.fileName;
},
getLineNumber(): number {
return location.lineNumber;
},
getColumnNumber(): number {
return location.columnNumber;
},
getEvalOrigin(): string | null {
return callSite.getEvalOrigin();
},
isToplevel(): boolean | null {
return callSite.isToplevel();
},
isEval(): boolean {
return callSite.isEval();
},
isNative(): boolean {
return callSite.isNative();
},
isConstructor(): boolean {
return callSite.isConstructor();
},
isAsync(): boolean {
return callSite.isAsync();
},
isPromiseAll(): boolean {
return callSite.isPromiseAll();
},
getPromiseIndex(): number | null {
return callSite.getPromiseIndex();
},
};
}
function getMethodCall(callSite: CallSite): string {
let result = "";
const typeName = callSite.getTypeName();
const methodName = callSite.getMethodName();
const functionName = callSite.getFunctionName();
if (functionName) {
if (typeName) {
const startsWithTypeName = functionName.startsWith(typeName);
if (!startsWithTypeName) {
result += `${typeName}.`;
}
}
result += functionName;
if (methodName) {
if (!functionName.endsWith(methodName)) {
result += ` [as ${methodName}]`;
}
}
} else {
if (typeName) {
result += `${typeName}.`;
}
if (methodName) {
result += methodName;
} else {
result += "<anonymous>";
}
}
return result;
}
function getFileLocation(callSite: CallSite, internal = false): string {
const cyan = internal ? colors.gray : colors.cyan;
const yellow = internal ? colors.gray : colors.yellow;
const black = internal ? colors.gray : (s: string): string => s;
if (callSite.isNative()) {
return cyan("native");
}
let result = "";
const fileName = callSite.getFileName();
if (!fileName && callSite.isEval()) {
const evalOrigin = callSite.getEvalOrigin();
assert(evalOrigin != null);
result += cyan(`${evalOrigin}, `);
}
if (fileName) {
result += cyan(fileName);
} else {
result += cyan("<anonymous>");
}
const lineNumber = callSite.getLineNumber();
if (lineNumber != null) {
result += `${black(":")}${yellow(lineNumber.toString())}`;
const columnNumber = callSite.getColumnNumber();
if (columnNumber != null) {
result += `${black(":")}${yellow(columnNumber.toString())}`;
}
}
return result;
}
function callSiteToString(callSite: CallSite, internal = false): string {
const cyan = internal ? colors.gray : colors.cyan;
const black = internal ? colors.gray : (s: string): string => s;
let result = "";
const functionName = callSite.getFunctionName();
const isTopLevel = callSite.isToplevel();
const isAsync = callSite.isAsync();
const isPromiseAll = callSite.isPromiseAll();
const isConstructor = callSite.isConstructor();
const isMethodCall = !(isTopLevel || isConstructor);
if (isAsync) {
result += colors.gray("async ");
}
if (isPromiseAll) {
result += colors.bold(
colors.italic(black(`Promise.all (index ${callSite.getPromiseIndex()})`)),
);
return result;
}
if (isMethodCall) {
result += colors.bold(colors.italic(black(getMethodCall(callSite))));
} else if (isConstructor) {
result += colors.gray("new ");
if (functionName) {
result += colors.bold(colors.italic(black(functionName)));
} else {
result += cyan("<anonymous>");
}
} else if (functionName) {
result += colors.bold(colors.italic(black(functionName)));
} else {
result += getFileLocation(callSite, internal);
return result;
}
result += ` ${black("(")}${getFileLocation(callSite, internal)}${black(")")}`;
return result;
}
interface CallSiteEval {
this: unknown;
typeName: string | null;
function: Function | null;
functionName: string | null;
methodName: string | null;
fileName: string | null;
lineNumber: number | null;
columnNumber: number | null;
evalOrigin: string | null;
isToplevel: boolean | null;
isEval: boolean;
isNative: boolean;
isConstructor: boolean;
isAsync: boolean;
isPromiseAll: boolean;
promiseIndex: number | null;
}
function evaluateCallSite(callSite: CallSite): CallSiteEval {
return {
this: callSite.getThis(),
typeName: callSite.getTypeName(),
function: callSite.getFunction(),
functionName: callSite.getFunctionName(),
methodName: callSite.getMethodName(),
fileName: callSite.getFileName(),
lineNumber: callSite.getLineNumber(),
columnNumber: callSite.getColumnNumber(),
evalOrigin: callSite.getEvalOrigin(),
isToplevel: callSite.isToplevel(),
isEval: callSite.isEval(),
isNative: callSite.isNative(),
isConstructor: callSite.isConstructor(),
isAsync: callSite.isAsync(),
isPromiseAll: callSite.isPromiseAll(),
promiseIndex: callSite.getPromiseIndex(),
};
}
function prepareStackTrace(
error: Error & {
__callSiteEvals: CallSiteEval[];
__formattedFrames: string[];
},
callSites: CallSite[],
): string {
const mappedCallSites = callSites.map(
(callSite): CallSite => {
const fileName = callSite.getFileName();
const lineNumber = callSite.getLineNumber();
const columnNumber = callSite.getColumnNumber();
if (fileName && lineNumber != null && columnNumber != null) {
return patchCallSite(
callSite,
applySourceMap({
fileName,
lineNumber,
columnNumber,
}),
);
}
return callSite;
},
);
Object.defineProperties(error, {
__callSiteEvals: { value: [], configurable: true },
__formattedFrames: { value: [], configurable: true },
});
for (const callSite of mappedCallSites) {
error.__callSiteEvals.push(Object.freeze(evaluateCallSite(callSite)));
const isInternal = callSite.getFileName()?.startsWith("$deno$") ?? false;
error.__formattedFrames.push(callSiteToString(callSite, isInternal));
}
Object.freeze(error.__callSiteEvals);
Object.freeze(error.__formattedFrames);
return (
`${error.name}: ${error.message}\n` +
error.__formattedFrames
.map((s: string) => ` at ${colors.stripColor(s)}`)
.join("\n")
);
}
// @internal
export function setPrepareStackTrace(ErrorConstructor: typeof Error): void {
ErrorConstructor.prepareStackTrace = prepareStackTrace;
}
exposeForTest("setPrepareStackTrace", setPrepareStackTrace);

View file

@ -1,225 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// Warning! The values in this enum are duplicated in cli/op_error.rs
// Update carefully!
export enum ErrorKind {
NotFound = 1,
PermissionDenied = 2,
ConnectionRefused = 3,
ConnectionReset = 4,
ConnectionAborted = 5,
NotConnected = 6,
AddrInUse = 7,
AddrNotAvailable = 8,
BrokenPipe = 9,
AlreadyExists = 10,
InvalidData = 13,
TimedOut = 14,
Interrupted = 15,
WriteZero = 16,
UnexpectedEof = 17,
BadResource = 18,
Http = 19,
URIError = 20,
TypeError = 21,
Other = 22,
Busy = 23,
}
interface ErrorClass {
new (msg: string): Error;
}
export function getErrorClass(kind: ErrorKind): ErrorClass {
switch (kind) {
case ErrorKind.TypeError:
return TypeError;
case ErrorKind.Other:
return Error;
case ErrorKind.URIError:
return URIError;
case ErrorKind.NotFound:
return NotFound;
case ErrorKind.PermissionDenied:
return PermissionDenied;
case ErrorKind.ConnectionRefused:
return ConnectionRefused;
case ErrorKind.ConnectionReset:
return ConnectionReset;
case ErrorKind.ConnectionAborted:
return ConnectionAborted;
case ErrorKind.NotConnected:
return NotConnected;
case ErrorKind.AddrInUse:
return AddrInUse;
case ErrorKind.AddrNotAvailable:
return AddrNotAvailable;
case ErrorKind.BrokenPipe:
return BrokenPipe;
case ErrorKind.AlreadyExists:
return AlreadyExists;
case ErrorKind.InvalidData:
return InvalidData;
case ErrorKind.TimedOut:
return TimedOut;
case ErrorKind.Interrupted:
return Interrupted;
case ErrorKind.WriteZero:
return WriteZero;
case ErrorKind.UnexpectedEof:
return UnexpectedEof;
case ErrorKind.BadResource:
return BadResource;
case ErrorKind.Http:
return Http;
case ErrorKind.Busy:
return Busy;
}
}
class NotFound extends Error {
constructor(msg: string) {
super(msg);
this.name = "NotFound";
}
}
class PermissionDenied extends Error {
constructor(msg: string) {
super(msg);
this.name = "PermissionDenied";
}
}
class ConnectionRefused extends Error {
constructor(msg: string) {
super(msg);
this.name = "ConnectionRefused";
}
}
class ConnectionReset extends Error {
constructor(msg: string) {
super(msg);
this.name = "ConnectionReset";
}
}
class ConnectionAborted extends Error {
constructor(msg: string) {
super(msg);
this.name = "ConnectionAborted";
}
}
class NotConnected extends Error {
constructor(msg: string) {
super(msg);
this.name = "NotConnected";
}
}
class AddrInUse extends Error {
constructor(msg: string) {
super(msg);
this.name = "AddrInUse";
}
}
class AddrNotAvailable extends Error {
constructor(msg: string) {
super(msg);
this.name = "AddrNotAvailable";
}
}
class BrokenPipe extends Error {
constructor(msg: string) {
super(msg);
this.name = "BrokenPipe";
}
}
class AlreadyExists extends Error {
constructor(msg: string) {
super(msg);
this.name = "AlreadyExists";
}
}
class InvalidData extends Error {
constructor(msg: string) {
super(msg);
this.name = "InvalidData";
}
}
class TimedOut extends Error {
constructor(msg: string) {
super(msg);
this.name = "TimedOut";
}
}
class Interrupted extends Error {
constructor(msg: string) {
super(msg);
this.name = "Interrupted";
}
}
class WriteZero extends Error {
constructor(msg: string) {
super(msg);
this.name = "WriteZero";
}
}
class UnexpectedEof extends Error {
constructor(msg: string) {
super(msg);
this.name = "UnexpectedEof";
}
}
class BadResource extends Error {
constructor(msg: string) {
super(msg);
this.name = "BadResource";
}
}
class Http extends Error {
constructor(msg: string) {
super(msg);
this.name = "Http";
}
}
class Busy extends Error {
constructor(msg: string) {
super(msg);
this.name = "Busy";
}
}
export const errors = {
NotFound,
PermissionDenied,
ConnectionRefused,
ConnectionReset,
ConnectionAborted,
NotConnected,
AddrInUse,
AddrNotAvailable,
BrokenPipe,
AlreadyExists,
InvalidData,
TimedOut,
Interrupted,
WriteZero,
UnexpectedEof,
BadResource,
Http,
Busy,
};

View file

@ -1,169 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import type {
Reader,
Writer,
Seeker,
Closer,
SeekMode,
ReaderSync,
WriterSync,
SeekerSync,
} from "./io.ts";
import { close } from "./ops/resources.ts";
import { read, readSync, write, writeSync } from "./ops/io.ts";
import { seek, seekSync } from "./ops/fs/seek.ts";
export { seek, seekSync } from "./ops/fs/seek.ts";
import {
open as opOpen,
openSync as opOpenSync,
OpenOptions,
} from "./ops/fs/open.ts";
export type { OpenOptions } from "./ops/fs/open.ts";
export function openSync(
path: string | URL,
options: OpenOptions = { read: true },
): File {
checkOpenOptions(options);
const rid = opOpenSync(path, options);
return new File(rid);
}
export async function open(
path: string | URL,
options: OpenOptions = { read: true },
): Promise<File> {
checkOpenOptions(options);
const rid = await opOpen(path, options);
return new File(rid);
}
export function createSync(path: string | URL): File {
return openSync(path, {
read: true,
write: true,
truncate: true,
create: true,
});
}
export function create(path: string | URL): Promise<File> {
return open(path, {
read: true,
write: true,
truncate: true,
create: true,
});
}
export class File
implements
Reader,
ReaderSync,
Writer,
WriterSync,
Seeker,
SeekerSync,
Closer {
constructor(readonly rid: number) {}
write(p: Uint8Array): Promise<number> {
return write(this.rid, p);
}
writeSync(p: Uint8Array): number {
return writeSync(this.rid, p);
}
read(p: Uint8Array): Promise<number | null> {
return read(this.rid, p);
}
readSync(p: Uint8Array): number | null {
return readSync(this.rid, p);
}
seek(offset: number, whence: SeekMode): Promise<number> {
return seek(this.rid, offset, whence);
}
seekSync(offset: number, whence: SeekMode): number {
return seekSync(this.rid, offset, whence);
}
close(): void {
close(this.rid);
}
}
class Stdin implements Reader, ReaderSync, Closer {
readonly rid = 0;
read(p: Uint8Array): Promise<number | null> {
return read(this.rid, p);
}
readSync(p: Uint8Array): number | null {
return readSync(this.rid, p);
}
close(): void {
close(this.rid);
}
}
class Stdout implements Writer, WriterSync, Closer {
readonly rid = 1;
write(p: Uint8Array): Promise<number> {
return write(this.rid, p);
}
writeSync(p: Uint8Array): number {
return writeSync(this.rid, p);
}
close(): void {
close(this.rid);
}
}
export class Stderr implements Writer, WriterSync, Closer {
readonly rid = 2;
write(p: Uint8Array): Promise<number> {
return write(this.rid, p);
}
writeSync(p: Uint8Array): number {
return writeSync(this.rid, p);
}
close(): void {
close(this.rid);
}
}
export const stdin = new Stdin();
export const stdout = new Stdout();
export const stderr = new Stderr();
function checkOpenOptions(options: OpenOptions): void {
if (Object.values(options).filter((val) => val === true).length === 0) {
throw new Error("OpenOptions requires at least one option to be true");
}
if (options.truncate && !options.write) {
throw new Error("'truncate' option requires 'write' option");
}
const createOrCreateNewWithoutWriteOrAppend =
(options.create || options.createNew) && !(options.write || options.append);
if (createOrCreateNewWithoutWriteOrAppend) {
throw new Error(
"'create' or 'createNew' options require 'write' or 'append' option",
);
}
}

View file

@ -1,263 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import "./lib.deno.shared_globals.d.ts";
import * as abortController from "./web/abort_controller.ts";
import * as abortSignal from "./web/abort_signal.ts";
import * as blob from "./web/blob.ts";
import * as consoleTypes from "./web/console.ts";
import * as csprng from "./ops/get_random_values.ts";
import type * as promiseTypes from "./web/promise.ts";
import * as customEvent from "./web/custom_event.ts";
import * as domException from "./web/dom_exception.ts";
import * as domFile from "./web/dom_file.ts";
import * as errorEvent from "./web/error_event.ts";
import * as event from "./web/event.ts";
import * as eventTarget from "./web/event_target.ts";
import * as formData from "./web/form_data.ts";
import * as fetchTypes from "./web/fetch.ts";
import * as headers from "./web/headers.ts";
import * as textEncoding from "./web/text_encoding.ts";
import * as timers from "./web/timers.ts";
import * as url from "./web/url.ts";
import * as urlSearchParams from "./web/url_search_params.ts";
import * as workers from "./web/workers.ts";
import * as performance from "./web/performance.ts";
import * as request from "./web/request.ts";
import * as readableStream from "./web/streams/readable_stream.ts";
import * as transformStream from "./web/streams/transform_stream.ts";
import * as queuingStrategy from "./web/streams/queuing_strategy.ts";
import * as writableStream from "./web/streams/writable_stream.ts";
// These imports are not exposed and therefore are fine to just import the
// symbols required.
import { core } from "./core.ts";
// This global augmentation is just enough types to be able to build Deno,
// the runtime types are fully defined in `lib.deno.*.d.ts`.
declare global {
interface CallSite {
getThis(): unknown;
getTypeName(): string | null;
getFunction(): Function | null;
getFunctionName(): string | null;
getMethodName(): string | null;
getFileName(): string | null;
getLineNumber(): number | null;
getColumnNumber(): number | null;
getEvalOrigin(): string | null;
isToplevel(): boolean | null;
isEval(): boolean;
isNative(): boolean;
isConstructor(): boolean;
isAsync(): boolean;
isPromiseAll(): boolean;
getPromiseIndex(): number | null;
}
interface ErrorConstructor {
prepareStackTrace(error: Error, structuredStackTrace: CallSite[]): string;
}
interface Object {
[consoleTypes.customInspect]?(): string;
}
interface EvalErrorInfo {
isNativeError: boolean;
isCompileError: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
thrown: any;
}
interface ImportMeta {
url: string;
main: boolean;
}
interface DenoCore {
print(s: string, isErr?: boolean): void;
dispatch(opId: number, ...zeroCopy: ArrayBufferView[]): Uint8Array | null;
dispatchByName(
opName: string,
...zeroCopy: ArrayBufferView[]
): Uint8Array | null;
setAsyncHandler(opId: number, cb: (msg: Uint8Array) => void): void;
sharedQueue: {
head(): number;
numRecords(): number;
size(): number;
push(buf: Uint8Array): boolean;
reset(): void;
shift(): Uint8Array | null;
};
ops(): Record<string, number>;
recv(cb: (opId: number, msg: Uint8Array) => void): void;
send(opId: number, ...data: ArrayBufferView[]): null | Uint8Array;
setMacrotaskCallback(cb: () => boolean): void;
shared: SharedArrayBuffer;
evalContext(
code: string,
scriptName?: string,
): [unknown, EvalErrorInfo | null];
formatError: (e: Error) => string;
/**
* Get promise details as two elements array.
*
* First element is the `PromiseState`.
* If promise isn't pending, second element would be the result of the promise.
* Otherwise, second element would be undefined.
*
* Throws `TypeError` if argument isn't a promise
*
*/
getPromiseDetails<T>(promise: Promise<T>): promiseTypes.PromiseDetails<T>;
decode(bytes: Uint8Array): string;
encode(text: string): Uint8Array;
}
// Only `var` variables show up in the `globalThis` type when doing a global
// scope augmentation.
/* eslint-disable no-var */
// Assigned to `window` global - main runtime
var Deno: {
core: DenoCore;
noColor: boolean;
};
var onload: ((e: Event) => void) | undefined;
var onunload: ((e: Event) => void) | undefined;
// These methods are used to prepare different runtime
// environments. After bootrapping, this namespace
// should be removed from global scope.
var bootstrap: {
mainRuntime: (() => void) | undefined;
// Assigned to `self` global - worker runtime and compiler
workerRuntime: ((name: string) => Promise<void> | void) | undefined;
// Assigned to `self` global - compiler
tsCompilerRuntime: (() => void) | undefined;
};
var onerror:
| ((
msg: string,
source: string,
lineno: number,
colno: number,
e: Event,
) => boolean | void)
| undefined;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
var onmessage: ((e: { data: any }) => Promise<void> | void) | undefined;
// Called in compiler
var close: () => void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
var postMessage: (msg: any) => void;
/* eslint-enable */
}
export function writable(value: unknown): PropertyDescriptor {
return {
value,
writable: true,
enumerable: true,
configurable: true,
};
}
export function nonEnumerable(value: unknown): PropertyDescriptor {
return {
value,
writable: true,
configurable: true,
};
}
export function readOnly(value: unknown): PropertyDescriptor {
return {
value,
enumerable: true,
};
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function getterOnly(getter: () => any): PropertyDescriptor {
return {
get: getter,
enumerable: true,
};
}
// https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope
export const windowOrWorkerGlobalScopeMethods = {
atob: writable(textEncoding.atob),
btoa: writable(textEncoding.btoa),
clearInterval: writable(timers.clearInterval),
clearTimeout: writable(timers.clearTimeout),
fetch: writable(fetchTypes.fetch),
// queueMicrotask is bound in Rust
setInterval: writable(timers.setInterval),
setTimeout: writable(timers.setTimeout),
};
// Other properties shared between WindowScope and WorkerGlobalScope
export const windowOrWorkerGlobalScopeProperties = {
console: writable(new consoleTypes.Console(core.print)),
AbortController: nonEnumerable(abortController.AbortControllerImpl),
AbortSignal: nonEnumerable(abortSignal.AbortSignalImpl),
Blob: nonEnumerable(blob.DenoBlob),
ByteLengthQueuingStrategy: nonEnumerable(
queuingStrategy.ByteLengthQueuingStrategyImpl,
),
CountQueuingStrategy: nonEnumerable(queuingStrategy.CountQueuingStrategyImpl),
crypto: readOnly(csprng),
File: nonEnumerable(domFile.DomFileImpl),
CustomEvent: nonEnumerable(customEvent.CustomEventImpl),
DOMException: nonEnumerable(domException.DOMExceptionImpl),
ErrorEvent: nonEnumerable(errorEvent.ErrorEventImpl),
Event: nonEnumerable(event.EventImpl),
EventTarget: nonEnumerable(eventTarget.EventTargetImpl),
Headers: nonEnumerable(headers.HeadersImpl),
FormData: nonEnumerable(formData.FormDataImpl),
ReadableStream: nonEnumerable(readableStream.ReadableStreamImpl),
Request: nonEnumerable(request.Request),
Response: nonEnumerable(fetchTypes.Response),
performance: writable(new performance.PerformanceImpl()),
Performance: nonEnumerable(performance.PerformanceImpl),
PerformanceEntry: nonEnumerable(performance.PerformanceEntryImpl),
PerformanceMark: nonEnumerable(performance.PerformanceMarkImpl),
PerformanceMeasure: nonEnumerable(performance.PerformanceMeasureImpl),
TextDecoder: nonEnumerable(textEncoding.TextDecoder),
TextEncoder: nonEnumerable(textEncoding.TextEncoder),
TransformStream: nonEnumerable(transformStream.TransformStreamImpl),
URL: nonEnumerable(url.URLImpl),
URLSearchParams: nonEnumerable(urlSearchParams.URLSearchParamsImpl),
Worker: nonEnumerable(workers.WorkerImpl),
WritableStream: nonEnumerable(writableStream.WritableStreamImpl),
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function setEventTargetData(value: any): void {
eventTarget.eventTargetData.set(value, eventTarget.getDefaultTargetData());
}
export const eventTargetProperties = {
addEventListener: readOnly(
eventTarget.EventTargetImpl.prototype.addEventListener,
),
dispatchEvent: readOnly(eventTarget.EventTargetImpl.prototype.dispatchEvent),
removeEventListener: readOnly(
eventTarget.EventTargetImpl.prototype.removeEventListener,
),
};

View file

@ -1,5 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
export const unstableMethods = {};
export const unstableProperties = {};

View file

@ -1,17 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
export const internalSymbol = Symbol("Deno.internal");
// The object where all the internal fields for testing will be living.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const internalObject: Record<string, any> = {};
// Register a field to internalObject for test access,
// through Deno[Deno.internal][name].
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function exposeForTest(name: string, value: any): void {
Object.defineProperty(internalObject, name, {
value,
enumerable: false,
});
}

View file

@ -1,113 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// Interfaces 100% copied from Go.
// Documentation liberally lifted from them too.
// Thank you! We love Go! <3
const DEFAULT_BUFFER_SIZE = 32 * 1024;
// Seek whence values.
// https://golang.org/pkg/io/#pkg-constants
export enum SeekMode {
Start = 0,
Current = 1,
End = 2,
}
// Reader is the interface that wraps the basic read() method.
// https://golang.org/pkg/io/#Reader
export interface Reader {
read(p: Uint8Array): Promise<number | null>;
}
export interface ReaderSync {
readSync(p: Uint8Array): number | null;
}
// Writer is the interface that wraps the basic write() method.
// https://golang.org/pkg/io/#Writer
export interface Writer {
write(p: Uint8Array): Promise<number>;
}
export interface WriterSync {
writeSync(p: Uint8Array): number;
}
// https://golang.org/pkg/io/#Closer
export interface Closer {
// The behavior of Close after the first call is undefined. Specific
// implementations may document their own behavior.
close(): void;
}
// https://golang.org/pkg/io/#Seeker
export interface Seeker {
seek(offset: number, whence: SeekMode): Promise<number>;
}
export interface SeekerSync {
seekSync(offset: number, whence: SeekMode): number;
}
export async function copy(
src: Reader,
dst: Writer,
options?: {
bufSize?: number;
},
): Promise<number> {
let n = 0;
const bufSize = options?.bufSize ?? DEFAULT_BUFFER_SIZE;
const b = new Uint8Array(bufSize);
let gotEOF = false;
while (gotEOF === false) {
const result = await src.read(b);
if (result === null) {
gotEOF = true;
} else {
let nwritten = 0;
while (nwritten < result) {
nwritten += await dst.write(b.subarray(nwritten, result));
}
n += nwritten;
}
}
return n;
}
export async function* iter(
r: Reader,
options?: {
bufSize?: number;
},
): AsyncIterableIterator<Uint8Array> {
const bufSize = options?.bufSize ?? DEFAULT_BUFFER_SIZE;
const b = new Uint8Array(bufSize);
while (true) {
const result = await r.read(b);
if (result === null) {
break;
}
yield b.subarray(0, result);
}
}
export function* iterSync(
r: ReaderSync,
options?: {
bufSize?: number;
},
): IterableIterator<Uint8Array> {
const bufSize = options?.bufSize ?? DEFAULT_BUFFER_SIZE;
const b = new Uint8Array(bufSize);
while (true) {
const result = r.readSync(b);
if (result === null) {
break;
}
yield b.subarray(0, result);
}
}

View file

@ -1,21 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { bootstrapMainRuntime } from "./runtime_main.ts";
import { bootstrapWorkerRuntime } from "./runtime_worker.ts";
// Removes the `__proto__` for security reasons. This intentionally makes
// Deno non compliant with ECMA-262 Annex B.2.2.1
//
// eslint-disable-next-line @typescript-eslint/no-explicit-any
delete (Object.prototype as any).__proto__;
Object.defineProperties(globalThis, {
bootstrap: {
value: {
mainRuntime: bootstrapMainRuntime,
workerRuntime: bootstrapWorkerRuntime,
},
configurable: true,
writable: true,
},
});

View file

@ -1,192 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { errors } from "./errors.ts";
import type { Reader, Writer, Closer } from "./io.ts";
import { read, write } from "./ops/io.ts";
import { close } from "./ops/resources.ts";
import * as netOps from "./ops/net.ts";
import type { Addr } from "./ops/net.ts";
export type { ShutdownMode, NetAddr, UnixAddr } from "./ops/net.ts";
export { shutdown } from "./ops/net.ts";
export interface DatagramConn extends AsyncIterable<[Uint8Array, Addr]> {
receive(p?: Uint8Array): Promise<[Uint8Array, Addr]>;
send(p: Uint8Array, addr: Addr): Promise<number>;
close(): void;
addr: Addr;
[Symbol.asyncIterator](): AsyncIterableIterator<[Uint8Array, Addr]>;
}
export interface Listener extends AsyncIterable<Conn> {
accept(): Promise<Conn>;
close(): void;
addr: Addr;
rid: number;
[Symbol.asyncIterator](): AsyncIterableIterator<Conn>;
}
export class ConnImpl implements Conn {
constructor(
readonly rid: number,
readonly remoteAddr: Addr,
readonly localAddr: Addr,
) {}
write(p: Uint8Array): Promise<number> {
return write(this.rid, p);
}
read(p: Uint8Array): Promise<number | null> {
return read(this.rid, p);
}
close(): void {
close(this.rid);
}
// TODO(lucacasonato): make this unavailable in stable
closeWrite(): void {
netOps.shutdown(this.rid, netOps.ShutdownMode.Write);
}
}
export class ListenerImpl implements Listener {
constructor(readonly rid: number, readonly addr: Addr) {}
async accept(): Promise<Conn> {
const res = await netOps.accept(this.rid, this.addr.transport);
return new ConnImpl(res.rid, res.remoteAddr, res.localAddr);
}
async next(): Promise<IteratorResult<Conn>> {
let conn: Conn;
try {
conn = await this.accept();
} catch (error) {
if (error instanceof errors.BadResource) {
return { value: undefined, done: true };
}
throw error;
}
return { value: conn!, done: false };
}
return(value?: Conn): Promise<IteratorResult<Conn>> {
this.close();
return Promise.resolve({ value, done: true });
}
close(): void {
close(this.rid);
}
[Symbol.asyncIterator](): AsyncIterableIterator<Conn> {
return this;
}
}
export class DatagramImpl implements DatagramConn {
constructor(
readonly rid: number,
readonly addr: Addr,
public bufSize: number = 1024,
) {}
async receive(p?: Uint8Array): Promise<[Uint8Array, Addr]> {
const buf = p || new Uint8Array(this.bufSize);
const { size, remoteAddr } = await netOps.receive(
this.rid,
this.addr.transport,
buf,
);
const sub = buf.subarray(0, size);
return [sub, remoteAddr];
}
send(p: Uint8Array, addr: Addr): Promise<number> {
const remote = { hostname: "127.0.0.1", ...addr };
const args = { ...remote, rid: this.rid };
return netOps.send(args as netOps.SendRequest, p);
}
close(): void {
close(this.rid);
}
async *[Symbol.asyncIterator](): AsyncIterableIterator<[Uint8Array, Addr]> {
while (true) {
try {
yield await this.receive();
} catch (err) {
if (err instanceof errors.BadResource) {
break;
}
throw err;
}
}
}
}
export interface Conn extends Reader, Writer, Closer {
localAddr: Addr;
remoteAddr: Addr;
rid: number;
closeWrite(): void;
}
export interface ListenOptions {
port: number;
hostname?: string;
transport?: "tcp";
}
export function listen(
options: ListenOptions & { transport?: "tcp" },
): Listener;
export function listen(options: ListenOptions): Listener {
const res = netOps.listen({
transport: "tcp",
hostname: "0.0.0.0",
...(options as ListenOptions),
});
return new ListenerImpl(res.rid, res.localAddr);
}
export interface ConnectOptions {
port: number;
hostname?: string;
transport?: "tcp";
}
export interface UnixConnectOptions {
transport: "unix";
path: string;
}
export async function connect(options: UnixConnectOptions): Promise<Conn>;
export async function connect(options: ConnectOptions): Promise<Conn>;
export async function connect(
options: ConnectOptions | UnixConnectOptions,
): Promise<Conn> {
let res;
if (options.transport === "unix") {
res = await netOps.connect(options);
} else {
res = await netOps.connect({
transport: "tcp",
hostname: "127.0.0.1",
...options,
});
}
return new ConnImpl(res.rid, res.remoteAddr!, res.localAddr!);
}

View file

@ -1,79 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import * as netOps from "./ops/net.ts";
import {
Listener,
DatagramConn,
ListenerImpl,
DatagramImpl,
ConnectOptions,
Conn,
ConnImpl,
listen as stableListen,
connect as stableConnect,
} from "./net.ts";
export interface ListenOptions {
port: number;
hostname?: string;
transport?: "tcp" | "udp";
}
export interface UnixListenOptions {
transport: "unix" | "unixpacket";
path: string;
}
export interface UnixConnectOptions {
transport: "unix";
path: string;
}
export function listen(
options: ListenOptions & { transport?: "tcp" },
): Listener;
export function listen(
options: UnixListenOptions & { transport: "unix" },
): Listener;
export function listen(options: ListenOptions | UnixListenOptions): Listener {
if (options.transport === "unix") {
const res = netOps.listen(options);
return new ListenerImpl(res.rid, res.localAddr);
} else {
return stableListen(options as ListenOptions & { transport?: "tcp" });
}
}
export function listenDatagram(
options: ListenOptions & { transport: "udp" },
): DatagramConn;
export function listenDatagram(
options: UnixListenOptions & { transport: "unixpacket" },
): DatagramConn;
export function listenDatagram(
options: ListenOptions | UnixListenOptions,
): DatagramConn {
let res;
if (options.transport === "unixpacket") {
res = netOps.listen(options);
} else {
res = netOps.listen({
transport: "udp",
hostname: "127.0.0.1",
...(options as ListenOptions),
});
}
return new DatagramImpl(res.rid, res.localAddr);
}
export async function connect(
options: ConnectOptions | UnixConnectOptions,
): Promise<Conn> {
if (options.transport === "unix") {
const res = await netOps.connect(options);
return new ConnImpl(res.rid, res.remoteAddr!, res.localAddr!);
} else {
return stableConnect(options as ConnectOptions);
}
}

View file

@ -1,94 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import * as util from "../util.ts";
import { core } from "../core.ts";
import { ErrorKind, getErrorClass } from "../errors.ts";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type Ok = any;
interface JsonError {
kind: ErrorKind;
message: string;
}
interface JsonResponse {
ok?: Ok;
err?: JsonError;
promiseId?: number; // Only present in async messages.
}
// Using an object without a prototype because `Map` was causing GC problems.
const promiseTable: Record<
number,
util.Resolvable<JsonResponse>
> = Object.create(null);
let _nextPromiseId = 1;
function nextPromiseId(): number {
return _nextPromiseId++;
}
function decode(ui8: Uint8Array): JsonResponse {
return JSON.parse(core.decode(ui8));
}
function encode(args: object): Uint8Array {
return core.encode(JSON.stringify(args));
}
function unwrapResponse(res: JsonResponse): Ok {
if (res.err != null) {
throw new (getErrorClass(res.err.kind))(res.err.message);
}
util.assert(res.ok != null);
return res.ok;
}
export function asyncMsgFromRust(resUi8: Uint8Array): void {
const res = decode(resUi8);
util.assert(res.promiseId != null);
const promise = promiseTable[res.promiseId!];
util.assert(promise != null);
delete promiseTable[res.promiseId!];
promise.resolve(res);
}
export function sendSync(
opName: string,
args: object = {},
...zeroCopy: Uint8Array[]
): Ok {
util.log("sendSync", opName);
const argsUi8 = encode(args);
const resUi8 = core.dispatchByName(opName, argsUi8, ...zeroCopy);
util.assert(resUi8 != null);
const res = decode(resUi8);
util.assert(res.promiseId == null);
return unwrapResponse(res);
}
export async function sendAsync(
opName: string,
args: object = {},
...zeroCopy: Uint8Array[]
): Promise<Ok> {
util.log("sendAsync", opName);
const promiseId = nextPromiseId();
args = Object.assign(args, { promiseId });
const promise = util.createResolvable<Ok>();
const argsUi8 = encode(args);
const buf = core.dispatchByName(opName, argsUi8, ...zeroCopy);
if (buf != null) {
// Sync result.
const res = decode(buf);
promise.resolve(res);
} else {
// Async result.
promiseTable[promiseId] = promise;
}
const res = await promise;
return unwrapResponse(res);
}

View file

@ -1,121 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import * as util from "../util.ts";
import { core } from "../core.ts";
import { TextDecoder } from "../web/text_encoding.ts";
import { ErrorKind, errors, getErrorClass } from "../errors.ts";
// Using an object without a prototype because `Map` was causing GC problems.
const promiseTableMin: Record<
number,
util.Resolvable<RecordMinimal>
> = Object.create(null);
// Note it's important that promiseId starts at 1 instead of 0, because sync
// messages are indicated with promiseId 0. If we ever add wrap around logic for
// overflows, this should be taken into account.
let _nextPromiseId = 1;
const decoder = new TextDecoder();
function nextPromiseId(): number {
return _nextPromiseId++;
}
export interface RecordMinimal {
promiseId: number;
arg: number;
result: number;
err?: {
kind: ErrorKind;
message: string;
};
}
export function recordFromBufMinimal(ui8: Uint8Array): RecordMinimal {
const header = ui8.subarray(0, 12);
const buf32 = new Int32Array(
header.buffer,
header.byteOffset,
header.byteLength / 4,
);
const promiseId = buf32[0];
const arg = buf32[1];
const result = buf32[2];
let err;
if (arg < 0) {
const kind = result as ErrorKind;
const message = decoder.decode(ui8.subarray(12));
err = { kind, message };
} else if (ui8.length != 12) {
throw new errors.InvalidData("BadMessage");
}
return {
promiseId,
arg,
result,
err,
};
}
function unwrapResponse(res: RecordMinimal): number {
if (res.err != null) {
throw new (getErrorClass(res.err.kind))(res.err.message);
}
return res.result;
}
const scratch32 = new Int32Array(3);
const scratchBytes = new Uint8Array(
scratch32.buffer,
scratch32.byteOffset,
scratch32.byteLength,
);
util.assert(scratchBytes.byteLength === scratch32.length * 4);
export function asyncMsgFromRust(ui8: Uint8Array): void {
const record = recordFromBufMinimal(ui8);
const { promiseId } = record;
const promise = promiseTableMin[promiseId];
delete promiseTableMin[promiseId];
util.assert(promise);
promise.resolve(record);
}
export async function sendAsyncMinimal(
opName: string,
arg: number,
zeroCopy: Uint8Array,
): Promise<number> {
const promiseId = nextPromiseId(); // AKA cmdId
scratch32[0] = promiseId;
scratch32[1] = arg;
scratch32[2] = 0; // result
const promise = util.createResolvable<RecordMinimal>();
const buf = core.dispatchByName(opName, scratchBytes, zeroCopy);
if (buf != null) {
const record = recordFromBufMinimal(buf);
// Sync result.
promise.resolve(record);
} else {
// Async result.
promiseTableMin[promiseId] = promise;
}
const res = await promise;
return unwrapResponse(res);
}
export function sendSyncMinimal(
opName: string,
arg: number,
zeroCopy: Uint8Array,
): number {
scratch32[0] = 0; // promiseId 0 indicates sync
scratch32[1] = arg;
const res = core.dispatchByName(opName, scratchBytes, zeroCopy)!;
const resRecord = recordFromBufMinimal(res);
return unwrapResponse(resRecord);
}

View file

@ -1,23 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import type { DiagnosticItem } from "../diagnostics.ts";
import { sendSync } from "./dispatch_json.ts";
export function formatDiagnostics(items: DiagnosticItem[]): string {
return sendSync("op_format_diagnostic", { items });
}
export interface Location {
fileName: string;
lineNumber: number;
columnNumber: number;
}
export function applySourceMap(location: Location): Location {
const res = sendSync("op_apply_source_map", location);
return {
fileName: res.fileName,
lineNumber: res.lineNumber,
columnNumber: res.columnNumber,
};
}

View file

@ -1,28 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendAsync } from "./dispatch_json.ts";
interface FetchRequest {
url: string;
method: string | null;
headers: Array<[string, string]>;
}
export interface FetchResponse {
bodyRid: number;
status: number;
statusText: string;
headers: Array<[string, string]>;
}
export function fetch(
args: FetchRequest,
body?: ArrayBufferView,
): Promise<FetchResponse> {
let zeroCopy;
if (body != null) {
zeroCopy = new Uint8Array(body.buffer, body.byteOffset, body.byteLength);
}
return sendAsync("op_fetch", args, ...(zeroCopy ? [zeroCopy] : []));
}

View file

@ -1,12 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "../dispatch_json.ts";
import { pathFromURL } from "../../util.ts";
export function chmodSync(path: string | URL, mode: number): void {
sendSync("op_chmod", { path: pathFromURL(path), mode });
}
export async function chmod(path: string | URL, mode: number): Promise<void> {
await sendAsync("op_chmod", { path: pathFromURL(path), mode });
}

View file

@ -1,20 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "../dispatch_json.ts";
import { pathFromURL } from "../../util.ts";
export function chownSync(
path: string | URL,
uid: number | null,
gid: number | null,
): void {
sendSync("op_chown", { path: pathFromURL(path), uid, gid });
}
export async function chown(
path: string | URL,
uid: number | null,
gid: number | null,
): Promise<void> {
await sendAsync("op_chown", { path: pathFromURL(path), uid, gid });
}

View file

@ -1,24 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "../dispatch_json.ts";
import { pathFromURL } from "../../util.ts";
export function copyFileSync(
fromPath: string | URL,
toPath: string | URL,
): void {
sendSync("op_copy_file", {
from: pathFromURL(fromPath),
to: pathFromURL(toPath),
});
}
export async function copyFile(
fromPath: string | URL,
toPath: string | URL,
): Promise<void> {
await sendAsync("op_copy_file", {
from: pathFromURL(fromPath),
to: pathFromURL(toPath),
});
}

View file

@ -1,11 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync } from "../dispatch_json.ts";
export function cwd(): string {
return sendSync("op_cwd");
}
export function chdir(directory: string): void {
sendSync("op_chdir", { directory });
}

View file

@ -1,11 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "../dispatch_json.ts";
export function linkSync(oldpath: string, newpath: string): void {
sendSync("op_link", { oldpath, newpath });
}
export async function link(oldpath: string, newpath: string): Promise<void> {
await sendAsync("op_link", { oldpath, newpath });
}

View file

@ -1,25 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "../dispatch_json.ts";
export interface MakeTempOptions {
dir?: string;
prefix?: string;
suffix?: string;
}
export function makeTempDirSync(options: MakeTempOptions = {}): string {
return sendSync("op_make_temp_dir", options);
}
export function makeTempDir(options: MakeTempOptions = {}): Promise<string> {
return sendAsync("op_make_temp_dir", options);
}
export function makeTempFileSync(options: MakeTempOptions = {}): string {
return sendSync("op_make_temp_file", options);
}
export function makeTempFile(options: MakeTempOptions = {}): Promise<string> {
return sendAsync("op_make_temp_file", options);
}

View file

@ -1,38 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "../dispatch_json.ts";
export interface MkdirOptions {
recursive?: boolean;
mode?: number;
}
interface MkdirArgs {
path: string;
recursive: boolean;
mode?: number;
}
function mkdirArgs(path: string, options?: MkdirOptions): MkdirArgs {
const args: MkdirArgs = { path, recursive: false };
if (options != null) {
if (typeof options.recursive == "boolean") {
args.recursive = options.recursive;
}
if (options.mode) {
args.mode = options.mode;
}
}
return args;
}
export function mkdirSync(path: string, options?: MkdirOptions): void {
sendSync("op_mkdir", mkdirArgs(path, options));
}
export async function mkdir(
path: string,
options?: MkdirOptions,
): Promise<void> {
await sendAsync("op_mkdir", mkdirArgs(path, options));
}

View file

@ -1,31 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "../dispatch_json.ts";
import { pathFromURL } from "../../util.ts";
export interface OpenOptions {
read?: boolean;
write?: boolean;
append?: boolean;
truncate?: boolean;
create?: boolean;
createNew?: boolean;
/** Permissions to use if creating the file (defaults to `0o666`, before
* the process's umask).
* It's an error to specify mode without also setting create or createNew to `true`.
* Ignored on Windows. */
mode?: number;
}
export function openSync(path: string | URL, options: OpenOptions): number {
const mode: number | undefined = options?.mode;
return sendSync("op_open", { path: pathFromURL(path), options, mode });
}
export function open(
path: string | URL,
options: OpenOptions,
): Promise<number> {
const mode: number | undefined = options?.mode;
return sendAsync("op_open", { path: pathFromURL(path), options, mode });
}

View file

@ -1,34 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "../dispatch_json.ts";
import { pathFromURL } from "../../util.ts";
export interface DirEntry {
name: string;
isFile: boolean;
isDirectory: boolean;
isSymlink: boolean;
}
interface ReadDirResponse {
entries: DirEntry[];
}
function res(response: ReadDirResponse): DirEntry[] {
return response.entries;
}
export function readDirSync(path: string | URL): Iterable<DirEntry> {
return res(sendSync("op_read_dir", { path: pathFromURL(path) }))[
Symbol.iterator
]();
}
export function readDir(path: string | URL): AsyncIterable<DirEntry> {
const array = sendAsync("op_read_dir", { path: pathFromURL(path) }).then(res);
return {
async *[Symbol.asyncIterator](): AsyncIterableIterator<DirEntry> {
yield* await array;
},
};
}

View file

@ -1,11 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "../dispatch_json.ts";
export function readLinkSync(path: string): string {
return sendSync("op_read_link", { path });
}
export function readLink(path: string): Promise<string> {
return sendAsync("op_read_link", { path });
}

View file

@ -1,11 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "../dispatch_json.ts";
export function realPathSync(path: string): string {
return sendSync("op_realpath", { path });
}
export function realPath(path: string): Promise<string> {
return sendAsync("op_realpath", { path });
}

View file

@ -1,28 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "../dispatch_json.ts";
import { pathFromURL } from "../../util.ts";
export interface RemoveOptions {
recursive?: boolean;
}
export function removeSync(
path: string | URL,
options: RemoveOptions = {},
): void {
sendSync("op_remove", {
path: pathFromURL(path),
recursive: !!options.recursive,
});
}
export async function remove(
path: string | URL,
options: RemoveOptions = {},
): Promise<void> {
await sendAsync("op_remove", {
path: pathFromURL(path),
recursive: !!options.recursive,
});
}

View file

@ -1,11 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "../dispatch_json.ts";
export function renameSync(oldpath: string, newpath: string): void {
sendSync("op_rename", { oldpath, newpath });
}
export async function rename(oldpath: string, newpath: string): Promise<void> {
await sendAsync("op_rename", { oldpath, newpath });
}

View file

@ -1,20 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "../dispatch_json.ts";
import type { SeekMode } from "../../io.ts";
export function seekSync(
rid: number,
offset: number,
whence: SeekMode,
): number {
return sendSync("op_seek", { rid, offset, whence });
}
export function seek(
rid: number,
offset: number,
whence: SeekMode,
): Promise<number> {
return sendAsync("op_seek", { rid, offset, whence });
}

View file

@ -1,108 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "../dispatch_json.ts";
import { build } from "../../build.ts";
import { pathFromURL } from "../../util.ts";
export interface FileInfo {
size: number;
mtime: Date | null;
atime: Date | null;
birthtime: Date | null;
dev: number | null;
ino: number | null;
mode: number | null;
nlink: number | null;
uid: number | null;
gid: number | null;
rdev: number | null;
blksize: number | null;
blocks: number | null;
isFile: boolean;
isDirectory: boolean;
isSymlink: boolean;
}
export interface StatResponse {
isFile: boolean;
isDirectory: boolean;
isSymlink: boolean;
size: number;
mtime: number | null;
atime: number | null;
birthtime: number | null;
// Unix only members
dev: number;
ino: number;
mode: number;
nlink: number;
uid: number;
gid: number;
rdev: number;
blksize: number;
blocks: number;
}
// @internal
export function parseFileInfo(response: StatResponse): FileInfo {
const unix = build.os === "darwin" || build.os === "linux";
return {
isFile: response.isFile,
isDirectory: response.isDirectory,
isSymlink: response.isSymlink,
size: response.size,
mtime: response.mtime != null ? new Date(response.mtime) : null,
atime: response.atime != null ? new Date(response.atime) : null,
birthtime: response.birthtime != null ? new Date(response.birthtime) : null,
// Only non-null if on Unix
dev: unix ? response.dev : null,
ino: unix ? response.ino : null,
mode: unix ? response.mode : null,
nlink: unix ? response.nlink : null,
uid: unix ? response.uid : null,
gid: unix ? response.gid : null,
rdev: unix ? response.rdev : null,
blksize: unix ? response.blksize : null,
blocks: unix ? response.blocks : null,
};
}
export function fstatSync(rid: number): FileInfo {
return parseFileInfo(sendSync("op_fstat", { rid }));
}
export async function fstat(rid: number): Promise<FileInfo> {
return parseFileInfo(await sendAsync("op_fstat", { rid }));
}
export async function lstat(path: string | URL): Promise<FileInfo> {
const res = await sendAsync("op_stat", {
path: pathFromURL(path),
lstat: true,
});
return parseFileInfo(res);
}
export function lstatSync(path: string | URL): FileInfo {
const res = sendSync("op_stat", {
path: pathFromURL(path),
lstat: true,
});
return parseFileInfo(res);
}
export async function stat(path: string | URL): Promise<FileInfo> {
const res = await sendAsync("op_stat", {
path: pathFromURL(path),
lstat: false,
});
return parseFileInfo(res);
}
export function statSync(path: string | URL): FileInfo {
const res = sendSync("op_stat", {
path: pathFromURL(path),
lstat: false,
});
return parseFileInfo(res);
}

View file

@ -1,23 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "../dispatch_json.ts";
export interface SymlinkOptions {
type: "file" | "dir";
}
export function symlinkSync(
oldpath: string,
newpath: string,
options?: SymlinkOptions,
): void {
sendSync("op_symlink", { oldpath, newpath, options });
}
export async function symlink(
oldpath: string,
newpath: string,
options?: SymlinkOptions,
): Promise<void> {
await sendAsync("op_symlink", { oldpath, newpath, options });
}

View file

@ -1,19 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "../dispatch_json.ts";
export function fdatasyncSync(rid: number): void {
sendSync("op_fdatasync", { rid });
}
export async function fdatasync(rid: number): Promise<void> {
await sendAsync("op_fdatasync", { rid });
}
export function fsyncSync(rid: number): void {
sendSync("op_fsync", { rid });
}
export async function fsync(rid: number): Promise<void> {
await sendAsync("op_fsync", { rid });
}

View file

@ -1,27 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "../dispatch_json.ts";
function coerceLen(len?: number): number {
if (len == null || len < 0) {
return 0;
}
return len;
}
export function ftruncateSync(rid: number, len?: number): void {
sendSync("op_ftruncate", { rid, len: coerceLen(len) });
}
export async function ftruncate(rid: number, len?: number): Promise<void> {
await sendAsync("op_ftruncate", { rid, len: coerceLen(len) });
}
export function truncateSync(path: string, len?: number): void {
sendSync("op_truncate", { path, len: coerceLen(len) });
}
export async function truncate(path: string, len?: number): Promise<void> {
await sendAsync("op_truncate", { path, len: coerceLen(len) });
}

View file

@ -1,7 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync } from "../dispatch_json.ts";
export function umask(mask?: number): number {
return sendSync("op_umask", { mask });
}

View file

@ -1,33 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "../dispatch_json.ts";
function toSecondsFromEpoch(v: number | Date): number {
return v instanceof Date ? Math.trunc(v.valueOf() / 1000) : v;
}
export function utimeSync(
path: string,
atime: number | Date,
mtime: number | Date,
): void {
sendSync("op_utime", {
path,
// TODO(ry) split atime, mtime into [seconds, nanoseconds] tuple
atime: toSecondsFromEpoch(atime),
mtime: toSecondsFromEpoch(mtime),
});
}
export async function utime(
path: string,
atime: number | Date,
mtime: number | Date,
): Promise<void> {
await sendAsync("op_utime", {
path,
// TODO(ry) split atime, mtime into [seconds, nanoseconds] tuple
atime: toSecondsFromEpoch(atime),
mtime: toSecondsFromEpoch(mtime),
});
}

View file

@ -1,44 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "./dispatch_json.ts";
import { close } from "./resources.ts";
export interface FsEvent {
kind: "any" | "access" | "create" | "modify" | "remove";
paths: string[];
}
interface FsWatcherOptions {
recursive: boolean;
}
class FsWatcher implements AsyncIterableIterator<FsEvent> {
readonly rid: number;
constructor(paths: string[], options: FsWatcherOptions) {
const { recursive } = options;
this.rid = sendSync("op_fs_events_open", { recursive, paths });
}
next(): Promise<IteratorResult<FsEvent>> {
return sendAsync("op_fs_events_poll", {
rid: this.rid,
});
}
return(value?: FsEvent): Promise<IteratorResult<FsEvent>> {
close(this.rid);
return Promise.resolve({ value, done: true });
}
[Symbol.asyncIterator](): AsyncIterableIterator<FsEvent> {
return this;
}
}
export function watchFs(
paths: string | string[],
options: FsWatcherOptions = { recursive: true },
): AsyncIterableIterator<FsEvent> {
return new FsWatcher(Array.isArray(paths) ? paths : [paths], options);
}

View file

@ -1,25 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync } from "./dispatch_json.ts";
import { assert } from "../util.ts";
export function getRandomValues<
T extends
| Int8Array
| Uint8Array
| Uint8ClampedArray
| Int16Array
| Uint16Array
| Int32Array
| Uint32Array,
>(typedArray: T): T {
assert(typedArray !== null, "Input must not be null");
assert(typedArray.length <= 65536, "Input must not be longer than 65536");
const ui8 = new Uint8Array(
typedArray.buffer,
typedArray.byteOffset,
typedArray.byteLength,
);
sendSync("op_get_random_values", {}, ui8);
return typedArray;
}

View file

@ -1,12 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
/** https://url.spec.whatwg.org/#idna */
import { sendSync } from "./dispatch_json.ts";
export function domainToAscii(
domain: string,
{ beStrict = false }: { beStrict?: boolean } = {},
): string {
return sendSync("op_domain_to_ascii", { domain, beStrict });
}

View file

@ -1,50 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendAsyncMinimal, sendSyncMinimal } from "./dispatch_minimal.ts";
export function readSync(rid: number, buffer: Uint8Array): number | null {
if (buffer.length === 0) {
return 0;
}
const nread = sendSyncMinimal("op_read", rid, buffer);
if (nread < 0) {
throw new Error("read error");
}
return nread === 0 ? null : nread;
}
export async function read(
rid: number,
buffer: Uint8Array,
): Promise<number | null> {
if (buffer.length === 0) {
return 0;
}
const nread = await sendAsyncMinimal("op_read", rid, buffer);
if (nread < 0) {
throw new Error("read error");
}
return nread === 0 ? null : nread;
}
export function writeSync(rid: number, data: Uint8Array): number {
const result = sendSyncMinimal("op_write", rid, data);
if (result < 0) {
throw new Error("write error");
}
return result;
}
export async function write(rid: number, data: Uint8Array): Promise<number> {
const result = await sendAsyncMinimal("op_write", rid, data);
if (result < 0) {
throw new Error("write error");
}
return result;
}

View file

@ -1,86 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "./dispatch_json.ts";
export interface NetAddr {
transport: "tcp" | "udp";
hostname: string;
port: number;
}
export interface UnixAddr {
transport: "unix" | "unixpacket";
path: string;
}
export type Addr = NetAddr | UnixAddr;
export enum ShutdownMode {
// See http://man7.org/linux/man-pages/man2/shutdown.2.html
// Corresponding to SHUT_RD, SHUT_WR, SHUT_RDWR
Read = 0,
Write = 1,
ReadWrite, // unused
}
export function shutdown(rid: number, how: ShutdownMode): Promise<void> {
sendSync("op_shutdown", { rid, how });
return Promise.resolve();
}
interface AcceptResponse {
rid: number;
localAddr: Addr;
remoteAddr: Addr;
}
export function accept(
rid: number,
transport: string,
): Promise<AcceptResponse> {
return sendAsync("op_accept", { rid, transport });
}
export type ListenRequest = Addr;
interface ListenResponse {
rid: number;
localAddr: Addr;
}
export function listen(args: ListenRequest): ListenResponse {
return sendSync("op_listen", args);
}
interface ConnectResponse {
rid: number;
localAddr: Addr;
remoteAddr: Addr;
}
export type ConnectRequest = Addr;
export function connect(args: ConnectRequest): Promise<ConnectResponse> {
return sendAsync("op_connect", args);
}
interface ReceiveResponse {
size: number;
remoteAddr: Addr;
}
export function receive(
rid: number,
transport: string,
zeroCopy: Uint8Array,
): Promise<ReceiveResponse> {
return sendAsync("op_datagram_receive", { rid, transport }, zeroCopy);
}
export type SendRequest = {
rid: number;
} & Addr;
export function send(args: SendRequest, zeroCopy: Uint8Array): Promise<number> {
return sendAsync("op_datagram_send", args, zeroCopy);
}

View file

@ -1,45 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync } from "./dispatch_json.ts";
export function loadavg(): number[] {
return sendSync("op_loadavg");
}
export function hostname(): string {
return sendSync("op_hostname");
}
export function osRelease(): string {
return sendSync("op_os_release");
}
export function exit(code = 0): never {
sendSync("op_exit", { code });
throw new Error("Code not reachable");
}
function setEnv(key: string, value: string): void {
sendSync("op_set_env", { key, value });
}
function getEnv(key: string): string | undefined {
return sendSync("op_get_env", { key })[0];
}
function deleteEnv(key: string): void {
sendSync("op_delete_env", { key });
}
export const env = {
get: getEnv,
toObject(): Record<string, string> {
return sendSync("op_env");
},
set: setEnv,
delete: deleteEnv,
};
export function execPath(): string {
return sendSync("op_exec_path");
}

View file

@ -1,22 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync } from "./dispatch_json.ts";
import type { PermissionState } from "../permissions.ts";
interface PermissionRequest {
name: string;
url?: string;
path?: string;
}
export function query(desc: PermissionRequest): PermissionState {
return sendSync("op_query_permission", desc).state;
}
export function revoke(desc: PermissionRequest): PermissionState {
return sendSync("op_revoke_permission", desc).state;
}
export function request(desc: PermissionRequest): PermissionState {
return sendSync("op_request_permission", desc).state;
}

View file

@ -1,7 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync } from "./dispatch_json.ts";
export function openPlugin(filename: string): number {
return sendSync("op_open_plugin", { filename });
}

View file

@ -1,43 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "./dispatch_json.ts";
import { assert } from "../util.ts";
export function kill(pid: number, signo: number): void {
sendSync("op_kill", { pid, signo });
}
interface RunStatusResponse {
gotSignal: boolean;
exitCode: number;
exitSignal: number;
}
export function runStatus(rid: number): Promise<RunStatusResponse> {
return sendAsync("op_run_status", { rid });
}
interface RunRequest {
cmd: string[];
cwd?: string;
env?: Array<[string, string]>;
stdin: string;
stdout: string;
stderr: string;
stdinRid: number;
stdoutRid: number;
stderrRid: number;
}
interface RunResponse {
rid: number;
pid: number;
stdinRid: number | null;
stdoutRid: number | null;
stderrRid: number | null;
}
export function run(request: RunRequest): RunResponse {
assert(request.cmd.length > 0);
return sendSync("op_run", request);
}

View file

@ -1,11 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "./dispatch_json.ts";
export function startRepl(historyFile: string): number {
return sendSync("op_repl_start", { historyFile });
}
export function readline(rid: number, prompt: string): Promise<string> {
return sendAsync("op_repl_readline", { rid, prompt });
}

View file

@ -1,18 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync } from "./dispatch_json.ts";
export type ResourceMap = Record<number, string>;
export function resources(): ResourceMap {
const res = sendSync("op_resources") as Array<[number, string]>;
const resources: ResourceMap = {};
for (const resourceTuple of res) {
resources[resourceTuple[0]] = resourceTuple[1];
}
return resources;
}
export function close(rid: number): void {
sendSync("op_close", { rid });
}

View file

@ -1,45 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync } from "./dispatch_json.ts";
export interface Start {
args: string[];
cwd: string;
debugFlag: boolean;
denoVersion: string;
noColor: boolean;
pid: number;
ppid: number;
repl: boolean;
target: string;
tsVersion: string;
unstableFlag: boolean;
v8Version: string;
versionFlag: boolean;
}
export function opStart(): Start {
return sendSync("op_start");
}
export function opMainModule(): string {
return sendSync("op_main_module");
}
export interface Metrics {
opsDispatched: number;
opsDispatchedSync: number;
opsDispatchedAsync: number;
opsDispatchedAsyncUnref: number;
opsCompleted: number;
opsCompletedSync: number;
opsCompletedAsync: number;
opsCompletedAsyncUnref: number;
bytesSentControl: number;
bytesSentData: number;
bytesReceived: number;
}
export function metrics(): Metrics {
return sendSync("op_metrics");
}

View file

@ -1,37 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendAsync } from "./dispatch_json.ts";
import type { DiagnosticItem } from "../diagnostics.ts";
interface CompileRequest {
rootName: string;
sources?: Record<string, string>;
options?: string;
bundle: boolean;
}
interface CompileResponse {
diagnostics: DiagnosticItem[];
output?: string;
emitMap?: Record<string, Record<string, string>>;
}
export function compile(request: CompileRequest): Promise<CompileResponse> {
return sendAsync("op_compile", request);
}
interface TranspileRequest {
sources: Record<string, string>;
options?: string;
}
export interface TranspileOnlyResult {
source: string;
map?: string;
}
export function transpile(
request: TranspileRequest,
): Promise<Record<string, TranspileOnlyResult>> {
return sendAsync("op_transpile", request);
}

View file

@ -1,23 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "./dispatch_json.ts";
interface BindSignalResponse {
rid: number;
}
interface PollSignalResponse {
done: boolean;
}
export function bindSignal(signo: number): BindSignalResponse {
return sendSync("op_signal_bind", { signo });
}
export function pollSignal(rid: number): Promise<PollSignalResponse> {
return sendAsync("op_signal_poll", { rid });
}
export function unbindSignal(rid: number): void {
sendSync("op_signal_unbind", { rid });
}

View file

@ -1,20 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "./dispatch_json.ts";
interface NowResponse {
seconds: number;
subsecNanos: number;
}
export function stopGlobalTimer(): void {
sendSync("op_global_timer_stop");
}
export async function startGlobalTimer(timeout: number): Promise<void> {
await sendAsync("op_global_timer", { timeout });
}
export function now(): NowResponse {
return sendSync("op_now");
}

View file

@ -1,79 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendAsync, sendSync } from "./dispatch_json.ts";
export interface ConnectTLSRequest {
transport: "tcp";
hostname: string;
port: number;
certFile?: string;
}
interface EstablishTLSResponse {
rid: number;
localAddr: {
hostname: string;
port: number;
transport: "tcp";
};
remoteAddr: {
hostname: string;
port: number;
transport: "tcp";
};
}
export function connectTls(
args: ConnectTLSRequest,
): Promise<EstablishTLSResponse> {
return sendAsync("op_connect_tls", args);
}
interface AcceptTLSResponse {
rid: number;
localAddr: {
hostname: string;
port: number;
transport: "tcp";
};
remoteAddr: {
hostname: string;
port: number;
transport: "tcp";
};
}
export function acceptTLS(rid: number): Promise<AcceptTLSResponse> {
return sendAsync("op_accept_tls", { rid });
}
export interface ListenTLSRequest {
port: number;
hostname: string;
transport: "tcp";
certFile: string;
keyFile: string;
}
interface ListenTLSResponse {
rid: number;
localAddr: {
hostname: string;
port: number;
transport: "tcp";
};
}
export function listenTls(args: ListenTLSRequest): ListenTLSResponse {
return sendSync("op_listen_tls", args);
}
export interface StartTLSRequest {
rid: number;
hostname: string;
certFile?: string;
}
export function startTls(args: StartTLSRequest): Promise<EstablishTLSResponse> {
return sendAsync("op_start_tls", args);
}

View file

@ -1,15 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync } from "./dispatch_json.ts";
export function consoleSize(rid: number): [number, number] {
return sendSync("op_console_size", { rid });
}
export function isatty(rid: number): boolean {
return sendSync("op_isatty", { rid });
}
export function setRaw(rid: number, mode: boolean): void {
sendSync("op_set_raw", { rid, mode });
}

View file

@ -1,11 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync } from "./dispatch_json.ts";
export function postMessage(data: Uint8Array): void {
sendSync("op_worker_post_message", {}, data);
}
export function close(): void {
sendSync("op_worker_close");
}

View file

@ -1,36 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
/* eslint-disable @typescript-eslint/no-explicit-any */
import { sendAsync, sendSync } from "./dispatch_json.ts";
interface CreateWorkerResponse {
id: number;
}
export function createWorker(
specifier: string,
hasSourceCode: boolean,
sourceCode: string,
useDenoNamespace: boolean,
name?: string,
): CreateWorkerResponse {
return sendSync("op_create_worker", {
specifier,
hasSourceCode,
sourceCode,
name,
useDenoNamespace,
});
}
export function hostTerminateWorker(id: number): void {
sendSync("op_host_terminate_worker", { id });
}
export function hostPostMessage(id: number, data: Uint8Array): void {
sendSync("op_host_post_message", { id }, data);
}
export function hostGetMessage(id: number): Promise<any> {
return sendAsync("op_host_get_message", { id });
}

View file

@ -1,79 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import * as permissionsOps from "./ops/permissions.ts";
export type PermissionName =
| "read"
| "write"
| "net"
| "env"
| "run"
| "plugin"
| "hrtime";
// NOTE: Keep in sync with cli/permissions.rs
export type PermissionState = "granted" | "denied" | "prompt";
export interface RunPermissionDescriptor {
name: "run";
}
export interface ReadPermissionDescriptor {
name: "read";
path?: string;
}
export interface WritePermissionDescriptor {
name: "write";
path?: string;
}
export interface NetPermissionDescriptor {
name: "net";
url?: string;
}
export interface EnvPermissionDescriptor {
name: "env";
}
export interface PluginPermissionDescriptor {
name: "plugin";
}
export interface HrtimePermissionDescriptor {
name: "hrtime";
}
export type PermissionDescriptor =
| RunPermissionDescriptor
| ReadPermissionDescriptor
| WritePermissionDescriptor
| NetPermissionDescriptor
| EnvPermissionDescriptor
| PluginPermissionDescriptor
| HrtimePermissionDescriptor;
export class PermissionStatus {
constructor(public state: PermissionState) {}
// TODO(kt3k): implement onchange handler
}
export class Permissions {
query(desc: PermissionDescriptor): Promise<PermissionStatus> {
const state = permissionsOps.query(desc);
return Promise.resolve(new PermissionStatus(state));
}
revoke(desc: PermissionDescriptor): Promise<PermissionStatus> {
const state = permissionsOps.revoke(desc);
return Promise.resolve(new PermissionStatus(state));
}
request(desc: PermissionDescriptor): Promise<PermissionStatus> {
const state = permissionsOps.request(desc);
return Promise.resolve(new PermissionStatus(state));
}
}
export const permissions = new Permissions();

View file

@ -1,136 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { File } from "./files.ts";
import { close } from "./ops/resources.ts";
import type { Closer, Reader, Writer } from "./io.ts";
import { readAll } from "./buffer.ts";
import { kill, runStatus as runStatusOp, run as runOp } from "./ops/process.ts";
// TODO Maybe extend VSCode's 'CommandOptions'?
// See https://code.visualstudio.com/docs/editor/tasks-appendix#_schema-for-tasksjson
export interface RunOptions {
cmd: string[];
cwd?: string;
env?: Record<string, string>;
stdout?: "inherit" | "piped" | "null" | number;
stderr?: "inherit" | "piped" | "null" | number;
stdin?: "inherit" | "piped" | "null" | number;
}
async function runStatus(rid: number): Promise<ProcessStatus> {
const res = await runStatusOp(rid);
if (res.gotSignal) {
const signal = res.exitSignal;
return { success: false, code: 128 + signal, signal };
} else if (res.exitCode != 0) {
return { success: false, code: res.exitCode };
} else {
return { success: true, code: 0 };
}
}
export class Process<T extends RunOptions = RunOptions> {
readonly rid: number;
readonly pid: number;
readonly stdin!: T["stdin"] extends "piped" ? Writer & Closer
: (Writer & Closer) | null;
readonly stdout!: T["stdout"] extends "piped" ? Reader & Closer
: (Reader & Closer) | null;
readonly stderr!: T["stderr"] extends "piped" ? Reader & Closer
: (Reader & Closer) | null;
// @internal
constructor(res: RunResponse) {
this.rid = res.rid;
this.pid = res.pid;
if (res.stdinRid && res.stdinRid > 0) {
this.stdin = (new File(res.stdinRid) as unknown) as Process<T>["stdin"];
}
if (res.stdoutRid && res.stdoutRid > 0) {
this.stdout = (new File(res.stdoutRid) as unknown) as Process<
T
>["stdout"];
}
if (res.stderrRid && res.stderrRid > 0) {
this.stderr = (new File(res.stderrRid) as unknown) as Process<
T
>["stderr"];
}
}
status(): Promise<ProcessStatus> {
return runStatus(this.rid);
}
async output(): Promise<Uint8Array> {
if (!this.stdout) {
throw new TypeError("stdout was not piped");
}
try {
return await readAll(this.stdout as Reader & Closer);
} finally {
(this.stdout as Reader & Closer).close();
}
}
async stderrOutput(): Promise<Uint8Array> {
if (!this.stderr) {
throw new TypeError("stderr was not piped");
}
try {
return await readAll(this.stderr as Reader & Closer);
} finally {
(this.stderr as Reader & Closer).close();
}
}
close(): void {
close(this.rid);
}
kill(signo: number): void {
kill(this.pid, signo);
}
}
export type ProcessStatus =
| { success: true; code: 0; signal?: undefined }
| { success: false; code: number; signal?: number };
function isRid(arg: unknown): arg is number {
return !isNaN(arg as number);
}
interface RunResponse {
rid: number;
pid: number;
stdinRid: number | null;
stdoutRid: number | null;
stderrRid: number | null;
}
export function run<T extends RunOptions = RunOptions>({
cmd,
cwd = undefined,
env = {},
stdout = "inherit",
stderr = "inherit",
stdin = "inherit",
}: T): Process<T> {
const res = runOp({
cmd: cmd.map(String),
cwd,
env: Object.entries(env),
stdin: isRid(stdin) ? "" : stdin,
stdout: isRid(stdout) ? "" : stdout,
stderr: isRid(stderr) ? "" : stderr,
stdinRid: isRid(stdin) ? stdin : 0,
stdoutRid: isRid(stdout) ? stdout : 0,
stderrRid: isRid(stderr) ? stderr : 0,
}) as RunResponse;
return new Process<T>(res);
}

View file

@ -1,252 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// Derived from https://github.com/vadimg/js_bintrees. MIT Licensed.
import { assert } from "./util.ts";
class RBNode<T> {
public left: this | null;
public right: this | null;
public red: boolean;
constructor(public data: T) {
this.left = null;
this.right = null;
this.red = true;
}
getChild(dir: boolean | number): this | null {
return dir ? this.right : this.left;
}
setChild(dir: boolean | number, val: this | null): void {
if (dir) {
this.right = val;
} else {
this.left = val;
}
}
}
export class RBTree<T> {
readonly #comparator: (a: T, b: T) => number;
#root: RBNode<T> | null;
constructor(comparator: (a: T, b: T) => number) {
this.#comparator = comparator;
this.#root = null;
}
/** Returns `null` if tree is empty. */
min(): T | null {
let res = this.#root;
if (res === null) {
return null;
}
while (res.left !== null) {
res = res.left;
}
return res.data;
}
/** Returns node `data` if found, `null` otherwise. */
find(data: T): T | null {
let res = this.#root;
while (res !== null) {
const c = this.#comparator(data, res.data);
if (c === 0) {
return res.data;
} else {
res = res.getChild(c > 0);
}
}
return null;
}
/** returns `true` if inserted, `false` if duplicate. */
insert(data: T): boolean {
let ret = false;
if (this.#root === null) {
// empty tree
this.#root = new RBNode(data);
ret = true;
} else {
const head = new RBNode((null as unknown) as T); // fake tree root
let dir = 0;
let last = 0;
// setup
let gp = null; // grandparent
let ggp = head; // grand-grand-parent
let p: RBNode<T> | null = null; // parent
let node: RBNode<T> | null = this.#root;
ggp.right = this.#root;
// search down
while (true) {
if (node === null) {
// insert new node at the bottom
node = new RBNode(data);
p!.setChild(dir, node);
ret = true;
} else if (isRed(node.left) && isRed(node.right)) {
// color flip
node.red = true;
node.left!.red = false;
node.right!.red = false;
}
// fix red violation
if (isRed(node) && isRed(p)) {
const dir2 = ggp.right === gp;
assert(gp);
if (node === p!.getChild(last)) {
ggp.setChild(dir2, singleRotate(gp, !last));
} else {
ggp.setChild(dir2, doubleRotate(gp, !last));
}
}
const cmp = this.#comparator(node.data, data);
// stop if found
if (cmp === 0) {
break;
}
last = dir;
dir = Number(cmp < 0); // Fix type
// update helpers
if (gp !== null) {
ggp = gp;
}
gp = p;
p = node;
node = node.getChild(dir);
}
// update root
this.#root = head.right;
}
// make root black
this.#root!.red = false;
return ret;
}
/** Returns `true` if removed, `false` if not found. */
remove(data: T): boolean {
if (this.#root === null) {
return false;
}
const head = new RBNode((null as unknown) as T); // fake tree root
let node = head;
node.right = this.#root;
let p = null; // parent
let gp = null; // grand parent
let found = null; // found item
let dir: boolean | number = 1;
while (node.getChild(dir) !== null) {
const last = dir;
// update helpers
gp = p;
p = node;
node = node.getChild(dir)!;
const cmp = this.#comparator(data, node.data);
dir = cmp > 0;
// save found node
if (cmp === 0) {
found = node;
}
// push the red node down
if (!isRed(node) && !isRed(node.getChild(dir))) {
if (isRed(node.getChild(!dir))) {
const sr = singleRotate(node, dir);
p.setChild(last, sr);
p = sr;
} else if (!isRed(node.getChild(!dir))) {
const sibling = p.getChild(!last);
if (sibling !== null) {
if (
!isRed(sibling.getChild(!last)) &&
!isRed(sibling.getChild(last))
) {
// color flip
p.red = false;
sibling.red = true;
node.red = true;
} else {
assert(gp);
const dir2 = gp.right === p;
if (isRed(sibling.getChild(last))) {
gp!.setChild(dir2, doubleRotate(p, last));
} else if (isRed(sibling.getChild(!last))) {
gp!.setChild(dir2, singleRotate(p, last));
}
// ensure correct coloring
const gpc = gp.getChild(dir2);
assert(gpc);
gpc.red = true;
node.red = true;
assert(gpc.left);
gpc.left.red = false;
assert(gpc.right);
gpc.right.red = false;
}
}
}
}
}
// replace and remove if found
if (found !== null) {
found.data = node.data;
assert(p);
p.setChild(p.right === node, node.getChild(node.left === null));
}
// update root and make it black
this.#root = head.right;
if (this.#root !== null) {
this.#root.red = false;
}
return found !== null;
}
}
function isRed<T>(node: RBNode<T> | null): boolean {
return node !== null && node.red;
}
function singleRotate<T>(root: RBNode<T>, dir: boolean | number): RBNode<T> {
const save = root.getChild(!dir);
assert(save);
root.setChild(!dir, save.getChild(dir));
save.setChild(dir, root);
root.red = true;
save.red = false;
return save;
}
function doubleRotate<T>(root: RBNode<T>, dir: boolean | number): RBNode<T> {
root.setChild(!dir, singleRotate(root.getChild(!dir)!, !dir));
return singleRotate(root, dir);
}

View file

@ -1,18 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { open, openSync } from "./files.ts";
import { readAll, readAllSync } from "./buffer.ts";
export function readFileSync(path: string | URL): Uint8Array {
const file = openSync(path);
const contents = readAllSync(file);
file.close();
return contents;
}
export async function readFile(path: string | URL): Promise<Uint8Array> {
const file = await open(path);
const contents = await readAll(file);
file.close();
return contents;
}

View file

@ -1,20 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { open, openSync } from "./files.ts";
import { readAll, readAllSync } from "./buffer.ts";
export function readTextFileSync(path: string | URL): string {
const file = openSync(path);
const contents = readAllSync(file);
file.close();
const decoder = new TextDecoder();
return decoder.decode(contents);
}
export async function readTextFile(path: string | URL): Promise<string> {
const file = await open(path);
const contents = await readAll(file);
file.close();
const decoder = new TextDecoder();
return decoder.decode(contents);
}

View file

@ -1,177 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { exit } from "./ops/os.ts";
import { core } from "./core.ts";
import { version } from "./version.ts";
import { inspectArgs } from "./web/console.ts";
import { startRepl, readline } from "./ops/repl.ts";
import { close } from "./ops/resources.ts";
function replLog(...args: unknown[]): void {
core.print(inspectArgs(args) + "\n");
}
function replError(...args: unknown[]): void {
core.print(inspectArgs(args) + "\n", true);
}
// Error messages that allow users to continue input
// instead of throwing an error to REPL
// ref: https://github.com/v8/v8/blob/master/src/message-template.h
// TODO(kevinkassimo): this list might not be comprehensive
const recoverableErrorMessages = [
"Unexpected end of input", // { or [ or (
"Missing initializer in const declaration", // const a
"Missing catch or finally after try", // try {}
"missing ) after argument list", // console.log(1
"Unterminated template literal", // `template
// TODO(kevinkassimo): need a parser to handling errors such as:
// "Missing } in template expression" // `${ or `${ a 123 }`
];
function isRecoverableError(e: Error): boolean {
return recoverableErrorMessages.includes(e.message);
}
// Returns `true` if `close()` is called in REPL.
// We should quit the REPL when this function returns `true`.
function isCloseCalled(): boolean {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (globalThis as any).closed;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type Value = any;
let lastEvalResult: Value = undefined;
let lastThrownError: Value = undefined;
// Evaluate code.
// Returns true if code is consumed (no error/irrecoverable error).
// Returns false if error is recoverable
function evaluate(code: string): boolean {
// each evalContext is a separate function body, and we want strict mode to
// work, so we should ensure that the code starts with "use strict"
const [result, errInfo] = core.evalContext(`"use strict";\n\n${code}`);
if (!errInfo) {
// when a function is eval'ed with just "use strict" sometimes the result
// is "use strict" which should be discarded
lastEvalResult = typeof result === "string" && result === "use strict"
? undefined
: result;
if (!isCloseCalled()) {
replLog(lastEvalResult);
}
} else if (errInfo.isCompileError && isRecoverableError(errInfo.thrown)) {
// Recoverable compiler error
return false; // don't consume code.
} else {
lastThrownError = errInfo.thrown;
if (errInfo.isNativeError) {
const formattedError = core.formatError(errInfo.thrown as Error);
replError(formattedError);
} else {
replError("Thrown:", errInfo.thrown);
}
}
return true;
}
// @internal
export async function replLoop(): Promise<void> {
const { console } = globalThis;
const historyFile = "deno_history.txt";
const rid = startRepl(historyFile);
const quitRepl = (exitCode: number): void => {
// Special handling in case user calls deno.close(3).
try {
close(rid); // close signals Drop on REPL and saves history.
} catch {}
exit(exitCode);
};
// Configure globalThis._ to give the last evaluation result.
Object.defineProperty(globalThis, "_", {
configurable: true,
get: (): Value => lastEvalResult,
set: (value: Value): Value => {
Object.defineProperty(globalThis, "_", {
value: value,
writable: true,
enumerable: true,
configurable: true,
});
console.log("Last evaluation result is no longer saved to _.");
},
});
// Configure globalThis._error to give the last thrown error.
Object.defineProperty(globalThis, "_error", {
configurable: true,
get: (): Value => lastThrownError,
set: (value: Value): Value => {
Object.defineProperty(globalThis, "_error", {
value: value,
writable: true,
enumerable: true,
configurable: true,
});
console.log("Last thrown error is no longer saved to _error.");
},
});
replLog(`Deno ${version.deno}`);
replLog("exit using ctrl+d or close()");
while (true) {
if (isCloseCalled()) {
quitRepl(0);
}
let code = "";
// Top level read
try {
code = await readline(rid, "> ");
if (code.trim() === "") {
continue;
}
} catch (err) {
if (err.message === "EOF") {
quitRepl(0);
} else {
// If interrupted, don't print error.
if (err.message !== "Interrupted") {
// e.g. this happens when we have deno.close(3).
// We want to display the problem.
const formattedError = core.formatError(err);
replError(formattedError);
}
// Quit REPL anyways.
quitRepl(1);
}
}
// Start continued read
while (!evaluate(code)) {
code += "\n";
try {
code += await readline(rid, " ");
} catch (err) {
// If interrupted on continued read,
// abort this read instead of quitting.
if (err.message === "Interrupted") {
break;
} else if (err.message === "EOF") {
quitRepl(0);
} else {
// e.g. this happens when we have deno.close(3).
// We want to display the problem.
const formattedError = core.formatError(err);
replError(formattedError);
quitRepl(1);
}
}
}
}
}

View file

@ -1,44 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { core } from "./core.ts";
import * as dispatchMinimal from "./ops/dispatch_minimal.ts";
import * as dispatchJson from "./ops/dispatch_json.ts";
import * as util from "./util.ts";
import { setBuildInfo } from "./build.ts";
import { setVersions } from "./version.ts";
import { setPrepareStackTrace } from "./error_stack.ts";
import { Start, opStart } from "./ops/runtime.ts";
import { handleTimerMacrotask } from "./web/timers.ts";
function getAsyncHandler(opName: string): (msg: Uint8Array) => void {
switch (opName) {
case "op_write":
case "op_read":
return dispatchMinimal.asyncMsgFromRust;
default:
return dispatchJson.asyncMsgFromRust;
}
}
// TODO(bartlomieju): temporary solution, must be fixed when moving
// dispatches to separate crates
export function initOps(): void {
const opsMap = core.ops();
for (const [name, opId] of Object.entries(opsMap)) {
core.setAsyncHandler(opId, getAsyncHandler(name));
}
core.setMacrotaskCallback(handleTimerMacrotask);
}
export function start(source?: string): Start {
initOps();
// First we send an empty `Start` message to let the privileged side know we
// are ready. The response should be a `StartRes` message containing the CLI
// args and other info.
const s = opStart();
setVersions(s.denoVersion, s.v8Version, s.tsVersion);
setBuildInfo(s.target);
util.setLogDebug(s.debugFlag, source);
setPrepareStackTrace(Error);
return s;
}

View file

@ -1,129 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// This module is the entry point for "main" isolate, ie. the one
// that is created when you run "deno" executable.
//
// It provides a single function that should be called by Rust:
// - `bootstrapMainRuntime` - must be called once, when Isolate is created.
// It sets up runtime by providing globals for `WindowScope` and adds `Deno` global.
import * as denoNs from "./deno.ts";
import * as denoUnstableNs from "./deno_unstable.ts";
import { opMainModule } from "./ops/runtime.ts";
import { exit } from "./ops/os.ts";
import {
readOnly,
getterOnly,
writable,
windowOrWorkerGlobalScopeMethods,
windowOrWorkerGlobalScopeProperties,
eventTargetProperties,
setEventTargetData,
} from "./globals.ts";
import { unstableMethods, unstableProperties } from "./globals_unstable.ts";
import { internalObject, internalSymbol } from "./internals.ts";
import { setSignals } from "./signals.ts";
import { replLoop } from "./repl.ts";
import { setTimeout } from "./web/timers.ts";
import * as runtime from "./runtime.ts";
import { log, immutableDefine } from "./util.ts";
// TODO: factor out `Deno` global assignment to separate function
// Add internal object to Deno object.
// This is not exposed as part of the Deno types.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(denoNs as any)[internalSymbol] = internalObject;
let windowIsClosing = false;
function windowClose(): void {
if (!windowIsClosing) {
windowIsClosing = true;
// Push a macrotask to exit after a promise resolve.
// This is not perfect, but should be fine for first pass.
Promise.resolve().then(() =>
setTimeout.call(
null,
() => {
// This should be fine, since only Window/MainWorker has .close()
exit(0);
},
0,
)
);
}
}
export const mainRuntimeGlobalProperties = {
window: readOnly(globalThis),
self: readOnly(globalThis),
// TODO(bartlomieju): from MDN docs (https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope)
// it seems those two properties should be available to workers as well
onload: writable(null),
onunload: writable(null),
close: writable(windowClose),
closed: getterOnly(() => windowIsClosing),
};
let hasBootstrapped = false;
export function bootstrapMainRuntime(): void {
if (hasBootstrapped) {
throw new Error("Worker runtime already bootstrapped");
}
// Remove bootstrapping methods from global scope
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(globalThis as any).bootstrap = undefined;
log("bootstrapMainRuntime");
hasBootstrapped = true;
Object.defineProperties(globalThis, windowOrWorkerGlobalScopeMethods);
Object.defineProperties(globalThis, windowOrWorkerGlobalScopeProperties);
Object.defineProperties(globalThis, eventTargetProperties);
Object.defineProperties(globalThis, mainRuntimeGlobalProperties);
setEventTargetData(globalThis);
// Registers the handler for window.onload function.
globalThis.addEventListener("load", (e) => {
const { onload } = globalThis;
if (typeof onload === "function") {
onload(e);
}
});
// Registers the handler for window.onunload function.
globalThis.addEventListener("unload", (e) => {
const { onunload } = globalThis;
if (typeof onunload === "function") {
onunload(e);
}
});
const { args, cwd, noColor, pid, ppid, repl, unstableFlag } = runtime.start();
Object.defineProperties(denoNs, {
pid: readOnly(pid),
ppid: readOnly(ppid),
noColor: readOnly(noColor),
args: readOnly(Object.freeze(args)),
});
if (unstableFlag) {
Object.defineProperties(globalThis, unstableMethods);
Object.defineProperties(globalThis, unstableProperties);
Object.defineProperty(denoNs, "mainModule", getterOnly(opMainModule));
Object.assign(denoNs, denoUnstableNs);
}
// Setup `Deno` global - we're actually overriding already
// existing global `Deno` with `Deno` namespace from "./deno.ts".
immutableDefine(globalThis, "Deno", denoNs);
Object.freeze(globalThis.Deno);
Object.freeze(globalThis.Deno.core);
Object.freeze(globalThis.Deno.core.sharedQueue);
setSignals();
log("cwd", cwd);
log("args", args);
if (repl) {
replLoop();
}
}

View file

@ -1,170 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// This module is the entry point for "worker" isolate, ie. the one
// that is created using `new Worker()` JS API.
//
// It provides a single function that should be called by Rust:
// - `bootstrapWorkerRuntime` - must be called once, when Isolate is created.
// It sets up runtime by providing globals for `DedicatedWorkerScope`.
/* eslint-disable @typescript-eslint/no-explicit-any */
import {
readOnly,
writable,
nonEnumerable,
windowOrWorkerGlobalScopeMethods,
windowOrWorkerGlobalScopeProperties,
eventTargetProperties,
setEventTargetData,
} from "./globals.ts";
import { unstableMethods, unstableProperties } from "./globals_unstable.ts";
import * as denoNs from "./deno.ts";
import * as denoUnstableNs from "./deno_unstable.ts";
import * as webWorkerOps from "./ops/web_worker.ts";
import { log, assert, immutableDefine } from "./util.ts";
import { ErrorEventImpl as ErrorEvent } from "./web/error_event.ts";
import { MessageEvent } from "./web/workers.ts";
import { TextEncoder } from "./web/text_encoding.ts";
import * as runtime from "./runtime.ts";
import { internalObject, internalSymbol } from "./internals.ts";
import { setSignals } from "./signals.ts";
// FIXME(bartlomieju): duplicated in `runtime_main.ts`
// TODO: factor out `Deno` global assignment to separate function
// Add internal object to Deno object.
// This is not exposed as part of the Deno types.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(denoNs as any)[internalSymbol] = internalObject;
const encoder = new TextEncoder();
// TODO(bartlomieju): remove these funtions
// Stuff for workers
export const onmessage: (e: { data: any }) => void = (): void => {};
export const onerror: (e: { data: any }) => void = (): void => {};
export function postMessage(data: any): void {
const dataJson = JSON.stringify(data);
const dataIntArray = encoder.encode(dataJson);
webWorkerOps.postMessage(dataIntArray);
}
let isClosing = false;
let hasBootstrapped = false;
export function close(): void {
if (isClosing) {
return;
}
isClosing = true;
webWorkerOps.close();
}
export async function workerMessageRecvCallback(data: string): Promise<void> {
const msgEvent = new MessageEvent("message", {
cancelable: false,
data,
});
try {
if (globalThis["onmessage"]) {
const result = globalThis.onmessage!(msgEvent);
if (result && "then" in result) {
await result;
}
}
globalThis.dispatchEvent(msgEvent);
} catch (e) {
let handled = false;
const errorEvent = new ErrorEvent("error", {
cancelable: true,
message: e.message,
lineno: e.lineNumber ? e.lineNumber + 1 : undefined,
colno: e.columnNumber ? e.columnNumber + 1 : undefined,
filename: e.fileName,
error: null,
});
if (globalThis["onerror"]) {
const ret = globalThis.onerror(
e.message,
e.fileName,
e.lineNumber,
e.columnNumber,
e,
);
handled = ret === true;
}
globalThis.dispatchEvent(errorEvent);
if (errorEvent.defaultPrevented) {
handled = true;
}
if (!handled) {
throw e;
}
}
}
export const workerRuntimeGlobalProperties = {
self: readOnly(globalThis),
onmessage: writable(onmessage),
onerror: writable(onerror),
// TODO: should be readonly?
close: nonEnumerable(close),
postMessage: writable(postMessage),
workerMessageRecvCallback: nonEnumerable(workerMessageRecvCallback),
};
export function bootstrapWorkerRuntime(
name: string,
useDenoNamespace: boolean,
internalName?: string,
): void {
if (hasBootstrapped) {
throw new Error("Worker runtime already bootstrapped");
}
// Remove bootstrapping methods from global scope
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(globalThis as any).bootstrap = undefined;
log("bootstrapWorkerRuntime");
hasBootstrapped = true;
Object.defineProperties(globalThis, windowOrWorkerGlobalScopeMethods);
Object.defineProperties(globalThis, windowOrWorkerGlobalScopeProperties);
Object.defineProperties(globalThis, workerRuntimeGlobalProperties);
Object.defineProperties(globalThis, eventTargetProperties);
Object.defineProperties(globalThis, { name: readOnly(name) });
setEventTargetData(globalThis);
const { unstableFlag, pid, noColor, args } = runtime.start(
internalName ?? name,
);
if (unstableFlag) {
Object.defineProperties(globalThis, unstableMethods);
Object.defineProperties(globalThis, unstableProperties);
}
if (useDenoNamespace) {
if (unstableFlag) {
Object.assign(denoNs, denoUnstableNs);
}
Object.defineProperties(denoNs, {
pid: readOnly(pid),
noColor: readOnly(noColor),
args: readOnly(Object.freeze(args)),
});
// Setup `Deno` global - we're actually overriding already
// existing global `Deno` with `Deno` namespace from "./deno.ts".
immutableDefine(globalThis, "Deno", denoNs);
Object.freeze(globalThis.Deno);
Object.freeze(globalThis.Deno.core);
Object.freeze(globalThis.Deno.core.sharedQueue);
setSignals();
} else {
delete globalThis.Deno;
assert(globalThis.Deno === undefined);
}
}

View file

@ -1,173 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { bindSignal, pollSignal, unbindSignal } from "./ops/signal.ts";
import { build } from "./build.ts";
// From `kill -l`
enum LinuxSignal {
SIGHUP = 1,
SIGINT = 2,
SIGQUIT = 3,
SIGILL = 4,
SIGTRAP = 5,
SIGABRT = 6,
SIGBUS = 7,
SIGFPE = 8,
SIGKILL = 9,
SIGUSR1 = 10,
SIGSEGV = 11,
SIGUSR2 = 12,
SIGPIPE = 13,
SIGALRM = 14,
SIGTERM = 15,
SIGSTKFLT = 16,
SIGCHLD = 17,
SIGCONT = 18,
SIGSTOP = 19,
SIGTSTP = 20,
SIGTTIN = 21,
SIGTTOU = 22,
SIGURG = 23,
SIGXCPU = 24,
SIGXFSZ = 25,
SIGVTALRM = 26,
SIGPROF = 27,
SIGWINCH = 28,
SIGIO = 29,
SIGPWR = 30,
SIGSYS = 31,
}
// From `kill -l`
enum MacOSSignal {
SIGHUP = 1,
SIGINT = 2,
SIGQUIT = 3,
SIGILL = 4,
SIGTRAP = 5,
SIGABRT = 6,
SIGEMT = 7,
SIGFPE = 8,
SIGKILL = 9,
SIGBUS = 10,
SIGSEGV = 11,
SIGSYS = 12,
SIGPIPE = 13,
SIGALRM = 14,
SIGTERM = 15,
SIGURG = 16,
SIGSTOP = 17,
SIGTSTP = 18,
SIGCONT = 19,
SIGCHLD = 20,
SIGTTIN = 21,
SIGTTOU = 22,
SIGIO = 23,
SIGXCPU = 24,
SIGXFSZ = 25,
SIGVTALRM = 26,
SIGPROF = 27,
SIGWINCH = 28,
SIGINFO = 29,
SIGUSR1 = 30,
SIGUSR2 = 31,
}
export const Signal: { [key: string]: number } = {};
export function setSignals(): void {
if (build.os === "darwin") {
Object.assign(Signal, MacOSSignal);
} else {
Object.assign(Signal, LinuxSignal);
}
}
export function signal(signo: number): SignalStream {
if (build.os === "windows") {
throw new Error("not implemented!");
}
return new SignalStream(signo);
}
export const signals = {
alarm(): SignalStream {
return signal(Signal.SIGALRM);
},
child(): SignalStream {
return signal(Signal.SIGCHLD);
},
hungup(): SignalStream {
return signal(Signal.SIGHUP);
},
interrupt(): SignalStream {
return signal(Signal.SIGINT);
},
io(): SignalStream {
return signal(Signal.SIGIO);
},
pipe(): SignalStream {
return signal(Signal.SIGPIPE);
},
quit(): SignalStream {
return signal(Signal.SIGQUIT);
},
terminate(): SignalStream {
return signal(Signal.SIGTERM);
},
userDefined1(): SignalStream {
return signal(Signal.SIGUSR1);
},
userDefined2(): SignalStream {
return signal(Signal.SIGUSR2);
},
windowChange(): SignalStream {
return signal(Signal.SIGWINCH);
},
};
export class SignalStream
implements AsyncIterableIterator<void>, PromiseLike<void> {
#disposed = false;
#pollingPromise: Promise<boolean> = Promise.resolve(false);
readonly #rid: number;
constructor(signo: number) {
this.#rid = bindSignal(signo).rid;
this.#loop();
}
#pollSignal = async (): Promise<boolean> => {
const res = await pollSignal(this.#rid);
return res.done;
};
#loop = async (): Promise<void> => {
do {
this.#pollingPromise = this.#pollSignal();
} while (!(await this.#pollingPromise) && !this.#disposed);
};
then<T, S>(
f: (v: void) => T | Promise<T>,
g?: (v: Error) => S | Promise<S>,
): Promise<T | S> {
return this.#pollingPromise.then(() => {}).then(f, g);
}
async next(): Promise<IteratorResult<void>> {
return { done: await this.#pollingPromise, value: undefined };
}
[Symbol.asyncIterator](): AsyncIterableIterator<void> {
return this;
}
dispose(): void {
if (this.#disposed) {
throw new Error("The stream has already been disposed.");
}
this.#disposed = true;
unbindSignal(this.#rid);
}
}

View file

@ -1,387 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { gray, green, italic, red, yellow } from "./colors.ts";
import { exit } from "./ops/os.ts";
import { Console, inspectArgs } from "./web/console.ts";
import { stdout } from "./files.ts";
import { exposeForTest } from "./internals.ts";
import { TextEncoder } from "./web/text_encoding.ts";
import { metrics } from "./ops/runtime.ts";
import { resources } from "./ops/resources.ts";
import { assert } from "./util.ts";
const disabledConsole = new Console((): void => {});
function delay(ms: number): Promise<void> {
return new Promise((resolve: () => void) => {
setTimeout(resolve, ms);
});
}
function formatDuration(time = 0): string {
const timeStr = `(${time}ms)`;
return gray(italic(timeStr));
}
// Wrap test function in additional assertion that makes sure
// the test case does not leak async "ops" - ie. number of async
// completed ops after the test is the same as number of dispatched
// ops. Note that "unref" ops are ignored since in nature that are
// optional.
function assertOps(fn: () => void | Promise<void>): () => void | Promise<void> {
return async function asyncOpSanitizer(): Promise<void> {
const pre = metrics();
await fn();
// Defer until next event loop turn - that way timeouts and intervals
// cleared can actually be removed from resource table, otherwise
// false positives may occur (https://github.com/denoland/deno/issues/4591)
await delay(0);
const post = metrics();
// We're checking diff because one might spawn HTTP server in the background
// that will be a pending async op before test starts.
const dispatchedDiff = post.opsDispatchedAsync - pre.opsDispatchedAsync;
const completedDiff = post.opsCompletedAsync - pre.opsCompletedAsync;
assert(
dispatchedDiff === completedDiff,
`Test case is leaking async ops.
Before:
- dispatched: ${pre.opsDispatchedAsync}
- completed: ${pre.opsCompletedAsync}
After:
- dispatched: ${post.opsDispatchedAsync}
- completed: ${post.opsCompletedAsync}
Make sure to await all promises returned from Deno APIs before
finishing test case.`,
);
};
}
// Wrap test function in additional assertion that makes sure
// the test case does not "leak" resources - ie. resource table after
// the test has exactly the same contents as before the test.
function assertResources(
fn: () => void | Promise<void>,
): () => void | Promise<void> {
return async function resourceSanitizer(): Promise<void> {
const pre = resources();
await fn();
const post = resources();
const preStr = JSON.stringify(pre, null, 2);
const postStr = JSON.stringify(post, null, 2);
const msg = `Test case is leaking resources.
Before: ${preStr}
After: ${postStr}
Make sure to close all open resource handles returned from Deno APIs before
finishing test case.`;
assert(preStr === postStr, msg);
};
}
export interface TestDefinition {
fn: () => void | Promise<void>;
name: string;
ignore?: boolean;
only?: boolean;
sanitizeOps?: boolean;
sanitizeResources?: boolean;
}
const TEST_REGISTRY: TestDefinition[] = [];
export function test(t: TestDefinition): void;
export function test(name: string, fn: () => void | Promise<void>): void;
// Main test function provided by Deno, as you can see it merely
// creates a new object with "name" and "fn" fields.
export function test(
t: string | TestDefinition,
fn?: () => void | Promise<void>,
): void {
let testDef: TestDefinition;
const defaults = {
ignore: false,
only: false,
sanitizeOps: true,
sanitizeResources: true,
};
if (typeof t === "string") {
if (!fn || typeof fn != "function") {
throw new TypeError("Missing test function");
}
if (!t) {
throw new TypeError("The test name can't be empty");
}
testDef = { fn: fn as () => void | Promise<void>, name: t, ...defaults };
} else {
if (!t.fn) {
throw new TypeError("Missing test function");
}
if (!t.name) {
throw new TypeError("The test name can't be empty");
}
testDef = { ...defaults, ...t };
}
if (testDef.sanitizeOps) {
testDef.fn = assertOps(testDef.fn);
}
if (testDef.sanitizeResources) {
testDef.fn = assertResources(testDef.fn);
}
TEST_REGISTRY.push(testDef);
}
interface TestMessage {
start?: {
tests: TestDefinition[];
};
// Must be extensible, avoiding `testStart?: TestDefinition;`.
testStart?: {
[P in keyof TestDefinition]: TestDefinition[P];
};
testEnd?: {
name: string;
status: "passed" | "failed" | "ignored";
duration: number;
error?: Error;
};
end?: {
filtered: number;
ignored: number;
measured: number;
passed: number;
failed: number;
usedOnly: boolean;
duration: number;
results: Array<TestMessage["testEnd"] & {}>;
};
}
const encoder = new TextEncoder();
function log(msg: string, noNewLine = false): void {
if (!noNewLine) {
msg += "\n";
}
// Using `stdout` here because it doesn't force new lines
// compared to `console.log`; `core.print` on the other hand
// is line-buffered and doesn't output message without newline
stdout.writeSync(encoder.encode(msg));
}
function reportToConsole(message: TestMessage): void {
const redFailed = red("FAILED");
const greenOk = green("ok");
const yellowIgnored = yellow("ignored");
if (message.start != null) {
log(`running ${message.start.tests.length} tests`);
} else if (message.testStart != null) {
const { name } = message.testStart;
log(`test ${name} ... `, true);
return;
} else if (message.testEnd != null) {
switch (message.testEnd.status) {
case "passed":
log(`${greenOk} ${formatDuration(message.testEnd.duration)}`);
break;
case "failed":
log(`${redFailed} ${formatDuration(message.testEnd.duration)}`);
break;
case "ignored":
log(`${yellowIgnored} ${formatDuration(message.testEnd.duration)}`);
break;
}
} else if (message.end != null) {
const failures = message.end.results.filter((m) => m.error != null);
if (failures.length > 0) {
log(`\nfailures:\n`);
for (const { name, error } of failures) {
log(name);
log(inspectArgs([error!]));
log("");
}
log(`failures:\n`);
for (const { name } of failures) {
log(`\t${name}`);
}
}
log(
`\ntest result: ${message.end.failed ? redFailed : greenOk}. ` +
`${message.end.passed} passed; ${message.end.failed} failed; ` +
`${message.end.ignored} ignored; ${message.end.measured} measured; ` +
`${message.end.filtered} filtered out ` +
`${formatDuration(message.end.duration)}\n`,
);
if (message.end.usedOnly && message.end.failed == 0) {
log(`${redFailed} because the "only" option was used\n`);
}
}
}
exposeForTest("reportToConsole", reportToConsole);
// TODO: already implements AsyncGenerator<RunTestsMessage>, but add as "implements to class"
// TODO: implements PromiseLike<RunTestsEndResult>
class TestRunner {
readonly testsToRun: TestDefinition[];
readonly stats = {
filtered: 0,
ignored: 0,
measured: 0,
passed: 0,
failed: 0,
};
readonly #usedOnly: boolean;
constructor(
tests: TestDefinition[],
public filterFn: (def: TestDefinition) => boolean,
public failFast: boolean,
) {
const onlyTests = tests.filter(({ only }) => only);
this.#usedOnly = onlyTests.length > 0;
const unfilteredTests = this.#usedOnly ? onlyTests : tests;
this.testsToRun = unfilteredTests.filter(filterFn);
this.stats.filtered = unfilteredTests.length - this.testsToRun.length;
}
async *[Symbol.asyncIterator](): AsyncIterator<TestMessage> {
yield { start: { tests: this.testsToRun } };
const results: Array<TestMessage["testEnd"] & {}> = [];
const suiteStart = +new Date();
for (const test of this.testsToRun) {
const endMessage: Partial<TestMessage["testEnd"] & {}> = {
name: test.name,
duration: 0,
};
yield { testStart: { ...test } };
if (test.ignore) {
endMessage.status = "ignored";
this.stats.ignored++;
} else {
const start = +new Date();
try {
await test.fn();
endMessage.status = "passed";
this.stats.passed++;
} catch (err) {
endMessage.status = "failed";
endMessage.error = err;
this.stats.failed++;
}
endMessage.duration = +new Date() - start;
}
results.push(endMessage as TestMessage["testEnd"] & {});
yield { testEnd: endMessage as TestMessage["testEnd"] };
if (this.failFast && endMessage.error != null) {
break;
}
}
const duration = +new Date() - suiteStart;
yield {
end: { ...this.stats, usedOnly: this.#usedOnly, duration, results },
};
}
}
function createFilterFn(
filter: undefined | string | RegExp,
skip: undefined | string | RegExp,
): (def: TestDefinition) => boolean {
return (def: TestDefinition): boolean => {
let passes = true;
if (filter) {
if (filter instanceof RegExp) {
passes = passes && filter.test(def.name);
} else if (filter.startsWith("/") && filter.endsWith("/")) {
const filterAsRegex = new RegExp(filter.slice(1, filter.length - 1));
passes = passes && filterAsRegex.test(def.name);
} else {
passes = passes && def.name.includes(filter);
}
}
if (skip) {
if (skip instanceof RegExp) {
passes = passes && !skip.test(def.name);
} else {
passes = passes && !def.name.includes(skip);
}
}
return passes;
};
}
exposeForTest("createFilterFn", createFilterFn);
interface RunTestsOptions {
exitOnFail?: boolean;
failFast?: boolean;
filter?: string | RegExp;
skip?: string | RegExp;
disableLog?: boolean;
reportToConsole?: boolean;
onMessage?: (message: TestMessage) => void | Promise<void>;
}
async function runTests({
exitOnFail = true,
failFast = false,
filter = undefined,
skip = undefined,
disableLog = false,
reportToConsole: reportToConsole_ = true,
onMessage = undefined,
}: RunTestsOptions = {}): Promise<TestMessage["end"] & {}> {
const filterFn = createFilterFn(filter, skip);
const testRunner = new TestRunner(TEST_REGISTRY, filterFn, failFast);
const originalConsole = globalThis.console;
if (disableLog) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(globalThis as any).console = disabledConsole;
}
let endMsg: TestMessage["end"];
for await (const message of testRunner) {
if (onMessage != null) {
await onMessage(message);
}
if (reportToConsole_) {
reportToConsole(message);
}
if (message.end != null) {
endMsg = message.end;
}
}
if (disableLog) {
globalThis.console = originalConsole;
}
if ((endMsg!.failed > 0 || endMsg?.usedOnly) && exitOnFail) {
exit(1);
}
return endMsg!;
}
exposeForTest("runTests", runTests);

View file

@ -1,77 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import * as tlsOps from "./ops/tls.ts";
import { Listener, Conn, ConnImpl, ListenerImpl } from "./net.ts";
// TODO(ry) There are many configuration options to add...
// https://docs.rs/rustls/0.16.0/rustls/struct.ClientConfig.html
interface ConnectTlsOptions {
transport?: "tcp";
port: number;
hostname?: string;
certFile?: string;
}
export async function connectTls({
port,
hostname = "127.0.0.1",
transport = "tcp",
certFile = undefined,
}: ConnectTlsOptions): Promise<Conn> {
const res = await tlsOps.connectTls({
port,
hostname,
transport,
certFile,
});
return new ConnImpl(res.rid, res.remoteAddr!, res.localAddr!);
}
class TLSListenerImpl extends ListenerImpl {
async accept(): Promise<Conn> {
const res = await tlsOps.acceptTLS(this.rid);
return new ConnImpl(res.rid, res.remoteAddr, res.localAddr);
}
}
export interface ListenTlsOptions {
port: number;
hostname?: string;
transport?: "tcp";
certFile: string;
keyFile: string;
}
export function listenTls({
port,
certFile,
keyFile,
hostname = "0.0.0.0",
transport = "tcp",
}: ListenTlsOptions): Listener {
const res = tlsOps.listenTls({
port,
certFile,
keyFile,
hostname,
transport,
});
return new TLSListenerImpl(res.rid, res.localAddr);
}
interface StartTlsOptions {
hostname?: string;
certFile?: string;
}
export async function startTls(
conn: Conn,
{ hostname = "127.0.0.1", certFile }: StartTlsOptions = {},
): Promise<Conn> {
const res = await tlsOps.startTls({
rid: conn.rid,
hostname,
certFile,
});
return new ConnImpl(res.rid, res.remoteAddr!, res.localAddr!);
}

37
cli/js/ts_global.d.ts vendored
View file

@ -1,37 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// This scopes the `ts` namespace globally, which is where it exists at runtime
// when building Deno, but the `typescript/lib/typescript.d.ts` is defined as a
// module.
// Warning! This is a magical import. We don't want to have multiple copies of
// typescript.d.ts around the repo, there's already one in
// deno_typescript/typescript/lib/typescript.d.ts. Ideally we could simply point
// to that in this import specifier, but "cargo package" is very strict and
// requires all files to be present in a crate's subtree.
// to get proper editor intellisense, you can substitute "$asset$" with
// "../../deno_typescript/typescript/lib" - remember to revert before committing
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import * as ts_ from "$asset$/typescript.d.ts";
declare global {
namespace ts {
export = ts_;
}
namespace ts {
// this are marked @internal in TypeScript, but we need to access them,
// there is a risk these could change in future versions of TypeScript
export const libs: string[];
export const libMap: Map<string, string>;
export const performance: {
enable(): void;
disable(): void;
getDuration(value: string): number;
};
interface SourceFile {
version?: string;
}
}
}

View file

@ -1,126 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { build } from "./build.ts";
import { exposeForTest } from "./internals.ts";
let logDebug = false;
let logSource = "JS";
// @internal
export function setLogDebug(debug: boolean, source?: string): void {
logDebug = debug;
if (source) {
logSource = source;
}
}
export function log(...args: unknown[]): void {
if (logDebug) {
// if we destructure `console` off `globalThis` too early, we don't bind to
// the right console, therefore we don't log anything out.
globalThis.console.log(`DEBUG ${logSource} -`, ...args);
}
}
// @internal
export class AssertionError extends Error {
constructor(msg?: string) {
super(msg);
this.name = "AssertionError";
}
}
// @internal
export function assert(cond: unknown, msg = "Assertion failed."): asserts cond {
if (!cond) {
throw new AssertionError(msg);
}
}
export type ResolveFunction<T> = (value?: T | PromiseLike<T>) => void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type RejectFunction = (reason?: any) => void;
export interface ResolvableMethods<T> {
resolve: ResolveFunction<T>;
reject: RejectFunction;
}
// @internal
export type Resolvable<T> = Promise<T> & ResolvableMethods<T>;
// @internal
export function createResolvable<T>(): Resolvable<T> {
let resolve: ResolveFunction<T>;
let reject: RejectFunction;
const promise = new Promise<T>((res, rej): void => {
resolve = res;
reject = rej;
}) as Resolvable<T>;
promise.resolve = resolve!;
promise.reject = reject!;
return promise;
}
// @internal
export function notImplemented(): never {
throw new Error("not implemented");
}
// @internal
export function immutableDefine(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
o: any,
p: string | number | symbol,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
value: any,
): void {
Object.defineProperty(o, p, {
value,
configurable: false,
writable: false,
});
}
function pathFromURLWin32(url: URL): string {
const hostname = url.hostname;
const pathname = decodeURIComponent(url.pathname.replace(/\//g, "\\"));
if (hostname !== "") {
//TODO(actual-size) Node adds a punycode decoding step, we should consider adding this
return `\\\\${hostname}${pathname}`;
}
const validPath = /^\\(?<driveLetter>[A-Za-z]):\\/;
const matches = validPath.exec(pathname);
if (!matches?.groups?.driveLetter) {
throw new TypeError("A URL with the file schema must be absolute.");
}
// we don't want a leading slash on an absolute path in Windows
return pathname.slice(1);
}
function pathFromURLPosix(url: URL): string {
if (url.hostname !== "") {
throw new TypeError(`Host must be empty.`);
}
return decodeURIComponent(url.pathname);
}
export function pathFromURL(pathOrUrl: string | URL): string {
if (pathOrUrl instanceof URL) {
if (pathOrUrl.protocol != "file:") {
throw new TypeError("Must be a file URL.");
}
return build.os == "windows"
? pathFromURLWin32(pathOrUrl)
: pathFromURLPosix(pathOrUrl);
}
return pathOrUrl;
}
exposeForTest("pathFromURL", pathFromURL);

View file

@ -1,25 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
interface Version {
deno: string;
v8: string;
typescript: string;
}
export const version: Version = {
deno: "",
v8: "",
typescript: "",
};
export function setVersions(
denoVersion: string,
v8Version: string,
tsVersion: string,
): void {
version.deno = denoVersion;
version.v8 = v8Version;
version.typescript = tsVersion;
Object.freeze(version);
}

View file

@ -1,47 +0,0 @@
# Deno Web APIs
This directory facilities Web APIs that are available in Deno.
Please note, that some implementations might not be completely aligned with
specification.
Some Web APIs are using ops under the hood, eg. `console`, `performance`.
## Implemented Web APIs
- [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob): for
representing opaque binary data
- [Console](https://developer.mozilla.org/en-US/docs/Web/API/Console): for
logging purposes
- [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent),
[EventTarget](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget)
and
[EventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventListener):
to work with DOM events
- **Implementation notes:** There is no DOM hierarchy in Deno, so there is no
tree for Events to bubble/capture through.
- [fetch](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch),
[Request](https://developer.mozilla.org/en-US/docs/Web/API/Request),
[Response](https://developer.mozilla.org/en-US/docs/Web/API/Response),
[Body](https://developer.mozilla.org/en-US/docs/Web/API/Body) and
[Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers): modern
Promise-based HTTP Request API
- [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData): access
to a `multipart/form-data` serialization
- [Performance](https://developer.mozilla.org/en-US/docs/Web/API/Performance):
retrieving current time with a high precision
- [setTimeout](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout),
[setInterval](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval),
[clearTimeout](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearTimeout):
scheduling callbacks in future and
[clearInterval](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearInterval)
- [Stream](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API) for
creating, composing, and consuming streams of data
- [URL](https://developer.mozilla.org/en-US/docs/Web/API/URL) and
[URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams):
to construct and parse URLSs
- [Worker](https://developer.mozilla.org/en-US/docs/Web/API/Worker): executing
additional code in a separate thread
- **Implementation notes:** Blob URLs are not supported, object ownership
cannot be transferred, posted data is serialized to JSON instead of
[structured cloning](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm).

View file

@ -1,24 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { AbortSignalImpl, signalAbort } from "./abort_signal.ts";
export class AbortControllerImpl implements AbortController {
#signal = new AbortSignalImpl();
get signal(): AbortSignal {
return this.#signal;
}
abort(): void {
this.#signal[signalAbort]();
}
get [Symbol.toStringTag](): string {
return "AbortController";
}
}
Object.defineProperty(AbortControllerImpl, "name", {
value: "AbortController",
configurable: true,
});

View file

@ -1,58 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { EventImpl } from "./event.ts";
import { EventTargetImpl } from "./event_target.ts";
export const add = Symbol("add");
export const signalAbort = Symbol("signalAbort");
export const remove = Symbol("remove");
export class AbortSignalImpl extends EventTargetImpl implements AbortSignal {
#aborted?: boolean;
#abortAlgorithms = new Set<() => void>();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onabort: ((this: AbortSignal, ev: Event) => any) | null = null;
[add](algorithm: () => void): void {
this.#abortAlgorithms.add(algorithm);
}
[signalAbort](): void {
if (this.#aborted) {
return;
}
this.#aborted = true;
for (const algorithm of this.#abortAlgorithms) {
algorithm();
}
this.#abortAlgorithms.clear();
this.dispatchEvent(new EventImpl("abort"));
}
[remove](algorithm: () => void): void {
this.#abortAlgorithms.delete(algorithm);
}
constructor() {
super();
this.addEventListener("abort", (evt: Event) => {
const { onabort } = this;
if (typeof onabort === "function") {
onabort.call(this, evt);
}
});
}
get aborted(): boolean {
return Boolean(this.#aborted);
}
get [Symbol.toStringTag](): string {
return "AbortSignal";
}
}
Object.defineProperty(AbortSignalImpl, "name", {
value: "AbortSignal",
configurable: true,
});

View file

@ -1,148 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// Forked from https://github.com/beatgammit/base64-js
// Copyright (c) 2014 Jameson Little. MIT License.
const lookup: string[] = [];
const revLookup: number[] = [];
const code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for (let i = 0, len = code.length; i < len; ++i) {
lookup[i] = code[i];
revLookup[code.charCodeAt(i)] = i;
}
// Support decoding URL-safe base64 strings, as Node.js does.
// See: https://en.wikipedia.org/wiki/Base64#URL_applications
revLookup["-".charCodeAt(0)] = 62;
revLookup["_".charCodeAt(0)] = 63;
function getLens(b64: string): [number, number] {
const len = b64.length;
if (len % 4 > 0) {
throw new Error("Invalid string. Length must be a multiple of 4");
}
// Trim off extra bytes after placeholder bytes are found
// See: https://github.com/beatgammit/base64-js/issues/42
let validLen = b64.indexOf("=");
if (validLen === -1) validLen = len;
const placeHoldersLen = validLen === len ? 0 : 4 - (validLen % 4);
return [validLen, placeHoldersLen];
}
// base64 is 4/3 + up to two characters of the original data
export function byteLength(b64: string): number {
const lens = getLens(b64);
const validLen = lens[0];
const placeHoldersLen = lens[1];
return ((validLen + placeHoldersLen) * 3) / 4 - placeHoldersLen;
}
function _byteLength(
b64: string,
validLen: number,
placeHoldersLen: number,
): number {
return ((validLen + placeHoldersLen) * 3) / 4 - placeHoldersLen;
}
export function toByteArray(b64: string): Uint8Array {
let tmp;
const lens = getLens(b64);
const validLen = lens[0];
const placeHoldersLen = lens[1];
const arr = new Uint8Array(_byteLength(b64, validLen, placeHoldersLen));
let curByte = 0;
// if there are placeholders, only get up to the last complete 4 chars
const len = placeHoldersLen > 0 ? validLen - 4 : validLen;
let i;
for (i = 0; i < len; i += 4) {
tmp = (revLookup[b64.charCodeAt(i)] << 18) |
(revLookup[b64.charCodeAt(i + 1)] << 12) |
(revLookup[b64.charCodeAt(i + 2)] << 6) |
revLookup[b64.charCodeAt(i + 3)];
arr[curByte++] = (tmp >> 16) & 0xff;
arr[curByte++] = (tmp >> 8) & 0xff;
arr[curByte++] = tmp & 0xff;
}
if (placeHoldersLen === 2) {
tmp = (revLookup[b64.charCodeAt(i)] << 2) |
(revLookup[b64.charCodeAt(i + 1)] >> 4);
arr[curByte++] = tmp & 0xff;
}
if (placeHoldersLen === 1) {
tmp = (revLookup[b64.charCodeAt(i)] << 10) |
(revLookup[b64.charCodeAt(i + 1)] << 4) |
(revLookup[b64.charCodeAt(i + 2)] >> 2);
arr[curByte++] = (tmp >> 8) & 0xff;
arr[curByte++] = tmp & 0xff;
}
return arr;
}
function tripletToBase64(num: number): string {
return (
lookup[(num >> 18) & 0x3f] +
lookup[(num >> 12) & 0x3f] +
lookup[(num >> 6) & 0x3f] +
lookup[num & 0x3f]
);
}
function encodeChunk(uint8: Uint8Array, start: number, end: number): string {
let tmp;
const output = [];
for (let i = start; i < end; i += 3) {
tmp = ((uint8[i] << 16) & 0xff0000) +
((uint8[i + 1] << 8) & 0xff00) +
(uint8[i + 2] & 0xff);
output.push(tripletToBase64(tmp));
}
return output.join("");
}
export function fromByteArray(uint8: Uint8Array): string {
let tmp;
const len = uint8.length;
const extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes
const parts = [];
const maxChunkLength = 16383; // must be multiple of 3
// go through the array every three bytes, we'll deal with trailing stuff later
for (let i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
parts.push(
encodeChunk(
uint8,
i,
i + maxChunkLength > len2 ? len2 : i + maxChunkLength,
),
);
}
// pad the end with zeros, but make sure to not forget the extra bytes
if (extraBytes === 1) {
tmp = uint8[len - 1];
parts.push(lookup[tmp >> 2] + lookup[(tmp << 4) & 0x3f] + "==");
} else if (extraBytes === 2) {
tmp = (uint8[len - 2] << 8) + uint8[len - 1];
parts.push(
lookup[tmp >> 10] +
lookup[(tmp >> 4) & 0x3f] +
lookup[(tmp << 2) & 0x3f] +
"=",
);
}
return parts.join("");
}

View file

@ -1,227 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { TextDecoder, TextEncoder } from "./text_encoding.ts";
import { build } from "../build.ts";
import { ReadableStreamImpl } from "./streams/readable_stream.ts";
export const bytesSymbol = Symbol("bytes");
export function containsOnlyASCII(str: string): boolean {
if (typeof str !== "string") {
return false;
}
return /^[\x00-\x7F]*$/.test(str);
}
function convertLineEndingsToNative(s: string): string {
const nativeLineEnd = build.os == "windows" ? "\r\n" : "\n";
let position = 0;
let collectionResult = collectSequenceNotCRLF(s, position);
let token = collectionResult.collected;
position = collectionResult.newPosition;
let result = token;
while (position < s.length) {
const c = s.charAt(position);
if (c == "\r") {
result += nativeLineEnd;
position++;
if (position < s.length && s.charAt(position) == "\n") {
position++;
}
} else if (c == "\n") {
position++;
result += nativeLineEnd;
}
collectionResult = collectSequenceNotCRLF(s, position);
token = collectionResult.collected;
position = collectionResult.newPosition;
result += token;
}
return result;
}
function collectSequenceNotCRLF(
s: string,
position: number,
): { collected: string; newPosition: number } {
const start = position;
for (
let c = s.charAt(position);
position < s.length && !(c == "\r" || c == "\n");
c = s.charAt(++position)
);
return { collected: s.slice(start, position), newPosition: position };
}
function toUint8Arrays(
blobParts: BlobPart[],
doNormalizeLineEndingsToNative: boolean,
): Uint8Array[] {
const ret: Uint8Array[] = [];
const enc = new TextEncoder();
for (const element of blobParts) {
if (typeof element === "string") {
let str = element;
if (doNormalizeLineEndingsToNative) {
str = convertLineEndingsToNative(element);
}
ret.push(enc.encode(str));
// eslint-disable-next-line @typescript-eslint/no-use-before-define
} else if (element instanceof DenoBlob) {
ret.push(element[bytesSymbol]);
} else if (element instanceof Uint8Array) {
ret.push(element);
} else if (element instanceof Uint16Array) {
const uint8 = new Uint8Array(element.buffer);
ret.push(uint8);
} else if (element instanceof Uint32Array) {
const uint8 = new Uint8Array(element.buffer);
ret.push(uint8);
} else if (ArrayBuffer.isView(element)) {
// Convert view to Uint8Array.
const uint8 = new Uint8Array(element.buffer);
ret.push(uint8);
} else if (element instanceof ArrayBuffer) {
// Create a new Uint8Array view for the given ArrayBuffer.
const uint8 = new Uint8Array(element);
ret.push(uint8);
} else {
ret.push(enc.encode(String(element)));
}
}
return ret;
}
function processBlobParts(
blobParts: BlobPart[],
options: BlobPropertyBag,
): Uint8Array {
const normalizeLineEndingsToNative = options.ending === "native";
// ArrayBuffer.transfer is not yet implemented in V8, so we just have to
// pre compute size of the array buffer and do some sort of static allocation
// instead of dynamic allocation.
const uint8Arrays = toUint8Arrays(blobParts, normalizeLineEndingsToNative);
const byteLength = uint8Arrays
.map((u8): number => u8.byteLength)
.reduce((a, b): number => a + b, 0);
const ab = new ArrayBuffer(byteLength);
const bytes = new Uint8Array(ab);
let courser = 0;
for (const u8 of uint8Arrays) {
bytes.set(u8, courser);
courser += u8.byteLength;
}
return bytes;
}
function getStream(blobBytes: Uint8Array): ReadableStream<ArrayBufferView> {
// TODO: Align to spec https://fetch.spec.whatwg.org/#concept-construct-readablestream
return new ReadableStreamImpl({
type: "bytes",
start: (controller: ReadableByteStreamController): void => {
controller.enqueue(blobBytes);
controller.close();
},
});
}
async function readBytes(
reader: ReadableStreamReader<ArrayBufferView>,
): Promise<ArrayBuffer> {
const chunks: Uint8Array[] = [];
while (true) {
const { done, value } = await reader.read();
if (!done && value instanceof Uint8Array) {
chunks.push(value);
} else if (done) {
const size = chunks.reduce((p, i) => p + i.byteLength, 0);
const bytes = new Uint8Array(size);
let offs = 0;
for (const chunk of chunks) {
bytes.set(chunk, offs);
offs += chunk.byteLength;
}
return bytes;
} else {
throw new TypeError("Invalid reader result.");
}
}
}
// A WeakMap holding blob to byte array mapping.
// Ensures it does not impact garbage collection.
export const blobBytesWeakMap = new WeakMap<Blob, Uint8Array>();
class DenoBlob implements Blob {
[bytesSymbol]: Uint8Array;
readonly size: number = 0;
readonly type: string = "";
constructor(blobParts?: BlobPart[], options?: BlobPropertyBag) {
if (arguments.length === 0) {
this[bytesSymbol] = new Uint8Array();
return;
}
const { ending = "transparent", type = "" } = options ?? {};
// Normalize options.type.
let normalizedType = type;
if (!containsOnlyASCII(type)) {
normalizedType = "";
} else {
if (type.length) {
for (let i = 0; i < type.length; ++i) {
const char = type[i];
if (char < "\u0020" || char > "\u007E") {
normalizedType = "";
break;
}
}
normalizedType = type.toLowerCase();
}
}
const bytes = processBlobParts(blobParts!, { ending, type });
// Set Blob object's properties.
this[bytesSymbol] = bytes;
this.size = bytes.byteLength;
this.type = normalizedType;
}
slice(start?: number, end?: number, contentType?: string): DenoBlob {
return new DenoBlob([this[bytesSymbol].slice(start, end)], {
type: contentType || this.type,
});
}
stream(): ReadableStream<ArrayBufferView> {
return getStream(this[bytesSymbol]);
}
async text(): Promise<string> {
const reader = getStream(this[bytesSymbol]).getReader();
const decoder = new TextDecoder();
return decoder.decode(await readBytes(reader));
}
arrayBuffer(): Promise<ArrayBuffer> {
return readBytes(getStream(this[bytesSymbol]).getReader());
}
}
// we want the Base class name to be the name of the class.
Object.defineProperty(DenoBlob, "name", {
value: "Blob",
configurable: true,
});
export { DenoBlob };

View file

@ -1,213 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import * as blob from "./blob.ts";
import * as encoding from "./text_encoding.ts";
import type * as domTypes from "./dom_types.d.ts";
import { ReadableStreamImpl } from "./streams/readable_stream.ts";
import { isReadableStreamDisturbed } from "./streams/internals.ts";
import { Buffer } from "../buffer.ts";
import {
getHeaderValueParams,
hasHeaderValueOf,
isTypedArray,
} from "./util.ts";
import { MultipartParser } from "./fetch/multipart.ts";
// only namespace imports work for now, plucking out what we need
const { TextEncoder, TextDecoder } = encoding;
const DenoBlob = blob.DenoBlob;
interface BodyMeta {
contentType: string;
size?: number;
}
function validateBodyType(owner: Body, bodySource: BodyInit | null): boolean {
if (isTypedArray(bodySource)) {
return true;
} else if (bodySource instanceof ArrayBuffer) {
return true;
} else if (typeof bodySource === "string") {
return true;
} else if (bodySource instanceof ReadableStreamImpl) {
return true;
} else if (bodySource instanceof FormData) {
return true;
} else if (bodySource instanceof URLSearchParams) {
return true;
} else if (!bodySource) {
return true; // null body is fine
}
throw new Error(
`Bad ${owner.constructor.name} body type: ${bodySource.constructor.name}`,
);
}
async function bufferFromStream(
stream: ReadableStreamReader,
size?: number,
): Promise<ArrayBuffer> {
const encoder = new TextEncoder();
const buffer = new Buffer();
if (size) {
// grow to avoid unnecessary allocations & copies
buffer.grow(size);
}
while (true) {
const { done, value } = await stream.read();
if (done) break;
if (typeof value === "string") {
buffer.writeSync(encoder.encode(value));
} else if (value instanceof ArrayBuffer) {
buffer.writeSync(new Uint8Array(value));
} else if (value instanceof Uint8Array) {
buffer.writeSync(value);
} else if (!value) {
// noop for undefined
} else {
throw new Error("unhandled type on stream read");
}
}
return buffer.bytes().buffer;
}
export const BodyUsedError =
"Failed to execute 'clone' on 'Body': body is already used";
export class Body implements domTypes.Body {
protected _stream: ReadableStreamImpl<string | ArrayBuffer> | null;
#contentType: string;
#size: number | undefined;
constructor(protected _bodySource: BodyInit | null, meta: BodyMeta) {
validateBodyType(this, _bodySource);
this._bodySource = _bodySource;
this.#contentType = meta.contentType;
this.#size = meta.size;
this._stream = null;
}
get body(): ReadableStream | null {
if (this._stream) {
return this._stream;
}
if (this._bodySource instanceof ReadableStreamImpl) {
this._stream = this._bodySource;
}
if (typeof this._bodySource === "string") {
const bodySource = this._bodySource;
this._stream = new ReadableStreamImpl<string | ArrayBuffer>({
start(controller: ReadableStreamDefaultController): void {
controller.enqueue(bodySource);
controller.close();
},
});
}
return this._stream;
}
get bodyUsed(): boolean {
if (this.body && isReadableStreamDisturbed(this.body)) {
return true;
}
return false;
}
public async blob(): Promise<Blob> {
return new DenoBlob([await this.arrayBuffer()], {
type: this.#contentType,
});
}
// ref: https://fetch.spec.whatwg.org/#body-mixin
public async formData(): Promise<FormData> {
const formData = new FormData();
if (hasHeaderValueOf(this.#contentType, "multipart/form-data")) {
const params = getHeaderValueParams(this.#contentType);
// ref: https://tools.ietf.org/html/rfc2046#section-5.1
const boundary = params.get("boundary")!;
const body = new Uint8Array(await this.arrayBuffer());
const multipartParser = new MultipartParser(body, boundary);
return multipartParser.parse();
} else if (
hasHeaderValueOf(this.#contentType, "application/x-www-form-urlencoded")
) {
// From https://github.com/github/fetch/blob/master/fetch.js
// Copyright (c) 2014-2016 GitHub, Inc. MIT License
const body = await this.text();
try {
body
.trim()
.split("&")
.forEach((bytes): void => {
if (bytes) {
const split = bytes.split("=");
const name = split.shift()!.replace(/\+/g, " ");
const value = split.join("=").replace(/\+/g, " ");
formData.append(
decodeURIComponent(name),
decodeURIComponent(value),
);
}
});
} catch (e) {
throw new TypeError("Invalid form urlencoded format");
}
return formData;
} else {
throw new TypeError("Invalid form data");
}
}
public async text(): Promise<string> {
if (typeof this._bodySource === "string") {
return this._bodySource;
}
const ab = await this.arrayBuffer();
const decoder = new TextDecoder("utf-8");
return decoder.decode(ab);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public async json(): Promise<any> {
const raw = await this.text();
return JSON.parse(raw);
}
public arrayBuffer(): Promise<ArrayBuffer> {
if (isTypedArray(this._bodySource)) {
return Promise.resolve(this._bodySource.buffer as ArrayBuffer);
} else if (this._bodySource instanceof ArrayBuffer) {
return Promise.resolve(this._bodySource);
} else if (typeof this._bodySource === "string") {
const enc = new TextEncoder();
return Promise.resolve(
enc.encode(this._bodySource).buffer as ArrayBuffer,
);
} else if (this._bodySource instanceof ReadableStreamImpl) {
return bufferFromStream(this._bodySource.getReader(), this.#size);
} else if (
this._bodySource instanceof FormData ||
this._bodySource instanceof URLSearchParams
) {
const enc = new TextEncoder();
return Promise.resolve(
enc.encode(this._bodySource.toString()).buffer as ArrayBuffer,
);
} else if (!this._bodySource) {
return Promise.resolve(new ArrayBuffer(0));
}
throw new Error(
`Body type not yet implemented: ${this._bodySource.constructor.name}`,
);
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,130 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// Copyright Joyent, Inc. and other Node contributors. MIT license.
// Forked from Node's lib/internal/cli_table.js
import { hasOwnProperty } from "./util.ts";
import { stripColor } from "../colors.ts";
const tableChars = {
middleMiddle: "─",
rowMiddle: "┼",
topRight: "┐",
topLeft: "┌",
leftMiddle: "├",
topMiddle: "┬",
bottomRight: "┘",
bottomLeft: "└",
bottomMiddle: "┴",
rightMiddle: "┤",
left: "│ ",
right: " │",
middle: " │ ",
};
function isFullWidthCodePoint(code: number): boolean {
// Code points are partially derived from:
// http://www.unicode.org/Public/UNIDATA/EastAsianWidth.txt
return (
code >= 0x1100 &&
(code <= 0x115f || // Hangul Jamo
code === 0x2329 || // LEFT-POINTING ANGLE BRACKET
code === 0x232a || // RIGHT-POINTING ANGLE BRACKET
// CJK Radicals Supplement .. Enclosed CJK Letters and Months
(code >= 0x2e80 && code <= 0x3247 && code !== 0x303f) ||
// Enclosed CJK Letters and Months .. CJK Unified Ideographs Extension A
(code >= 0x3250 && code <= 0x4dbf) ||
// CJK Unified Ideographs .. Yi Radicals
(code >= 0x4e00 && code <= 0xa4c6) ||
// Hangul Jamo Extended-A
(code >= 0xa960 && code <= 0xa97c) ||
// Hangul Syllables
(code >= 0xac00 && code <= 0xd7a3) ||
// CJK Compatibility Ideographs
(code >= 0xf900 && code <= 0xfaff) ||
// Vertical Forms
(code >= 0xfe10 && code <= 0xfe19) ||
// CJK Compatibility Forms .. Small Form Variants
(code >= 0xfe30 && code <= 0xfe6b) ||
// Halfwidth and Fullwidth Forms
(code >= 0xff01 && code <= 0xff60) ||
(code >= 0xffe0 && code <= 0xffe6) ||
// Kana Supplement
(code >= 0x1b000 && code <= 0x1b001) ||
// Enclosed Ideographic Supplement
(code >= 0x1f200 && code <= 0x1f251) ||
// Miscellaneous Symbols and Pictographs 0x1f300 - 0x1f5ff
// Emoticons 0x1f600 - 0x1f64f
(code >= 0x1f300 && code <= 0x1f64f) ||
// CJK Unified Ideographs Extension B .. Tertiary Ideographic Plane
(code >= 0x20000 && code <= 0x3fffd))
);
}
function getStringWidth(str: string): number {
str = stripColor(str).normalize("NFC");
let width = 0;
for (const ch of str) {
width += isFullWidthCodePoint(ch.codePointAt(0)!) ? 2 : 1;
}
return width;
}
function renderRow(row: string[], columnWidths: number[]): string {
let out = tableChars.left;
for (let i = 0; i < row.length; i++) {
const cell = row[i];
const len = getStringWidth(cell);
const needed = (columnWidths[i] - len) / 2;
// round(needed) + ceil(needed) will always add up to the amount
// of spaces we need while also left justifying the output.
out += `${" ".repeat(needed)}${cell}${" ".repeat(Math.ceil(needed))}`;
if (i !== row.length - 1) {
out += tableChars.middle;
}
}
out += tableChars.right;
return out;
}
export function cliTable(head: string[], columns: string[][]): string {
const rows: string[][] = [];
const columnWidths = head.map((h: string): number => getStringWidth(h));
const longestColumn = columns.reduce(
(n: number, a: string[]): number => Math.max(n, a.length),
0,
);
for (let i = 0; i < head.length; i++) {
const column = columns[i];
for (let j = 0; j < longestColumn; j++) {
if (rows[j] === undefined) {
rows[j] = [];
}
const value = (rows[j][i] = hasOwnProperty(column, j) ? column[j] : "");
const width = columnWidths[i] || 0;
const counted = getStringWidth(value);
columnWidths[i] = Math.max(width, counted);
}
}
const divider = columnWidths.map((i: number): string =>
tableChars.middleMiddle.repeat(i + 2)
);
let result = `${tableChars.topLeft}${divider.join(tableChars.topMiddle)}` +
`${tableChars.topRight}\n${renderRow(head, columnWidths)}\n` +
`${tableChars.leftMiddle}${divider.join(tableChars.rowMiddle)}` +
`${tableChars.rightMiddle}\n`;
for (const row of rows) {
result += `${renderRow(row, columnWidths)}\n`;
}
result += `${tableChars.bottomLeft}${divider.join(tableChars.bottomMiddle)}` +
tableChars.bottomRight;
return result;
}

View file

@ -1,29 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { EventImpl as Event } from "./event.ts";
import { requiredArguments } from "./util.ts";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export class CustomEventImpl<T = any> extends Event implements CustomEvent {
readonly #detail: T;
constructor(type: string, eventInitDict: CustomEventInit<T> = {}) {
super(type, eventInitDict);
requiredArguments("CustomEvent", arguments.length, 1);
const { detail } = eventInitDict;
this.#detail = detail as T;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
get detail(): T {
return this.#detail;
}
get [Symbol.toStringTag](): string {
return "CustomEvent";
}
}
Reflect.defineProperty(CustomEventImpl.prototype, "detail", {
enumerable: true,
});

View file

@ -1,135 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// This module is based on Bjoern Hoehrmann's DFA UTF-8 decoder.
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
//
// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
//
// 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.
// `.apply` can actually take a typed array, though the type system doesn't
// really support it, so we have to "hack" it a bit to get past some of the
// strict type checks.
declare global {
interface CallableFunction extends Function {
apply<T, R>(
this: (this: T, ...args: number[]) => R,
thisArg: T,
args: Uint16Array,
): R;
}
}
export function decodeUtf8(
input: Uint8Array,
fatal: boolean,
ignoreBOM: boolean,
): string {
let outString = "";
// Prepare a buffer so that we don't have to do a lot of string concats, which
// are very slow.
const outBufferLength: number = Math.min(1024, input.length);
const outBuffer = new Uint16Array(outBufferLength);
let outIndex = 0;
let state = 0;
let codepoint = 0;
let type: number;
let i =
ignoreBOM && input[0] === 0xef && input[1] === 0xbb && input[2] === 0xbf
? 3
: 0;
for (; i < input.length; ++i) {
// Encoding error handling
if (state === 12 || (state !== 0 && (input[i] & 0xc0) !== 0x80)) {
if (fatal) {
throw new TypeError(
`Decoder error. Invalid byte in sequence at position ${i} in data.`,
);
}
outBuffer[outIndex++] = 0xfffd; // Replacement character
if (outIndex === outBufferLength) {
outString += String.fromCharCode.apply(null, outBuffer);
outIndex = 0;
}
state = 0;
}
// deno-fmt-ignore
type = [
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8
][input[i]];
codepoint = state !== 0
? (input[i] & 0x3f) | (codepoint << 6)
: (0xff >> type) & input[i];
// deno-fmt-ignore
state = [
0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
12,36,12,12,12,12,12,12,12,12,12,12
][state + type];
if (state !== 0) continue;
// Add codepoint to buffer (as charcodes for utf-16), and flush buffer to
// string if needed.
if (codepoint > 0xffff) {
outBuffer[outIndex++] = 0xd7c0 + (codepoint >> 10);
if (outIndex === outBufferLength) {
outString += String.fromCharCode.apply(null, outBuffer);
outIndex = 0;
}
outBuffer[outIndex++] = 0xdc00 | (codepoint & 0x3ff);
if (outIndex === outBufferLength) {
outString += String.fromCharCode.apply(null, outBuffer);
outIndex = 0;
}
} else {
outBuffer[outIndex++] = codepoint;
if (outIndex === outBufferLength) {
outString += String.fromCharCode.apply(null, outBuffer);
outIndex = 0;
}
}
}
// Add a replacement character if we ended in the middle of a sequence or
// encountered an invalid code at the end.
if (state !== 0) {
if (fatal) throw new TypeError(`Decoder error. Unexpected end of data.`);
outBuffer[outIndex++] = 0xfffd; // Replacement character
}
// Final flush of buffer
outString += String.fromCharCode.apply(null, outBuffer.subarray(0, outIndex));
return outString;
}

View file

@ -1,24 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import * as blob from "./blob.ts";
export class DomFileImpl extends blob.DenoBlob implements File {
lastModified: number;
name: string;
constructor(
fileBits: BlobPart[],
fileName: string,
options?: FilePropertyBag,
) {
const { lastModified = Date.now(), ...blobPropertyBag } = options ?? {};
super(fileBits, blobPropertyBag);
// 4.1.2.1 Replace any "/" character (U+002F SOLIDUS)
// with a ":" (U + 003A COLON)
this.name = String(fileName).replace(/\u002F/g, "\u003A");
// 4.1.3.3 If lastModified is not provided, set lastModified to the current
// date and time represented in number of milliseconds since the Unix Epoch.
this.lastModified = lastModified;
}
}

View file

@ -1,92 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { requiredArguments } from "./util.ts";
import { exposeForTest } from "../internals.ts";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type Constructor<T = {}> = new (...args: any[]) => T;
export interface DomIterable<K, V> {
keys(): IterableIterator<K>;
values(): IterableIterator<V>;
entries(): IterableIterator<[K, V]>;
[Symbol.iterator](): IterableIterator<[K, V]>;
forEach(
callback: (value: V, key: K, parent: this) => void,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
thisArg?: any,
): void;
}
export function DomIterableMixin<K, V, TBase extends Constructor>(
Base: TBase,
dataSymbol: symbol,
): TBase & Constructor<DomIterable<K, V>> {
// we have to cast `this` as `any` because there is no way to describe the
// Base class in a way where the Symbol `dataSymbol` is defined. So the
// runtime code works, but we do lose a little bit of type safety.
// Additionally, we have to not use .keys() nor .values() since the internal
// slot differs in type - some have a Map, which yields [K, V] in
// Symbol.iterator, and some have an Array, which yields V, in this case
// [K, V] too as they are arrays of tuples.
const DomIterable = class extends Base {
*entries(): IterableIterator<[K, V]> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
for (const entry of (this as any)[dataSymbol]) {
yield entry;
}
}
*keys(): IterableIterator<K> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
for (const [key] of (this as any)[dataSymbol]) {
yield key;
}
}
*values(): IterableIterator<V> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
for (const [, value] of (this as any)[dataSymbol]) {
yield value;
}
}
forEach(
callbackfn: (value: V, key: K, parent: this) => void,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
thisArg?: any,
): void {
requiredArguments(
`${this.constructor.name}.forEach`,
arguments.length,
1,
);
callbackfn = callbackfn.bind(
thisArg == null ? globalThis : Object(thisArg),
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
for (const [key, value] of (this as any)[dataSymbol]) {
callbackfn(value, key, this);
}
}
*[Symbol.iterator](): IterableIterator<[K, V]> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
for (const entry of (this as any)[dataSymbol]) {
yield entry;
}
}
};
// we want the Base class name to be the name of the class.
Object.defineProperty(DomIterable, "name", {
value: Base.name,
configurable: true,
});
return DomIterable;
}
exposeForTest("DomIterableMixin", DomIterableMixin);

View file

@ -1,318 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
/*! ****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
*******************************************************************************/
/* eslint-disable @typescript-eslint/no-explicit-any */
export type RequestInfo = Request | string;
export interface ProgressEventInit extends EventInit {
lengthComputable?: boolean;
loaded?: number;
total?: number;
}
export interface UIEventInit extends EventInit {
detail?: number;
// adjust Window -> Node
view?: Node | null;
}
export class UIEvent extends Event {
constructor(type: string, eventInitDict?: UIEventInit);
readonly detail: number;
// adjust Window -> Node
readonly view: Node | null;
}
export interface FocusEventInit extends UIEventInit {
relatedTarget?: EventTarget | null;
}
export class FocusEvent extends UIEvent {
constructor(type: string, eventInitDict?: FocusEventInit);
readonly relatedTarget: EventTarget | null;
}
export interface EventModifierInit extends UIEventInit {
altKey?: boolean;
ctrlKey?: boolean;
metaKey?: boolean;
modifierAltGraph?: boolean;
modifierCapsLock?: boolean;
modifierFn?: boolean;
modifierFnLock?: boolean;
modifierHyper?: boolean;
modifierNumLock?: boolean;
modifierScrollLock?: boolean;
modifierSuper?: boolean;
modifierSymbol?: boolean;
modifierSymbolLock?: boolean;
shiftKey?: boolean;
}
export interface MouseEventInit extends EventModifierInit {
button?: number;
buttons?: number;
clientX?: number;
clientY?: number;
movementX?: number;
movementY?: number;
relatedTarget?: EventTarget | null;
screenX?: number;
screenY?: number;
}
export class MouseEvent extends UIEvent {
constructor(type: string, eventInitDict?: MouseEventInit);
readonly altKey: boolean;
readonly button: number;
readonly buttons: number;
readonly clientX: number;
readonly clientY: number;
readonly ctrlKey: boolean;
readonly metaKey: boolean;
readonly movementX: number;
readonly movementY: number;
readonly offsetX: number;
readonly offsetY: number;
readonly pageX: number;
readonly pageY: number;
readonly relatedTarget: EventTarget | null;
readonly screenX: number;
readonly screenY: number;
readonly shiftKey: boolean;
readonly x: number;
readonly y: number;
getModifierState(keyArg: string): boolean;
}
interface GetRootNodeOptions {
composed?: boolean;
}
export class Node extends EventTarget {
readonly baseURI: string;
readonly childNodes: NodeListOf<ChildNode>;
readonly firstChild: ChildNode | null;
readonly isConnected: boolean;
readonly lastChild: ChildNode | null;
readonly nextSibling: ChildNode | null;
readonly nodeName: string;
readonly nodeType: number;
nodeValue: string | null;
// adjusted: Document -> Node
readonly ownerDocument: Node | null;
// adjusted: HTMLElement -> Node
readonly parentElement: Node | null;
readonly parentNode: (Node & ParentNode) | null;
readonly previousSibling: ChildNode | null;
textContent: string | null;
appendChild<T extends Node>(newChild: T): T;
cloneNode(deep?: boolean): Node;
compareDocumentPosition(other: Node): number;
contains(other: Node | null): boolean;
getRootNode(options?: GetRootNodeOptions): Node;
hasChildNodes(): boolean;
insertBefore<T extends Node>(newChild: T, refChild: Node | null): T;
isDefaultNamespace(namespace: string | null): boolean;
isEqualNode(otherNode: Node | null): boolean;
isSameNode(otherNode: Node | null): boolean;
lookupNamespaceURI(prefix: string | null): string | null;
lookupPrefix(namespace: string | null): string | null;
normalize(): void;
removeChild<T extends Node>(oldChild: T): T;
replaceChild<T extends Node>(newChild: Node, oldChild: T): T;
readonly ATTRIBUTE_NODE: number;
readonly CDATA_SECTION_NODE: number;
readonly COMMENT_NODE: number;
readonly DOCUMENT_FRAGMENT_NODE: number;
readonly DOCUMENT_NODE: number;
readonly DOCUMENT_POSITION_CONTAINED_BY: number;
readonly DOCUMENT_POSITION_CONTAINS: number;
readonly DOCUMENT_POSITION_DISCONNECTED: number;
readonly DOCUMENT_POSITION_FOLLOWING: number;
readonly DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: number;
readonly DOCUMENT_POSITION_PRECEDING: number;
readonly DOCUMENT_TYPE_NODE: number;
readonly ELEMENT_NODE: number;
readonly ENTITY_NODE: number;
readonly ENTITY_REFERENCE_NODE: number;
readonly NOTATION_NODE: number;
readonly PROCESSING_INSTRUCTION_NODE: number;
readonly TEXT_NODE: number;
static readonly ATTRIBUTE_NODE: number;
static readonly CDATA_SECTION_NODE: number;
static readonly COMMENT_NODE: number;
static readonly DOCUMENT_FRAGMENT_NODE: number;
static readonly DOCUMENT_NODE: number;
static readonly DOCUMENT_POSITION_CONTAINED_BY: number;
static readonly DOCUMENT_POSITION_CONTAINS: number;
static readonly DOCUMENT_POSITION_DISCONNECTED: number;
static readonly DOCUMENT_POSITION_FOLLOWING: number;
static readonly DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: number;
static readonly DOCUMENT_POSITION_PRECEDING: number;
static readonly DOCUMENT_TYPE_NODE: number;
static readonly ELEMENT_NODE: number;
static readonly ENTITY_NODE: number;
static readonly ENTITY_REFERENCE_NODE: number;
static readonly NOTATION_NODE: number;
static readonly PROCESSING_INSTRUCTION_NODE: number;
static readonly TEXT_NODE: number;
}
interface Slotable {
// adjusted: HTMLSlotElement -> Node
readonly assignedSlot: Node | null;
}
interface ChildNode extends Node {
after(...nodes: Array<Node | string>): void;
before(...nodes: Array<Node | string>): void;
remove(): void;
replaceWith(...nodes: Array<Node | string>): void;
}
interface ParentNode {
readonly childElementCount: number;
// not currently supported
// readonly children: HTMLCollection;
// adjusted: Element -> Node
readonly firstElementChild: Node | null;
// adjusted: Element -> Node
readonly lastElementChild: Node | null;
append(...nodes: Array<Node | string>): void;
prepend(...nodes: Array<Node | string>): void;
// not currently supported
// querySelector<K extends keyof HTMLElementTagNameMap>(
// selectors: K,
// ): HTMLElementTagNameMap[K] | null;
// querySelector<K extends keyof SVGElementTagNameMap>(
// selectors: K,
// ): SVGElementTagNameMap[K] | null;
// querySelector<E extends Element = Element>(selectors: string): E | null;
// querySelectorAll<K extends keyof HTMLElementTagNameMap>(
// selectors: K,
// ): NodeListOf<HTMLElementTagNameMap[K]>;
// querySelectorAll<K extends keyof SVGElementTagNameMap>(
// selectors: K,
// ): NodeListOf<SVGElementTagNameMap[K]>;
// querySelectorAll<E extends Element = Element>(
// selectors: string,
// ): NodeListOf<E>;
}
interface NodeList {
readonly length: number;
item(index: number): Node | null;
forEach(
callbackfn: (value: Node, key: number, parent: NodeList) => void,
thisArg?: any,
): void;
[index: number]: Node;
[Symbol.iterator](): IterableIterator<Node>;
entries(): IterableIterator<[number, Node]>;
keys(): IterableIterator<number>;
values(): IterableIterator<Node>;
}
interface NodeListOf<TNode extends Node> extends NodeList {
length: number;
item(index: number): TNode;
forEach(
callbackfn: (value: TNode, key: number, parent: NodeListOf<TNode>) => void,
thisArg?: any,
): void;
[index: number]: TNode;
[Symbol.iterator](): IterableIterator<TNode>;
entries(): IterableIterator<[number, TNode]>;
keys(): IterableIterator<number>;
values(): IterableIterator<TNode>;
}
export interface Body {
readonly body: ReadableStream<Uint8Array> | null;
readonly bodyUsed: boolean;
arrayBuffer(): Promise<ArrayBuffer>;
blob(): Promise<Blob>;
formData(): Promise<FormData>;
json(): Promise<any>;
text(): Promise<string>;
}
export interface RequestInit {
body?: BodyInit | null;
cache?: RequestCache;
credentials?: RequestCredentials;
headers?: HeadersInit;
integrity?: string;
keepalive?: boolean;
method?: string;
mode?: RequestMode;
redirect?: RequestRedirect;
referrer?: string;
referrerPolicy?: ReferrerPolicy;
signal?: AbortSignal | null;
window?: any;
}
export interface ResponseInit {
headers?: HeadersInit;
status?: number;
statusText?: string;
}
export interface Request extends Body {
readonly cache?: RequestCache;
readonly credentials?: RequestCredentials;
readonly destination?: RequestDestination;
readonly headers: Headers;
readonly integrity?: string;
readonly isHistoryNavigation?: boolean;
readonly isReloadNavigation?: boolean;
readonly keepalive?: boolean;
readonly method: string;
readonly mode?: RequestMode;
readonly redirect?: RequestRedirect;
readonly referrer?: string;
readonly referrerPolicy?: ReferrerPolicy;
readonly signal?: AbortSignal;
readonly url: string;
clone(): Request;
}
export interface RequestConstructor {
new (input: RequestInfo, init?: RequestInit): Request;
prototype: Request;
}
export interface Response extends Body {
readonly headers: Headers;
readonly ok: boolean;
readonly redirected: boolean;
readonly status: number;
readonly statusText: string;
readonly type: ResponseType;
readonly url: string;
clone(): Response;
}
export interface ResponseConstructor {
prototype: Response;
new (body?: BodyInit | null, init?: ResponseInit): Response;
error(): Response;
redirect(url: string, status?: number): Response;
}

View file

@ -1,18 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
export function getDOMStringList(arr: string[]): DOMStringList {
Object.defineProperties(arr, {
contains: {
value(searchElement: string): boolean {
return arr.includes(searchElement);
},
enumerable: true,
},
item: {
value(idx: number): string | null {
return idx in arr ? arr[idx] : null;
},
},
});
return arr as string[] & DOMStringList;
}

View file

@ -1,68 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { EventImpl as Event } from "./event.ts";
import { defineEnumerableProps } from "./util.ts";
export class ErrorEventImpl extends Event implements ErrorEvent {
readonly #message: string;
readonly #filename: string;
readonly #lineno: number;
readonly #colno: number;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
readonly #error: any;
get message(): string {
return this.#message;
}
get filename(): string {
return this.#filename;
}
get lineno(): number {
return this.#lineno;
}
get colno(): number {
return this.#colno;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
get error(): any {
return this.#error;
}
constructor(
type: string,
{
bubbles,
cancelable,
composed,
message = "",
filename = "",
lineno = 0,
colno = 0,
error = null,
}: ErrorEventInit = {},
) {
super(type, {
bubbles: bubbles,
cancelable: cancelable,
composed: composed,
});
this.#message = message;
this.#filename = filename;
this.#lineno = lineno;
this.#colno = colno;
this.#error = error;
}
get [Symbol.toStringTag](): string {
return "ErrorEvent";
}
}
defineEnumerableProps(ErrorEventImpl, [
"message",
"filename",
"lineno",
"colno",
"error",
]);

View file

@ -1,406 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import type * as domTypes from "./dom_types.d.ts";
import { defineEnumerableProps, requiredArguments } from "./util.ts";
import { assert } from "../util.ts";
/** Stores a non-accessible view of the event path which is used internally in
* the logic for determining the path of an event. */
export interface EventPath {
item: EventTarget;
itemInShadowTree: boolean;
relatedTarget: EventTarget | null;
rootOfClosedTree: boolean;
slotInClosedTree: boolean;
target: EventTarget | null;
touchTargetList: EventTarget[];
}
interface EventAttributes {
type: string;
bubbles: boolean;
cancelable: boolean;
composed: boolean;
currentTarget: EventTarget | null;
eventPhase: number;
target: EventTarget | null;
timeStamp: number;
}
interface EventData {
dispatched: boolean;
inPassiveListener: boolean;
isTrusted: boolean;
path: EventPath[];
stopImmediatePropagation: boolean;
}
const eventData = new WeakMap<Event, EventData>();
// accessors for non runtime visible data
export function getDispatched(event: Event): boolean {
return Boolean(eventData.get(event)?.dispatched);
}
export function getPath(event: Event): EventPath[] {
return eventData.get(event)?.path ?? [];
}
export function getStopImmediatePropagation(event: Event): boolean {
return Boolean(eventData.get(event)?.stopImmediatePropagation);
}
export function setCurrentTarget(
event: Event,
value: EventTarget | null,
): void {
(event as EventImpl).currentTarget = value;
}
export function setDispatched(event: Event, value: boolean): void {
const data = eventData.get(event as Event);
if (data) {
data.dispatched = value;
}
}
export function setEventPhase(event: Event, value: number): void {
(event as EventImpl).eventPhase = value;
}
export function setInPassiveListener(event: Event, value: boolean): void {
const data = eventData.get(event as Event);
if (data) {
data.inPassiveListener = value;
}
}
export function setPath(event: Event, value: EventPath[]): void {
const data = eventData.get(event as Event);
if (data) {
data.path = value;
}
}
export function setRelatedTarget<T extends Event>(
event: T,
value: EventTarget | null,
): void {
if ("relatedTarget" in event) {
(event as T & {
relatedTarget: EventTarget | null;
}).relatedTarget = value;
}
}
export function setTarget(event: Event, value: EventTarget | null): void {
(event as EventImpl).target = value;
}
export function setStopImmediatePropagation(
event: Event,
value: boolean,
): void {
const data = eventData.get(event as Event);
if (data) {
data.stopImmediatePropagation = value;
}
}
// Type guards that widen the event type
export function hasRelatedTarget(
event: Event,
): event is domTypes.FocusEvent | domTypes.MouseEvent {
return "relatedTarget" in event;
}
function isTrusted(this: Event): boolean {
return eventData.get(this)!.isTrusted;
}
export class EventImpl implements Event {
// The default value is `false`.
// Use `defineProperty` to define on each instance, NOT on the prototype.
isTrusted!: boolean;
#canceledFlag = false;
#stopPropagationFlag = false;
#attributes: EventAttributes;
constructor(type: string, eventInitDict: EventInit = {}) {
requiredArguments("Event", arguments.length, 1);
type = String(type);
this.#attributes = {
type,
bubbles: eventInitDict.bubbles ?? false,
cancelable: eventInitDict.cancelable ?? false,
composed: eventInitDict.composed ?? false,
currentTarget: null,
eventPhase: Event.NONE,
target: null,
timeStamp: Date.now(),
};
eventData.set(this, {
dispatched: false,
inPassiveListener: false,
isTrusted: false,
path: [],
stopImmediatePropagation: false,
});
Reflect.defineProperty(this, "isTrusted", {
enumerable: true,
get: isTrusted,
});
}
get bubbles(): boolean {
return this.#attributes.bubbles;
}
get cancelBubble(): boolean {
return this.#stopPropagationFlag;
}
set cancelBubble(value: boolean) {
this.#stopPropagationFlag = value;
}
get cancelable(): boolean {
return this.#attributes.cancelable;
}
get composed(): boolean {
return this.#attributes.composed;
}
get currentTarget(): EventTarget | null {
return this.#attributes.currentTarget;
}
set currentTarget(value: EventTarget | null) {
this.#attributes = {
type: this.type,
bubbles: this.bubbles,
cancelable: this.cancelable,
composed: this.composed,
currentTarget: value,
eventPhase: this.eventPhase,
target: this.target,
timeStamp: this.timeStamp,
};
}
get defaultPrevented(): boolean {
return this.#canceledFlag;
}
get eventPhase(): number {
return this.#attributes.eventPhase;
}
set eventPhase(value: number) {
this.#attributes = {
type: this.type,
bubbles: this.bubbles,
cancelable: this.cancelable,
composed: this.composed,
currentTarget: this.currentTarget,
eventPhase: value,
target: this.target,
timeStamp: this.timeStamp,
};
}
get initialized(): boolean {
return true;
}
get target(): EventTarget | null {
return this.#attributes.target;
}
set target(value: EventTarget | null) {
this.#attributes = {
type: this.type,
bubbles: this.bubbles,
cancelable: this.cancelable,
composed: this.composed,
currentTarget: this.currentTarget,
eventPhase: this.eventPhase,
target: value,
timeStamp: this.timeStamp,
};
}
get timeStamp(): number {
return this.#attributes.timeStamp;
}
get type(): string {
return this.#attributes.type;
}
composedPath(): EventTarget[] {
const path = eventData.get(this)!.path;
if (path.length === 0) {
return [];
}
assert(this.currentTarget);
const composedPath: EventPath[] = [
{
item: this.currentTarget,
itemInShadowTree: false,
relatedTarget: null,
rootOfClosedTree: false,
slotInClosedTree: false,
target: null,
touchTargetList: [],
},
];
let currentTargetIndex = 0;
let currentTargetHiddenSubtreeLevel = 0;
for (let index = path.length - 1; index >= 0; index--) {
const { item, rootOfClosedTree, slotInClosedTree } = path[index];
if (rootOfClosedTree) {
currentTargetHiddenSubtreeLevel++;
}
if (item === this.currentTarget) {
currentTargetIndex = index;
break;
}
if (slotInClosedTree) {
currentTargetHiddenSubtreeLevel--;
}
}
let currentHiddenLevel = currentTargetHiddenSubtreeLevel;
let maxHiddenLevel = currentTargetHiddenSubtreeLevel;
for (let i = currentTargetIndex - 1; i >= 0; i--) {
const { item, rootOfClosedTree, slotInClosedTree } = path[i];
if (rootOfClosedTree) {
currentHiddenLevel++;
}
if (currentHiddenLevel <= maxHiddenLevel) {
composedPath.unshift({
item,
itemInShadowTree: false,
relatedTarget: null,
rootOfClosedTree: false,
slotInClosedTree: false,
target: null,
touchTargetList: [],
});
}
if (slotInClosedTree) {
currentHiddenLevel--;
if (currentHiddenLevel < maxHiddenLevel) {
maxHiddenLevel = currentHiddenLevel;
}
}
}
currentHiddenLevel = currentTargetHiddenSubtreeLevel;
maxHiddenLevel = currentTargetHiddenSubtreeLevel;
for (let index = currentTargetIndex + 1; index < path.length; index++) {
const { item, rootOfClosedTree, slotInClosedTree } = path[index];
if (slotInClosedTree) {
currentHiddenLevel++;
}
if (currentHiddenLevel <= maxHiddenLevel) {
composedPath.push({
item,
itemInShadowTree: false,
relatedTarget: null,
rootOfClosedTree: false,
slotInClosedTree: false,
target: null,
touchTargetList: [],
});
}
if (rootOfClosedTree) {
currentHiddenLevel--;
if (currentHiddenLevel < maxHiddenLevel) {
maxHiddenLevel = currentHiddenLevel;
}
}
}
return composedPath.map((p) => p.item);
}
preventDefault(): void {
if (this.cancelable && !eventData.get(this)!.inPassiveListener) {
this.#canceledFlag = true;
}
}
stopPropagation(): void {
this.#stopPropagationFlag = true;
}
stopImmediatePropagation(): void {
this.#stopPropagationFlag = true;
eventData.get(this)!.stopImmediatePropagation = true;
}
get NONE(): number {
return Event.NONE;
}
get CAPTURING_PHASE(): number {
return Event.CAPTURING_PHASE;
}
get AT_TARGET(): number {
return Event.AT_TARGET;
}
get BUBBLING_PHASE(): number {
return Event.BUBBLING_PHASE;
}
static get NONE(): number {
return 0;
}
static get CAPTURING_PHASE(): number {
return 1;
}
static get AT_TARGET(): number {
return 2;
}
static get BUBBLING_PHASE(): number {
return 3;
}
}
defineEnumerableProps(EventImpl, [
"bubbles",
"cancelable",
"composed",
"currentTarget",
"defaultPrevented",
"eventPhase",
"target",
"timeStamp",
"type",
]);

View file

@ -1,588 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// This module follows most of the WHATWG Living Standard for the DOM logic.
// Many parts of the DOM are not implemented in Deno, but the logic for those
// parts still exists. This means you will observe a lot of strange structures
// and impossible logic branches based on what Deno currently supports.
import { DOMExceptionImpl as DOMException } from "./dom_exception.ts";
import type * as domTypes from "./dom_types.d.ts";
import {
EventImpl as Event,
EventPath,
getDispatched,
getPath,
getStopImmediatePropagation,
hasRelatedTarget,
setCurrentTarget,
setDispatched,
setEventPhase,
setInPassiveListener,
setPath,
setRelatedTarget,
setStopImmediatePropagation,
setTarget,
} from "./event.ts";
import { defineEnumerableProps, requiredArguments } from "./util.ts";
// This is currently the only node type we are using, so instead of implementing
// the whole of the Node interface at the moment, this just gives us the one
// value to power the standards based logic
const DOCUMENT_FRAGMENT_NODE = 11;
// DOM Logic Helper functions and type guards
/** Get the parent node, for event targets that have a parent.
*
* Ref: https://dom.spec.whatwg.org/#get-the-parent */
function getParent(eventTarget: EventTarget): EventTarget | null {
return isNode(eventTarget) ? eventTarget.parentNode : null;
}
function getRoot(eventTarget: EventTarget): EventTarget | null {
return isNode(eventTarget)
? eventTarget.getRootNode({ composed: true })
: null;
}
function isNode<T extends EventTarget>(
eventTarget: T | null,
): eventTarget is T & domTypes.Node {
return Boolean(eventTarget && "nodeType" in eventTarget);
}
// https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-ancestor
function isShadowInclusiveAncestor(
ancestor: EventTarget | null,
node: EventTarget | null,
): boolean {
while (isNode(node)) {
if (node === ancestor) {
return true;
}
if (isShadowRoot(node)) {
node = node && getHost(node);
} else {
node = getParent(node);
}
}
return false;
}
function isShadowRoot(nodeImpl: EventTarget | null): boolean {
return Boolean(
nodeImpl &&
isNode(nodeImpl) &&
nodeImpl.nodeType === DOCUMENT_FRAGMENT_NODE &&
getHost(nodeImpl) != null,
);
}
function isSlotable<T extends EventTarget>(
nodeImpl: T | null,
): nodeImpl is T & domTypes.Node & domTypes.Slotable {
return Boolean(isNode(nodeImpl) && "assignedSlot" in nodeImpl);
}
// DOM Logic functions
/** Append a path item to an event's path.
*
* Ref: https://dom.spec.whatwg.org/#concept-event-path-append
*/
function appendToEventPath(
eventImpl: Event,
target: EventTarget,
targetOverride: EventTarget | null,
relatedTarget: EventTarget | null,
touchTargets: EventTarget[],
slotInClosedTree: boolean,
): void {
const itemInShadowTree = isNode(target) && isShadowRoot(getRoot(target));
const rootOfClosedTree = isShadowRoot(target) && getMode(target) === "closed";
getPath(eventImpl).push({
item: target,
itemInShadowTree,
target: targetOverride,
relatedTarget,
touchTargetList: touchTargets,
rootOfClosedTree,
slotInClosedTree,
});
}
function dispatch(
targetImpl: EventTarget,
eventImpl: Event,
targetOverride?: EventTarget,
): boolean {
let clearTargets = false;
let activationTarget: EventTarget | null = null;
setDispatched(eventImpl, true);
targetOverride = targetOverride ?? targetImpl;
const eventRelatedTarget = hasRelatedTarget(eventImpl)
? eventImpl.relatedTarget
: null;
let relatedTarget = retarget(eventRelatedTarget, targetImpl);
if (targetImpl !== relatedTarget || targetImpl === eventRelatedTarget) {
const touchTargets: EventTarget[] = [];
appendToEventPath(
eventImpl,
targetImpl,
targetOverride,
relatedTarget,
touchTargets,
false,
);
const isActivationEvent = eventImpl.type === "click";
if (isActivationEvent && getHasActivationBehavior(targetImpl)) {
activationTarget = targetImpl;
}
let slotInClosedTree = false;
let slotable = isSlotable(targetImpl) && getAssignedSlot(targetImpl)
? targetImpl
: null;
let parent = getParent(targetImpl);
// Populate event path
// https://dom.spec.whatwg.org/#event-path
while (parent !== null) {
if (slotable !== null) {
slotable = null;
const parentRoot = getRoot(parent);
if (
isShadowRoot(parentRoot) &&
parentRoot &&
getMode(parentRoot) === "closed"
) {
slotInClosedTree = true;
}
}
relatedTarget = retarget(eventRelatedTarget, parent);
if (
isNode(parent) &&
isShadowInclusiveAncestor(getRoot(targetImpl), parent)
) {
appendToEventPath(
eventImpl,
parent,
null,
relatedTarget,
touchTargets,
slotInClosedTree,
);
} else if (parent === relatedTarget) {
parent = null;
} else {
targetImpl = parent;
if (
isActivationEvent &&
activationTarget === null &&
getHasActivationBehavior(targetImpl)
) {
activationTarget = targetImpl;
}
appendToEventPath(
eventImpl,
parent,
targetImpl,
relatedTarget,
touchTargets,
slotInClosedTree,
);
}
if (parent !== null) {
parent = getParent(parent);
}
slotInClosedTree = false;
}
let clearTargetsTupleIndex = -1;
const path = getPath(eventImpl);
for (
let i = path.length - 1;
i >= 0 && clearTargetsTupleIndex === -1;
i--
) {
if (path[i].target !== null) {
clearTargetsTupleIndex = i;
}
}
const clearTargetsTuple = path[clearTargetsTupleIndex];
clearTargets = (isNode(clearTargetsTuple.target) &&
isShadowRoot(getRoot(clearTargetsTuple.target))) ||
(isNode(clearTargetsTuple.relatedTarget) &&
isShadowRoot(getRoot(clearTargetsTuple.relatedTarget)));
setEventPhase(eventImpl, Event.CAPTURING_PHASE);
for (let i = path.length - 1; i >= 0; --i) {
const tuple = path[i];
if (tuple.target === null) {
invokeEventListeners(tuple, eventImpl);
}
}
for (let i = 0; i < path.length; i++) {
const tuple = path[i];
if (tuple.target !== null) {
setEventPhase(eventImpl, Event.AT_TARGET);
} else {
setEventPhase(eventImpl, Event.BUBBLING_PHASE);
}
if (
(eventImpl.eventPhase === Event.BUBBLING_PHASE && eventImpl.bubbles) ||
eventImpl.eventPhase === Event.AT_TARGET
) {
invokeEventListeners(tuple, eventImpl);
}
}
}
setEventPhase(eventImpl, Event.NONE);
setCurrentTarget(eventImpl, null);
setPath(eventImpl, []);
setDispatched(eventImpl, false);
eventImpl.cancelBubble = false;
setStopImmediatePropagation(eventImpl, false);
if (clearTargets) {
setTarget(eventImpl, null);
setRelatedTarget(eventImpl, null);
}
// TODO: invoke activation targets if HTML nodes will be implemented
// if (activationTarget !== null) {
// if (!eventImpl.defaultPrevented) {
// activationTarget._activationBehavior();
// }
// }
return !eventImpl.defaultPrevented;
}
/** Inner invoking of the event listeners where the resolved listeners are
* called.
*
* Ref: https://dom.spec.whatwg.org/#concept-event-listener-inner-invoke */
function innerInvokeEventListeners(
eventImpl: Event,
targetListeners: Record<string, Listener[]>,
): boolean {
let found = false;
const { type } = eventImpl;
if (!targetListeners || !targetListeners[type]) {
return found;
}
// Copy event listeners before iterating since the list can be modified during the iteration.
const handlers = targetListeners[type].slice();
for (let i = 0; i < handlers.length; i++) {
const listener = handlers[i];
let capture, once, passive;
if (typeof listener.options === "boolean") {
capture = listener.options;
once = false;
passive = false;
} else {
capture = listener.options.capture;
once = listener.options.once;
passive = listener.options.passive;
}
// Check if the event listener has been removed since the listeners has been cloned.
if (!targetListeners[type].includes(listener)) {
continue;
}
found = true;
if (
(eventImpl.eventPhase === Event.CAPTURING_PHASE && !capture) ||
(eventImpl.eventPhase === Event.BUBBLING_PHASE && capture)
) {
continue;
}
if (once) {
targetListeners[type].splice(targetListeners[type].indexOf(listener), 1);
}
if (passive) {
setInPassiveListener(eventImpl, true);
}
if (typeof listener.callback === "object") {
if (typeof listener.callback.handleEvent === "function") {
listener.callback.handleEvent(eventImpl);
}
} else {
listener.callback.call(eventImpl.currentTarget, eventImpl);
}
setInPassiveListener(eventImpl, false);
if (getStopImmediatePropagation(eventImpl)) {
return found;
}
}
return found;
}
/** Invokes the listeners on a given event path with the supplied event.
*
* Ref: https://dom.spec.whatwg.org/#concept-event-listener-invoke */
function invokeEventListeners(tuple: EventPath, eventImpl: Event): void {
const path = getPath(eventImpl);
const tupleIndex = path.indexOf(tuple);
for (let i = tupleIndex; i >= 0; i--) {
const t = path[i];
if (t.target) {
setTarget(eventImpl, t.target);
break;
}
}
setRelatedTarget(eventImpl, tuple.relatedTarget);
if (eventImpl.cancelBubble) {
return;
}
setCurrentTarget(eventImpl, tuple.item);
innerInvokeEventListeners(eventImpl, getListeners(tuple.item));
}
function normalizeAddEventHandlerOptions(
options: boolean | AddEventListenerOptions | undefined,
): AddEventListenerOptions {
if (typeof options === "boolean" || typeof options === "undefined") {
return {
capture: Boolean(options),
once: false,
passive: false,
};
} else {
return options;
}
}
function normalizeEventHandlerOptions(
options: boolean | EventListenerOptions | undefined,
): EventListenerOptions {
if (typeof options === "boolean" || typeof options === "undefined") {
return {
capture: Boolean(options),
};
} else {
return options;
}
}
/** Retarget the target following the spec logic.
*
* Ref: https://dom.spec.whatwg.org/#retarget */
function retarget(a: EventTarget | null, b: EventTarget): EventTarget | null {
while (true) {
if (!isNode(a)) {
return a;
}
const aRoot = a.getRootNode();
if (aRoot) {
if (
!isShadowRoot(aRoot) ||
(isNode(b) && isShadowInclusiveAncestor(aRoot, b))
) {
return a;
}
a = getHost(aRoot);
}
}
}
// Non-public state information for an event target that needs to held onto.
// Some of the information should be moved to other entities (like Node,
// ShowRoot, UIElement, etc.).
interface EventTargetData {
assignedSlot: boolean;
hasActivationBehavior: boolean;
host: EventTarget | null;
listeners: Record<string, Listener[]>;
mode: string;
}
interface Listener {
callback: EventListenerOrEventListenerObject;
options: AddEventListenerOptions;
}
// Accessors for non-public data
export const eventTargetData = new WeakMap<EventTarget, EventTargetData>();
function getAssignedSlot(target: EventTarget): boolean {
return Boolean(eventTargetData.get(target as EventTarget)?.assignedSlot);
}
function getHasActivationBehavior(target: EventTarget): boolean {
return Boolean(
eventTargetData.get(target as EventTarget)?.hasActivationBehavior,
);
}
function getHost(target: EventTarget): EventTarget | null {
return eventTargetData.get(target as EventTarget)?.host ?? null;
}
function getListeners(target: EventTarget): Record<string, Listener[]> {
return eventTargetData.get(target as EventTarget)?.listeners ?? {};
}
function getMode(target: EventTarget): string | null {
return eventTargetData.get(target as EventTarget)?.mode ?? null;
}
export function getDefaultTargetData(): Readonly<EventTargetData> {
return {
assignedSlot: false,
hasActivationBehavior: false,
host: null,
listeners: Object.create(null),
mode: "",
};
}
export class EventTargetImpl implements EventTarget {
constructor() {
eventTargetData.set(this, getDefaultTargetData());
}
public addEventListener(
type: string,
callback: EventListenerOrEventListenerObject | null,
options?: AddEventListenerOptions | boolean,
): void {
requiredArguments("EventTarget.addEventListener", arguments.length, 2);
if (callback === null) {
return;
}
options = normalizeAddEventHandlerOptions(options);
const { listeners } = eventTargetData.get(this ?? globalThis)!;
if (!(type in listeners)) {
listeners[type] = [];
}
for (const listener of listeners[type]) {
if (
((typeof listener.options === "boolean" &&
listener.options === options.capture) ||
(typeof listener.options === "object" &&
listener.options.capture === options.capture)) &&
listener.callback === callback
) {
return;
}
}
listeners[type].push({ callback, options });
}
public removeEventListener(
type: string,
callback: EventListenerOrEventListenerObject | null,
options?: EventListenerOptions | boolean,
): void {
requiredArguments("EventTarget.removeEventListener", arguments.length, 2);
const listeners = eventTargetData.get(this ?? globalThis)!.listeners;
if (callback !== null && type in listeners) {
listeners[type] = listeners[type].filter(
(listener) => listener.callback !== callback,
);
} else if (callback === null || !listeners[type]) {
return;
}
options = normalizeEventHandlerOptions(options);
for (let i = 0; i < listeners[type].length; ++i) {
const listener = listeners[type][i];
if (
((typeof listener.options === "boolean" &&
listener.options === options.capture) ||
(typeof listener.options === "object" &&
listener.options.capture === options.capture)) &&
listener.callback === callback
) {
listeners[type].splice(i, 1);
break;
}
}
}
public dispatchEvent(event: Event): boolean {
requiredArguments("EventTarget.dispatchEvent", arguments.length, 1);
const self = this ?? globalThis;
const listeners = eventTargetData.get(self)!.listeners;
if (!(event.type in listeners)) {
return true;
}
if (getDispatched(event)) {
throw new DOMException("Invalid event state.", "InvalidStateError");
}
if (event.eventPhase !== Event.NONE) {
throw new DOMException("Invalid event state.", "InvalidStateError");
}
return dispatch(self, event);
}
get [Symbol.toStringTag](): string {
return "EventTarget";
}
protected getParent(_event: Event): EventTarget | null {
return null;
}
}
defineEnumerableProps(EventTargetImpl, [
"addEventListener",
"removeEventListener",
"dispatchEvent",
]);

View file

@ -1,361 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { notImplemented } from "../util.ts";
import { isTypedArray } from "./util.ts";
import type * as domTypes from "./dom_types.d.ts";
import { TextEncoder } from "./text_encoding.ts";
import { DenoBlob, bytesSymbol as blobBytesSymbol } from "./blob.ts";
import { read } from "../ops/io.ts";
import { close } from "../ops/resources.ts";
import { fetch as opFetch } from "../ops/fetch.ts";
import type { FetchResponse } from "../ops/fetch.ts";
import * as Body from "./body.ts";
import { getHeaderValueParams } from "./util.ts";
import { ReadableStreamImpl } from "./streams/readable_stream.ts";
import { MultipartBuilder } from "./fetch/multipart.ts";
const NULL_BODY_STATUS = [101, 204, 205, 304];
const REDIRECT_STATUS = [301, 302, 303, 307, 308];
const responseData = new WeakMap();
export class Response extends Body.Body implements domTypes.Response {
readonly type: ResponseType;
readonly redirected: boolean;
readonly url: string;
readonly status: number;
readonly statusText: string;
headers: Headers;
constructor(body: BodyInit | null = null, init?: domTypes.ResponseInit) {
init = init ?? {};
if (typeof init !== "object") {
throw new TypeError(`'init' is not an object`);
}
const extraInit = responseData.get(init) || {};
let { type = "default", url = "" } = extraInit;
let status = init.status === undefined ? 200 : Number(init.status || 0);
let statusText = init.statusText ?? "";
let headers = init.headers instanceof Headers
? init.headers
: new Headers(init.headers);
if (init.status !== undefined && (status < 200 || status > 599)) {
throw new RangeError(
`The status provided (${init.status}) is outside the range [200, 599]`,
);
}
// null body status
if (body && NULL_BODY_STATUS.includes(status)) {
throw new TypeError("Response with null body status cannot have body");
}
if (!type) {
type = "default";
} else {
if (type == "error") {
// spec: https://fetch.spec.whatwg.org/#concept-network-error
status = 0;
statusText = "";
headers = new Headers();
body = null;
/* spec for other Response types:
https://fetch.spec.whatwg.org/#concept-filtered-response-basic
Please note that type "basic" is not the same thing as "default".*/
} else if (type == "basic") {
for (const h of headers) {
/* Forbidden Response-Header Names:
https://fetch.spec.whatwg.org/#forbidden-response-header-name */
if (["set-cookie", "set-cookie2"].includes(h[0].toLowerCase())) {
headers.delete(h[0]);
}
}
} else if (type == "cors") {
/* CORS-safelisted Response-Header Names:
https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name */
const allowedHeaders = [
"Cache-Control",
"Content-Language",
"Content-Length",
"Content-Type",
"Expires",
"Last-Modified",
"Pragma",
].map((c: string) => c.toLowerCase());
for (const h of headers) {
/* Technically this is still not standards compliant because we are
supposed to allow headers allowed in the
'Access-Control-Expose-Headers' header in the 'internal response'
However, this implementation of response doesn't seem to have an
easy way to access the internal response, so we ignore that
header.
TODO(serverhiccups): change how internal responses are handled
so we can do this properly. */
if (!allowedHeaders.includes(h[0].toLowerCase())) {
headers.delete(h[0]);
}
}
/* TODO(serverhiccups): Once I fix the 'internal response' thing,
these actually need to treat the internal response differently */
} else if (type == "opaque" || type == "opaqueredirect") {
url = "";
status = 0;
statusText = "";
headers = new Headers();
body = null;
}
}
const contentType = headers.get("content-type") || "";
const size = Number(headers.get("content-length")) || undefined;
super(body, { contentType, size });
this.url = url;
this.statusText = statusText;
this.status = extraInit.status || status;
this.headers = headers;
this.redirected = extraInit.redirected || false;
this.type = type;
}
get ok(): boolean {
return 200 <= this.status && this.status < 300;
}
public clone(): domTypes.Response {
if (this.bodyUsed) {
throw TypeError(Body.BodyUsedError);
}
const iterators = this.headers.entries();
const headersList: Array<[string, string]> = [];
for (const header of iterators) {
headersList.push(header);
}
let resBody = this._bodySource;
if (this._bodySource instanceof ReadableStreamImpl) {
const tees = this._bodySource.tee();
this._stream = this._bodySource = tees[0];
resBody = tees[1];
}
return new Response(resBody, {
status: this.status,
statusText: this.statusText,
headers: new Headers(headersList),
});
}
static redirect(url: URL | string, status: number): domTypes.Response {
if (![301, 302, 303, 307, 308].includes(status)) {
throw new RangeError(
"The redirection status must be one of 301, 302, 303, 307 and 308.",
);
}
return new Response(null, {
status,
statusText: "",
headers: [["Location", typeof url === "string" ? url : url.toString()]],
});
}
}
function sendFetchReq(
url: string,
method: string | null,
headers: Headers | null,
body: ArrayBufferView | undefined,
): Promise<FetchResponse> {
let headerArray: Array<[string, string]> = [];
if (headers) {
headerArray = Array.from(headers.entries());
}
const args = {
method,
url,
headers: headerArray,
};
return opFetch(args, body);
}
export async function fetch(
input: (domTypes.Request & { _bodySource?: unknown }) | URL | string,
init?: domTypes.RequestInit,
): Promise<Response> {
let url: string;
let method: string | null = null;
let headers: Headers | null = null;
let body: ArrayBufferView | undefined;
let redirected = false;
let remRedirectCount = 20; // TODO: use a better way to handle
if (typeof input === "string" || input instanceof URL) {
url = typeof input === "string" ? (input as string) : (input as URL).href;
if (init != null) {
method = init.method || null;
if (init.headers) {
headers = init.headers instanceof Headers
? init.headers
: new Headers(init.headers);
} else {
headers = null;
}
// ref: https://fetch.spec.whatwg.org/#body-mixin
// Body should have been a mixin
// but we are treating it as a separate class
if (init.body) {
if (!headers) {
headers = new Headers();
}
let contentType = "";
if (typeof init.body === "string") {
body = new TextEncoder().encode(init.body);
contentType = "text/plain;charset=UTF-8";
} else if (isTypedArray(init.body)) {
body = init.body;
} else if (init.body instanceof ArrayBuffer) {
body = new Uint8Array(init.body);
} else if (init.body instanceof URLSearchParams) {
body = new TextEncoder().encode(init.body.toString());
contentType = "application/x-www-form-urlencoded;charset=UTF-8";
} else if (init.body instanceof DenoBlob) {
body = init.body[blobBytesSymbol];
contentType = init.body.type;
} else if (init.body instanceof FormData) {
let boundary;
if (headers.has("content-type")) {
const params = getHeaderValueParams("content-type");
boundary = params.get("boundary")!;
}
const multipartBuilder = new MultipartBuilder(init.body, boundary);
body = multipartBuilder.getBody();
contentType = multipartBuilder.getContentType();
} else {
// TODO: ReadableStream
notImplemented();
}
if (contentType && !headers.has("content-type")) {
headers.set("content-type", contentType);
}
}
}
} else {
url = input.url;
method = input.method;
headers = input.headers;
if (input._bodySource) {
body = new DataView(await input.arrayBuffer());
}
}
let responseBody;
let responseInit: domTypes.ResponseInit = {};
while (remRedirectCount) {
const fetchResponse = await sendFetchReq(url, method, headers, body);
if (
NULL_BODY_STATUS.includes(fetchResponse.status) ||
REDIRECT_STATUS.includes(fetchResponse.status)
) {
// We won't use body of received response, so close it now
// otherwise it will be kept in resource table.
close(fetchResponse.bodyRid);
responseBody = null;
} else {
responseBody = new ReadableStreamImpl({
async pull(controller: ReadableStreamDefaultController): Promise<void> {
try {
const b = new Uint8Array(1024 * 32);
const result = await read(fetchResponse.bodyRid, b);
if (result === null) {
controller.close();
return close(fetchResponse.bodyRid);
}
controller.enqueue(b.subarray(0, result));
} catch (e) {
controller.error(e);
controller.close();
close(fetchResponse.bodyRid);
}
},
cancel(): void {
// When reader.cancel() is called
close(fetchResponse.bodyRid);
},
});
}
responseInit = {
status: 200,
statusText: fetchResponse.statusText,
headers: fetchResponse.headers,
};
responseData.set(responseInit, {
redirected,
rid: fetchResponse.bodyRid,
status: fetchResponse.status,
url,
});
const response = new Response(responseBody, responseInit);
if (REDIRECT_STATUS.includes(fetchResponse.status)) {
// We're in a redirect status
switch ((init && init.redirect) || "follow") {
case "error":
responseInit = {};
responseData.set(responseInit, {
type: "error",
redirected: false,
url: "",
});
return new Response(null, responseInit);
case "manual":
responseInit = {};
responseData.set(responseInit, {
type: "opaqueredirect",
redirected: false,
url: "",
});
return new Response(null, responseInit);
case "follow":
default:
let redirectUrl = response.headers.get("Location");
if (redirectUrl == null) {
return response; // Unspecified
}
if (
!redirectUrl.startsWith("http://") &&
!redirectUrl.startsWith("https://")
) {
redirectUrl = new URL(redirectUrl, url).href;
}
url = redirectUrl;
redirected = true;
remRedirectCount--;
}
} else {
return response;
}
}
responseData.set(responseInit, {
type: "error",
redirected: false,
url: "",
});
return new Response(null, responseInit);
}

Some files were not shown because too many files have changed in this diff Show more